I did a lot of toying with MBNCSUtil tonight, and I've got some working bits online for you to play with:
http://www.jinxbot.net/mbncsutil/mbncsutil-2.0-beta1.zipWhat's new in this release:
MBNCSUtil.Data namespace - contains classes used for working with MPQ archives.
To use MPQs, use code such as:
MpqServiceProvider provider = MpqServices.Singleton.Provider;
MpqArchive archive = provider.OpenArchive("IX86Ver1.mpq");
if (archive.ContainsFile("IX86Ver1.dll"))
{
byte[] verDll = null;
using (MpqFileStream mfs = archive.OpenFile("IX86Ver1.dll"))
{
verDll = new byte[mfs.Length];
mfs.Read(verDll, 0, (int)mfs.Length];
}
if (verDll != null)
{
FileStream fs = new FileStream("IX86Ver1.dll", FileMode.OpenOrCreate, FileAccess.Write);
fs.Write(verDll, 0, verDll.Length);
fs.Flush();
fs.Close();
}
}
The above code sample extracts the IX86Ver1.dll file from IX86Ver1.mpq and writes it to the local path.
I haven't tried using this in Visual Basic 6 yet, but I did wrap it with COM interfaces, so that should also be visible.
I haven't made documentation yet because I'm still trying to figure out how to get the bits of Sandcastle from Microsoft (their internal documentation compiler for .NET 2.0) to work. However, full code is provided in the download, as is the XML documentation.
Also included, but incomplete, is the MBNCSUtil.BnFtp namespace. This namespace will provide two classes: BnFtpVersion1Request and BnFtpVersion2Request. Presently, because I hard-coded in the FILETIME of IX86Ver1.mpq, only BnFtpVersion1Request works and only with IX86Ver1.mpq. However, if you dink around with those constructors, you should probably be able to get them to work with no problem.
I am posting this to get comments and feedback from the community; if anyone uses MBNCSUtil and would like to try out the new features, please let me know what you think. Thanks!
I also want to answer the question about why I structured the classes like I did in the MPQ reading namespace.
I use an external library developed by a programmer called ShadowFlare called SFmpq.dll. I included this DLL as a resource stream in the project, and when the MPQ API is first loaded, the DLL is extracted into a temporary file. The temporary file is then LoadLibrary'd and I get the addresses of the APIs I used via GetProcAddress. I defined a series of delegates that match the signatures of these methods. Finally, I used Marshal.GetDelegateForFunctionPointer (a new API in .NET 2.0) to map the unmanaged function pointer to a managed delegate. When the application is shut down and the finalizers are being called, I clean up any of the MpqArchive objects I created (HMPQs), then FreeLibrary() the temporary file, then delete the temporary file.
Unfortunately, if there are any exceptions that cause the application to exit without calling the finalizers, the temporary file remains on disk.
Anyway, thanks again for using it and let me know if you have any comments or questions.