Why not embed the typelib into the COM server and only ship it separately? - windows

I'm analyzing a rather old COM server project in order to reuse some stuff from it and noticed a strange thing - in order to expose itself to the registry it implements a separate function different from DllRegisterServer() and that function accepts the path to the typelib and loads the typelib from that path and the typelib is shipped separately and can be located anywhere.
The typical solution is to just use ATL CComModule::RegisterServer() which will happily load the typelib from the same DLL if it is embedded as a resource. The DLL already uses ATL and this should be the most direct way.
I tried to find why the typelib is not embedded as a resource but looks like it was a very old design decision and noone can explain it.
I can see a reason for shipping the typelib separately - this way it's easier for COM server developers to #import it. But why not both ship it as a separate file and embed as a resource into the COM server DLL? I could imagine that the typelib increases the DLL size by several hundred kilobytes but can't find any other serious reason.
What could be the reasons for shipping the typelib as a separate file only?

I finally found a serious reason for shipping a typelib separately only. If two versions - standalone and embedded - are shipped the installer could screw something up and those two typelibs could come out of sync and this would cause all kinds of weird problems for customers. Shipping exactly one version of typelib is safer in this aspect.

Related

How to create a manifest file for TLBs which are used for remote COM objects only?

My Delphi application Client.exe needs a couple of .tlb files to work. These files define server interfaces. The corresponding object instances are created with System.Win.ComObj.CreateRemoteComObject.
What is the problem?
For now the .tlb files are registered globally during the installation using regtlibv12.exe and are unregistered on uninstalling the software. This makes it impossible to install and uninstall multiple instances of the same software since it can break the TLB registrations.
Attempt to solve it with Registration Free COM
The idea is to use the .tlb files without registration but with a .manifest file.
I know how to use a customized Windows application manifest file with Delphi. But I don't know how to extract the information from the .tlb files and create the correct .manifest file.
I have found Mt.exe which can be used to generate .manifest files but it doesn't help me because
it's asking for a corresponding DLL file when the -tlb parameter is set but there are no .dll files shipped with the application since the COM objects are created on remote machines
it doesn't accept multiple .tlb files in the parameter list.
Other tools like Make My Manifest or Unattended Make My Manifest aren't available anymore or don't help me either.
What is the right way to create a manifest file in this case?
AFAIK RegFree COM does only support registration of local instances, via a dll. There is no way of using it with DCOM, which is something much more complex than local COM.
From my own experiment, DCOM could be a real PITA, especially in terms of registration. IMHO you should either use local COM objects, or switch to another much standard approach, like REST services. You may be able to re-use almost the same interfaces using e.g. an SOA approach over REST/JSON - see especially sicClientDriven mode to emulate DCOM objects.

Multiple DLL Resource Management

I have an existing MFC product and am planning on supporting a couple of other national languages thru the use of resource-only DLLs. I've read a number of articles and tutorials on how to go about this, but admit that I don't have a lot of in-depth knowledge of Windows resources (mostly just use VS 2008's graphical interface).
The major area that I am trying to understand is that it seems like all of the resource source files (i.e., resource.rc) for these DLLs -- and the main program -- should be sharing the same copy of resource.h. After all, all those IDD_xxx values have to be consistent, and it seems like making updates to the resources would be even more complicated by having to keep multiple resource.h files in sync!
So am I correct on this, and does anyone have any tips for how to best implement this? Should I modify resource.rc in the DLL projects to point to the "master" resource.h in the main program directory?
Yes, use the same resource.h file for sure.
One way is to just copy the resources you need to be translated into the the new resource project--stuff like menus, strings, dialogs. Bitmaps and icons probably don't need to be translated unless you put some text on them that is language specific. If you know your localse, at program startup you can call AfxSetResourceHandle() with the resource DLL you manually load.
Another way to approach the problem if you have a multitude of DLLs and EXEs is to use binary resource editing tools. What they do is create token files from your resources. Your translators edit the token file with the binary editing tool. When all is done, you run a tool to apply the translation to the binaries. Basically, you don't distribute resource DLLs, but distribute different versions of your DLLs for each language. The tools are smart enough so that if you make a change like add a string or dialog, it will get picked up and your translator can see that he needs to translate something new. The previously translated work will be saved in the token files. This is how we do it at my shop. We used to use Microsoft's Localization Resource toolkit. I don't know if we still use it or not since it is somebody else's responsibility now.
I found the MSDN article ID 198846 a good starting point for sharing of resources via a dll, though it does need updating for newer versions of visual studio, it was quite easy to follow and understand.
http://support.microsoft.com/kb/198846

Common runtime for different DLLs

I need to build a DLL capable to load other DLLs at runtime; these other DLLs have a rather intimate relationship with the main DLL (this is Python and extensions), so they must have a common runtime. The main DLL must be a single file that can be simply copied on the target machine. The auxiliary DLLs will be placed in a different directory.
So: "common runtime" means no static linking; "single file + simple copy" rules out the shared MS redistributables, especially when coupled with "different directories".
I only see the following options: link all DLLs against msvcrt.dll; embed current msvcrtXX into the main DLL and re-export all its symbols; use the msvcrtXX of the host application. To me the first looks the simplest, because it's a common need and there are many web pages explaining how to go about it. How would you approach this?
I suggest you re-architecture so that your plug-in DLL (the one the host application loads explicitly) contains nothing but proxy functions plus the file management logic. This DLL could use a static runtime, or no runtime at all.
Put the actual functionality (and in particular all code that needs to share a runtime with the Python extensions) in a separate ("primary") DLL and put this DLL, as well as the runtime of your choice, in the same directory as the Python extensions.
The primary DLL and the runtime could be zipped to the plug-in DLL, along with the core extensions. (I presume this is within the scope of the runtime's redistributable license, since it's basically the same as the way most installers work, but you should check for yourself.)
The calls to the plug-in will be slightly less efficient since they have to go through the proxy DLL, but the performance difference probably won't be measurable. :-)
Another option (in my humble opinion, much better) would be to dynamically link - aka. LoadLibrary/GetProcAddress) the dependencies when the main starts. This would allow you to support cases of missing DLLs and/or support your own internal version scheme.

