Every UMDF driver must support DllMain as the driver’s primary entry point and must export the DllGetClassObject function so that COM can instantiate the driver object. The Skeleton sample defines these functions in the Dllsup.cpp file.
1. Driver Entry Point: DllMain
DllMain is the
driver’s primary entry point. This function typically initializes any
data that is required for tracing and debugging but otherwise does
little because most driver-and-device-specific initialization takes
place in conjunction with the driver and device object creation. In the
Skeleton driver, DllMain simply initializes tracing, as the following source code shows:
BOOL
WINAPI
DllMain{
HINSTANCE ModuleHandle,
DWORD Reason,
PVOID /* Reserved */
}
/*++
Routine Description:
This is the entry point and exit point for the I/O
driver. It does very little because the driver has mini-
mal global data.
This method initializes tracing.
Arguments:
ModuleHandle - the Dll handle for this module.
Reason - the reason this entry point was called.
Reserved - unused
Return Value:
TRUE
--*/
{
If (DLL_PROCESS_ATTACH == Reason)
{
//
// Initialize tracing.
//
WPP_INIT_TRACING(MYDRIVER_TRACING_ID);
}
else if (DLL_PROCESS_DETACH == Reason)
{
//
// Clean up tracing.
//
WPP_CLEANUP();
}
return TRUE;
}
When the driver host process calls DllMain,
it passes a reason for the call, along with a handle and a reserved
value, both of which the function can ignore. If the driver host process
is starting and the DLL is being loaded, the reason is DLL_PROCESS_ATTACH.
In this case, the function initializes tracing. If the driver host
process is terminating or the library did not load successfully, the
reason is DLL_PROCESS_DETACH, so the function ends tracing. Starting and ending tracing in DllMain ensures that trace information is recorded for the entire life of the driver.
2. Get Class Object: DllGetClassObject
COM calls the driver’s DllGetClassObject
function to get a pointer to an interface through which it can
instantiate a driver callback object. This method should create an
instance of the class factory for the driver object; UMDF later calls
methods on the class factory to actually instantiate the driver callback
object.
The following is the source code for the Skeleton driver’s DllGetClassObject function:
HRESULT
STDAPICALLTYPE
DllGetClassObject{
__in REFCLSID ClassId,
__in REFIID InterfaceId,
__deref_out LPVOID *Interface
}
/*++
Routine Description:
This routine is called by COM to instantiate the skeleton
driver callback object and do an initial query interface
on it.
This method only creates an instance of the driver's
class factory, which is the minimum required to support
UMDF.
Arguments:
ClassId - the CLSID of the object being "gotten"
InterfaceId - the interface the caller wants from that
object
Interface - a location to store the referenced interface
pointer
Return Value:
S_OK if the function succeeds, or
Error code indicating the reason for failure
--*/
{
PCClassFactory factory;
HRESULT hr = S_OK;
*interface = NULL;
//
// If the CLSID doesn't match that of our "coclass"
// defined in the IDL file) then we can't create the
// object that the caller wants. This error may indicate
// that the COM registration is incorrect, and another
// CLSID is referencing this driver.
//
If (IsEqualCLSID(ClassId, CLSID_MyDriverCoClass == false)
{
Trace{
TRACE_LEVEL_ERROR,
L"ERROR: Called to create instance of unrecognized
class
"(%!GUID!)",
};
Return CLASS_E_CLASSNOTAVAILABLE;
}
//
// Create an instance of the class factory for the caller
//
factory = new CClassFactory();
if (NULL == factory)
{
Hr = E_OUTOFMEMORY;
}
//
// Query the object we created for the interface that the
// caller requested. Then release the object. If the QI
// succeeded and referenced the object, its reference
// count will now be 1. If the QI failed, the reference
// count is 0 and the object is automatically deleted.
//
If (S_OK == hr)
{
hr = factory->QueryInterface(InterfaceId, Interface);
factory->Release();
}
return hr;
}
In the Skeleton driver, DllGetClassObject
verifies that the class ID passed in by the caller (COM) matches the
class ID of the object, as defined in the IDL file. It creates an
instance of the class factory, calls QueryInterface on the class factory to get a pointer to the IClassFactory interface and increment its reference count, and then returns.