Ages ago, I happened onto Bruce McKinney’s HardCore VB and the Win.TLB file that he created and I was hooked.
Ever since, I’ve been a big fan of using typelibs with VB6. They’re relatively compact, support help, work nicely with Intellisense, and, most importantly, any elements of a typelib that your project doesn’t use, don’t get compiled into you project, unlike standard VB DECLARE statements.
Furthermore, typelibs provide just about the ONLY way to access certain COM interfaces that are normally declared with attributes that make them unusable by VB.
For examples of that, check out Edanmo’s page, or the VBAccelerator stuff.
I’ve been using Matt Curland’s Excellent PowerVB Typelib editor to edit, extend, and generally hack and bash the original win.tlb (I generally don’t use unicode much explicitly, so I haven’t kept the WINU.TLB unicode variant up to date, unfortunately). Note, though that you have to buy the book to get the editor. If you do this much, the editor alone is worth it, but the book is truly the best books on low level VB6 out there.
Doing things the Right Way
However, I really wanted to get this thing back into shape, and I felt like the best way to do that was to get it BACK into IDL format, and then use the MIDL compiler on it.
You’d think that doing so would be, basically:
- Load the TLB into OLEVIEW
- Export the whole thing as an IDL file.
- Edit the IDL with a text editor
- Run MIDL on it to recompile the WIN.TLB and presto! Nice new, clean tlb file.
Sigh. Is anything ever that simple?
Problems, Problems
First, OLEVIEW exports things in completely the wrong order (I’m not exactly sure what it uses to order things other than just the defined order in the TLB). As a result, I got tons of “symbol not defined” errors when I compiled, because a call referenced a structure that was defined later in the IDL, and didn’t have forward declaration.
Shuffling LOTS of typedefs around, I resolved all that, only to end up with tons of MIDL2022 “illegal or missing value for entry attribute”, as well as MIDL2270 “duplicate UUID” errors.
The duplicate UUID errors I fully understand, even though I really don’t like it. Basically, the TLB “redefines” a number of internal COM interfaces to make them usable by VB, for instance IEnumString.
However, MIDL doesn’t allow you to redefine an interface that already exists, and that particular interface does already exist.
In that case, commonly, you just rename your new definition to, say, IVBEnumString.
And with mktyplib and Matt’s TLB editor, that’s no problem. But MIDL see’s the old IEnumString (defined in the automatically INCLUDEd OBJIDL.IDL) and the new IVBEnumString, notices that they have the same UUID (which they must) and throws that MIDL2270 Duplicate UUID error.
Bruce resolved this by actually copying the OAIDL.IDL, OBJIDL.IDL, UNKNWN.IDL and WTYPES.IDL from the Visual Studio 6 Include dir right into his TLB project, and modified them as necessary. It works because of the MIDL search rules, but I REALLY didn’t want to continue mucking with the MS IDL files. I’d much rather just redefine those that I need to redefine and be done with it. Just seems like a safer alternative.
Ok, fine, so I go back to mktyplib and move on.
Not so fast, young Skywalker!
mktyplib is an older tool (read, unsupported, not maintained, and generally considered just that much bit junk now). And sure enough, a very common element in my type lib, it doesn’t support, namely non-variant optional parameters.
I have a line of ODL (mktyplib’s prefered input file type) like:
HRESULT _stdcall Commit([in, optional, defaultvalue(0)] STGC grfCommitFlags);
And it has no idea how to handle that OPTIONAL and I have too many of these to bother counting them all (ok, not really, there’s 64).
I really don’t want to have to make all those method parms suddenly “required” when they’re not.
The Cycle of Irritation
So, here I am, hours later, and back where I started.
I’m going to continue using the PowerVB editor to update the WIN.TLB file.
And just to recap, my version started from Bruce McKinney’s ANSI version, generally targeted at VB5, then pulls in LOTS of additional COM interfaces, ala Edanmo, VBAccelerator, and others, corrects some issues with certain calls that VB5 had no issues with but VB6 didn’t like, throws in lots of new ENUMS for parameters of functions instead of just blind LONGs where you get no Intellisense, and rounds things out with a little bit more help text for some methods (though that’s still pretty spotty).
One nasty habit of TypeLibs
One thing to be very careful of if you do start working with typelibs, is to make sure that any API function you decide to pull in and actually use will exist on the target machine.
These days, that’s not particularly hard. Win2k through Vista have changed very little as far as typical low level API’s are concerned.
At one point, my apps were running on everything from Win95 through XP, and there were definitely issues with commonly used functions existing under Win2k or XP that had no equivalent under 95 or 98. In those few cases, I just resorted to a standard VB declare and then error trapped the call. If the function wasn’t available, you’d get an error, trap it and deal with it.
However, if that same function was defined in a typelib, the app loaded will validate all implicitly linked libs and try to resolve them all at load time. If it failed for ANY function, the app won’t load at all, and all this happens before any of you VB code has a chance to do anything about it.