Creating an Instance
When CoCreateInstance() is called with standard arguments, COM will apply an order of preference to the available sources of the requested component, as follows:
|1.||Registered class factory|
|4.||Remote server (on another machine)|
Thus if one has run up a Dolphin development image in which a class factory for the component is registered (i.e. with COMInterfaceImp class>>registerClassFactory), then it will service all requests for components made by any client, including in-process component requests and those made by itself (hence the in-image mode).
Assuming that an instance of the server is not already running, then the next most favoured is the in-process implementation. Since COMInterfaceImp>>register creates both InProcServer32 and LocalServer32 keys, COM will always attempt to launch the Dolphin server in-process (using the IPDolphin.DLL stub) unless the client has specifically excluded the CLSCTX_INPROC_SERVER flag when calling CoCreateInstance(). Many client environments do not expose this level of detail in the language and thus one frequently has no control over the type of server requested. Consequently it can be difficult not to pick up the in-process implementation. Furthermore if one is attempting to use a Dolphin image to load a Dolphin client for debugging, then this will result in the Dolphin client crashing because of the limitation that the VM can only load a single image into each process (see above). For these reasons it is a good idea to omit or remove the InProcServer32 key when attempting to debug in out-of-process mode. This can be achieved by registering the COMInterfaceImp subclass for the local server context only:
register: (OLEConstants at: #CLSCTX_LOCAL_SERVER).
Having registered the COMRandomStream sample as a local server only, try evaluating the following:
COMRandomStream unregisterClassFactory. “Prevent client servicing own request ”
r := IRandomStream new.
You may get an error message similar to the following (the path to the image may be different):
If you do get this error then the client will also lock up until a certain timeout period has passed. Eventually it will pop up a walkback similar to the following:
This is the error (CO_E_APPDIDNTREG: 0x80080005 – “Server execution failed”) you can expect to see when the server COM launches but shuts down before registering any class factories, or fails to register a class factory for the CLSID requested by the client.
This will occur if the LocalServer32 registry entry is incorrect. The Image key cannot be used when debugging out-of-process, because at the time a local server is started it does not know which components it will be expected to service. Indeed a local server is expected to register class factories for all the components that it is able to service. Essentially COM launches the executable as a new process with the /Embedding command line argument. It then waits a while to give the server the chance to register its class factories, at which point it can proceed to invoke the relevant class factory (if any). The command line must, therefore, include the full and correct image path. The path must be quoted if it contains spaces.
The COMInterfaceImp class>>register[:] method should create a correctly formed key, but if it doesn’t you may need to edit it manually. Alternatively you can save an image where the launcher will find it (i.e. at the path specified in the error message box).
If/when the LocalServer32 registry entry is correct then the development system will start up in headless mode, and you should see the Dolphin splash screen. The client may still lock up and eventually pop up another walkback. The error may be the same as above, or the slightly more helpful CO_E_APPDIDNTREG: 0x800401FE – “Application was launched but it didn't register a class factory”.
If the server process is launching (the splash screen pops up), but the client still experiences the above error, this will probably be because the server image has been saved down without any class factory registration. If a class factory is not registered in the Dolphin image then when it starts it will not register a class factory object with COM. This error is quite easy to cause if one is attempting to use the same image as the test client and the server because in the client the class factory must not be registered.
We can fix this in this case by following sequence of steps:
|2.||Save image again|
Finally try creating an IRandomStream again, and this time it should work. If not you might get the following walkback because the type library is not correctly registered:
If this occurs, try registering the type library, either using the command specifically intended for this purpose (Register Type Library on the Additional Tools menu), or implicitly by browsing the library using the Active-X Component Wizard. Note that when you deploy an Active-X DLL on NT/2000//2003/XP you can arrange for the type-library to be bound into the DLL, in which case it does not need to be shipped separately, and furthermore it will be self-registered by the DLL.
Obviously one should avoid using the same actual image for the test client as the test server but we went through these steps to illustrate some of the most common errors one sees. To recap:
|•||If using a Dolphin development image as a test client, ensure it has not registered a class factory for the coclass (COMInterfaceImp class>>unregisterClassFactory).|
|•||Ensure that the development stubs are registered as the implementations for the CLSID in the registry (COMInterfaceImp class>>register:), but|
|•||Make sure there is no InProcServer32 key registered for the coclass’ CLSID, as otherwise COM will attempt to use that in preference. This will crash a Dolphin client, and launch the image in-process for other clients. The best way to achieve this is to #unregister and the #register: specifying only CLSCTX_LOCAL_SERVER.|
|•||Make sure the LocalServer32 registry entry for the class is specifying the correct image path.|
|•||Make sure the server development image does have a class factory registered (COMInterfaceImp class>>registerClassFactory)|
|•||Ensure that marshalling support is available.|
All being well the server should start, the instance creation request will be serviced, and an interface pointer returned to the client.