"Declare" statement as yet an other way to circumvent the .dll hell?

To my astonishment I found VB6 code that uses Declare statements to define functions in a .dll that lives in the Program Folder without it being registered on Windows. This seems like a supersimple way to avoid the .dll hell without having to resort to using Side by side manifests. Can I read some more about this somewhere? Are there snags?
The Declare statement is used to do "just in time" binding to non-ActiveX DLLs. Until your program "touches" a Declared entrypoint no attempt is made to load the library.
It basically has nothing at all to do with the topic of DLL Hell.
Muddled thinking can even lead people to plop ActiveX DLLs "next to" the EXE which actually can result in DLL Hell because people who tend to do this also use poor techniques for installing and uninstalling applications.
Poorly designed application A deployment plops a commonly shared DLL or OCX next to the EXE.
Poorly designed application is run, the VB6 runtime can't find the classes in the registry, does a DLL Search using Windows heuristics, immediately locates the DLL next to the EXE and calls its self-registration entrypoint.
Innocent, properly designed applications B, C, D are later installed that use the same DLL/OCX and their installers find the library already registered.
Poorly designed application A is uninstalled, typically by simply deleteing its folder in Program Files.
Applications B, C, and D (and any future applications using the library) are now broken - due to orphaned component registration pointing to a non-existant library.
Moral of the story:
Never, never, never put DLLs "next to" your VB6 application on installation. If you have private DLLs that are not shared with other applications even then put them into a libs, etc. folder under the application folder. Possible exception might be non-COM DLLs, such as those you expect to use Declare with.
There is also a great deal of misunderstanding about manifests, of which there are multiple kinds. The ones you are probably thinking of are application and assembly manifests.
These can be used for selecting among different versions of a library installed Side by Side, or they can be used to isolate applications and assemblies which is the part that has bearing on DLL Hell.
Of course application manifests can be used to specify quite a few other things about how Windows should run the application.
Windows searches in a well-documented sequence of folders for LoadLibrary (which VB6 uses behind the scenes to resolve Declare declarations). Since the first location on the list of search folders is the app's own folder, your discovery makes perfect sense.
It doesn't resolve the "DLL hell" issue for the most part, though. It can't work for system DLLs, for instance, because Windows preloads most of them. Also, if a DLL is already loaded into memory, Windows may use that copy of the DLL (not sharing data, but code can be reused).
That's part of the reason that manifests were created; they allow an application to strictly define required versions of system DLLs in order to provide certain functionality. VB6's technique is old fashioned (just like VB6).

Recreating a COM DLL, do I need to worry about the GUID?

A change needs to be made in a DLL. The DLL was originally coded in VB6 (not by me), and the source code lost.
It is very simple in its functionality, so I recreated it from scratch, but I only have access to VB Express 2008.
I created it first as a normal DLL then realized it had to be a COM DLL. Fortunately, an excellent article at http://www.codeproject.com/KB/COM/nettocom.aspx tells me how.
But, I don't know anything about GUIDs...
Should I use the same GUID as the original DLL or not? Does it make any difference?
Edit: Does it really matter since it's a COM DLL? It is called into by an Active X control & I can see no reference in the web page to the GUI ... (but I'm just a n00b, so what do I know? ;-)
If you want this library to be a direct replacement of the original and it is fully binary compatible (all interfaces are unchanged) - then yes, you should use the same GUIDs for the class ids and interface ids. If you don't do that users of the original library will not be able to use yours without recompiling their programs.
Beware that binary compatibility is a must for reusing the GUIDs. If you break any interface - change its id and the id of the class implementing it and recompile the client.
The GUIDs acts as a kind of identifier for your COM object and DLL. If you use the same GUID you need to register your new DLL so that the location is updated (i.e. if you don't place it exactly in the same spot and have recreated all interfaces the old DLL previously had registered).
The cleaner approach is to generate a new GUID and modify the caller to use the new GUID/DLL instead.

Resources