Next: LocalServer container implementation, Previous: The COM object implementation, Up: Creating COM objects with GNAT [Contents][Index]
Step 1 - The export file
Every InProc container (DLL housing a COM object), needs to export four functions in its export (.def) file.
The def file must start exactly like this, but may contain additional exports following these four:
EXPORTS DllGetClassObject=DllGetClassObject@12 @2 DllCanUnloadNow=DllCanUnloadNow@0 @3 DllRegisterServer=DllRegisterServer@0 @4 DllUnregisterServer=DllUnregisterServer@0 @5 |
Step 2 - The dll implementation
In addition to the four exports mentioned every DLL must contain an
exported DllMain procedure. The implementation for the
DllMain will be the same for all objects, unless additional
functionality is needed on the containers startup or shutdown:
function DllMain (hinstDLL : Win32.Windef.HINSTANCE;
fdwReason : Win32.DWORD;
lpvReserved : Win32.LPVOID)
return Win32.BOOL
is
procedure Adainit;
pragma Import (C, Adainit);
procedure Adafinal;
pragma Import (C, Adafinal);
DLL_PROCESS_DETACH : constant := 0;
DLL_PROCESS_ATTACH : constant := 1;
begin
case fdwReason is
when DLL_PROCESS_ATTACH =>
AdaInit;
hInstance := hinstDll;
return 1;
when DLL_PROCESS_DETACH =>
AdaFinal;
return 1;
when others =>
return 1;
end case;
end DllMain;
|
The Instance handle assigned to the Dll is save in a variable hInstance
for use by the exported COM Dll functions.
The DllGetClassObject is used by COM to request from the Dll a pointer
to the factory object for a particular type of COM object. The
implementation needs to check that it does in fact support creation of
those objects and then needs to return a pointer to the class factory
that will produces objects of the requested type. See the implementation
in the gnatexample-dll.adb file for an example.
The DllCanUnloadNow function is called periodically by the operating
system to determine if the Dll can be unloaded or needs to remain in
memory. The Dll needs to remain in memory and returns S_FALSE if there
are any server locks or if there are any created objects still being
used. For example:
function DllCanUnloadNow return HRESULT is
use type Interfaces.C.Long;
begin
if Server_Lock_Count = 0 and then Component_Count = 0 then
return Win32.Winerror.S_OK;
else
return Win32.Winerror.S_FALSE;
end if;
end DllCanUnloadNow;
|
The functions DllRegisterServer and DllUnregisterServer
are called by the application regsvr32.exe (or an install
program) to request that the Dll add or remove all the relevant COM
entries of the registry for its supported objects and type libraries.
The first step in DllRegisterServer is to register the type
libraries. This is done by first obtaining the full path file name of
the Dll. Using this path, the Win32 APIs LoadTypeLib and
RegisterTypeLib are used to load and register the type
library. Then the following entries are registered to the NT registry
under HKEY_CLASSES_ROOT (using a simple helper procedure in the
example file):
Register ("CLSID\" & CLSID, "", Library_Description);
-- CLSID = CLASS ID of the COM Object (CoClass GUID)
-- Library_Description = Description of object to appear in COM
-- browsers
Register ("CLSID\" & CLSID, "AppID", CLSID);
-- This entry links together the COM information (under \CLSID)
-- with the remoting information for DCOM (under \APPID)
Register ("CLSID\" & CLSID & "\InProcServer32",
"",
C.To_Ada (DllPath));
-- Path to InProcServer 32 bit implementation of the COM object
-- (a DLL)
Register ("CLSID\" & CLSID & "\InProcServer32",
"ThreadingModel",
"Apartment");
-- Tells the operating system that this object is aware of
-- threading issues, but the OS should synchronize access to
-- the object.
-- This does not affect the type of clients that can use this
-- object,ie. a client usingCoInitializeEx(CLSCTX_MULTI_THREADED)
-- can create this object and the OS will handle synchronization
-- of calls made by each thread trying to access the object.
Register ("CLSID\" & CLSID & "\ProgID",
"",
Object_Name & "." & Library_Version);
-- Links the CLSID to the PROGID
-- The ProgID is the human readable name of the COM object used
-- by VB and other languages instead of the GUID.
-- The PROGID also contains a dot followed by the version number.
Register ("CLSID\" & CLSID & "\VersionIndependentProgID",
"",
Object_Name);
-- Links the CLSID to the PROGID with out the version number
Register (Object_Name, "", Library_Description);
-- Creates the version independant PROGID entry
Register (Object_Name & "\CLSID", "", CLSID);
-- Links the PROGID to the CLSID of the object
Register (Object_Name & "\CurVer",
"",
Object_Name & "." & Library_Version);
-- Links the version independant PROGID to the version
-- dependant PROGID
Register (Object_Name & "." & Library_Version,
"",
Object_Name);
-- Creates the PROGID entry
Register (Object_Name & "." & Library_Version & "\CLSID",
"",
CLSID);
-- Links the PROGID to the CLSID
Register ("AppID\" & CLSID, "", Library_Description);
-- Creates the AppID entry where remoting infromation about the
-- COM object is stored.
Register ("AppID\" & CLSID, "DllSurrogate", "");
-- Tells the opearting system that if a request is made to run
-- the COM object as a DCOM object or as a separate process
-- (LocalServer) to provide this for the dll using a built in NT
-- application DLLHOST.EXE
|
The DllUnregisterServer function first removes the registered type
library using the Win32 API function UnregisterTypeLib, it then
removes all the entries in the NT registery created by
DllRegisterServer.
Next: LocalServer container implementation, Previous: The COM object implementation, Up: Creating COM objects with GNAT [Contents][Index]