/*++ Copyright (C) 1996-2001 Microsoft Corporation Module Name: MAINDLL.CPP Abstract: Contains DLL entry points. Also has code that controls when the DLL can be unloaded by tracking the number of objects and locks. History: a-davj 15-Aug-96 Created. --*/ #include "precomp.h" #include bool bServer = false; // {C9B930CF-92D6-11d1-8AE6-00600806D9B6} CLSID for the pipes client marshaler DEFINE_GUID(CLSID_IWbemLocator_Pipes, 0xc9b930cf, 0x92d6, 0x11d1, 0x8a, 0xe6, 0x0, 0x60, 0x8, 0x6, 0xd9, 0xb6); // {15AB0B00-9529-11d1-9367-00AA00A4086C} DEFINE_GUID(CLSID_IWbemLocator_Tcpip, 0x15ab0b00, 0x9529, 0x11d1, 0x93, 0x67, 0x0, 0xaa, 0x0, 0xa4, 0x8, 0x6c); // {5C20EE1C-95EC-11d1-978E-0000F81E849C} DEFINE_GUID(CLSID_IWbemAddressResolver_Tcpip, 0x5c20ee1c, 0x95ec, 0x11d1, 0x97, 0x8e, 0x0, 0x0, 0xf8, 0x1e, 0x84, 0x9c); // {4FE4452B-92D8-11d1-8AE6-00600806D9B6} Display name for pipes client marshaler DEFINE_GUID(UUID_PipesName, 0x4fe4452b, 0x92d8, 0x11d1, 0x8a, 0xe6, 0x0, 0x60, 0x8, 0x6, 0xd9, 0xb6); // {15AB0B01-9529-11d1-9367-00AA00A4086C} DEFINE_GUID(UUID_TcpipName, 0x15ab0b01, 0x9529, 0x11d1, 0x93, 0x67, 0x0, 0xaa, 0x0, 0xa4, 0x8, 0x6c); #ifdef TCPIP_MARSHALER // {8F174CA0-952A-11d1-9367-00AA00A4086C} DEFINE_GUID(UUID_IWbemAddressResolver_Tcpip, 0x8f174ca0, 0x952a, 0x11d1, 0x93, 0x67, 0x0, 0xaa, 0x0, 0xa4, 0x8, 0x6c); // {A15E76E0-95EF-11d1-978E-0000F81E849C} DEFINE_GUID(UUID_IWbemAddressResolver_TcpipName, 0xa15e76e0, 0x95ef, 0x11d1, 0x97, 0x8e, 0x0, 0x0, 0xf8, 0x1e, 0x84, 0x9c); // {4BB2D69A-95F0-11d1-978E-0000F81E849C} DEFINE_GUID(UUID_Tcpip, 0x4bb2d69a, 0x95f0, 0x11d1, 0x97, 0x8e, 0x0, 0x0, 0xf8, 0x1e, 0x84, 0x9c); DEFINE_GUID(UUID_LocalAddrType, 0xa1044803, 0x8f7e, 0x11d1, 0x9e, 0x7c, 0x0, 0xc0, 0x4f, 0xc3, 0x24, 0xa8); #endif // Length of a {...} string representation of a GUID #define GUID_SIZE 39 // Registry key names and values static TCHAR *s_modTranPath = WBEM_REG_WBEM __TEXT("\\TRANSPORTS\\Network Transport Modules"); static TCHAR *s_AddResPath = WBEM_REG_WBEM __TEXT("\\TRANSPORTS\\Address Resolution Modules"); static TCHAR *s_localizations = WBEM_REG_WBEM __TEXT("\\TRANSPORTS\\Localizations\\409"); static TCHAR *s_pipesName = __TEXT("WBEM Anonymous Pipes Client Marshaler V1"); static TCHAR *s_localaddressType = __TEXT("{A1044803-8F7E-11D1-9E7C-00C04FC324A8}"); // Local #ifdef TCPIP_MARSHALER static TCHAR *s_tcpipName = __TEXT("WBEM Tcpip Client Marshaler V1"); static TCHAR *s_tcpipAddressName = __TEXT("WBEM Tcpip Address Resolution Module V1"); static TCHAR *s_tcpipaddressType = __TEXT("{8F174CA0-952A-11d1-9367-00AA00A4086C}"); // Local #endif static TCHAR *s_name = __TEXT("Name"); static TCHAR *s_independent = __TEXT("Independent"); static TCHAR *s_supportedAddressTypes = __TEXT("Supported Address Types"); static TCHAR *s_displayName = __TEXT("Display Name"); static TCHAR *s_stackOrder = __TEXT("Stack Order"); static LONG ObjectTypeTable[MAX_CLIENT_OBJECT_TYPES] = { 0 }; void ShowObjectCounts (); // Count number of objects and number of locks. long g_cObj = 0 ; ULONG g_cLock = 0 ; // used to keep track of allocated objects. MaintObj gMaintObj(TRUE); CThrdPool gThrdPool; HMODULE ghModule ; extern void DestroySharedMemory () ; //*************************************************************************** // // BOOL WINAPI DllMain // // DESCRIPTION: // // Entry point for DLL. Good place for initialization. // // PARAMETERS: // // hInstance instance handle // ulReason why we are being called // pvReserved reserved // // RETURN VALUE: // // TRUE if OK. // //*************************************************************************** BOOL WINAPI DllMain ( IN HINSTANCE hInstance, IN ULONG ulReason, LPVOID pvReserved ) { if ( DLL_PROCESS_DETACH == ulReason ) { DEBUGTRACE((LOG,"\nUnloading Pipes Marshaler Proxy")); DestroySharedMemory () ; DeleteCriticalSection ( & g_GlobalCriticalSection ) ; if ( g_Terminate ) { TerminateThread ( gMaintObj.GetThreadHandle () , 0 ) ; DEBUGTRACE((LOG,"\nShutdown All")); gMaintObj.UnLockedShutDownAllComlinks () ; DEBUGTRACE((LOG,"\nCompleted Shutdown All")); gThrdPool.Free () ; SetEvent ( g_Terminate ) ; int ii; for(ii = 0; ii < 50; ii++) { if(ObjectTypeTable[OBJECT_TYPE_COMLINK] > 0) Sleep(100); else break; } } DEBUGTRACE((LOG,"\nUnloaded Pipes Marshaler Proxy")); ShowObjectCounts(); return TRUE; } else { if ( DLL_PROCESS_ATTACH == ulReason ) { DEBUGTRACE((LOG,"\nLoading Pipes Marshaler Proxy")); ghModule = hInstance; InitializeCriticalSection ( & g_GlobalCriticalSection ) ; } else if ( DLL_PROCESS_ATTACH != ulReason ) { if ( g_Terminate == NULL ) { DEBUGTRACE((LOG,"\ncould not create a terminate event")); return FALSE; } return TRUE; } } return TRUE; } //*************************************************************************** // // STDAPI DllGetClassObject // // DESCRIPTION: // // Called when Ole wants a class factory. Return one only if it is the sort // of class this DLL supports. // // PARAMETERS: // // rclsid CLSID of the object that is desired. // riid ID of the desired interface. // ppv Set to the class factory. // // RETURN VALUE: // // S_OK all is well // E_FAILED not something we support // //*************************************************************************** STDAPI DllGetClassObject( IN REFCLSID rclsid, IN REFIID riid, OUT PPVOID ppv ) { DEBUGTRACE((LOG,"\nRequest to get ClassFactory")); HRESULT hr; CLocatorFactory *pObj = NULL; if (CLSID_IWbemLocator_Pipes == rclsid) { pObj=new CLocatorFactory(CLocatorFactory::PIPELOCATOR); } #ifdef TCPIP_MARSHALER else if (CLSID_IWbemLocator_Tcpip == rclsid) { pObj=new CLocatorFactory(CLocatorFactory::TCPIPLOCATOR); } else if (CLSID_IWbemAddressResolver_Tcpip == rclsid) { pObj=new CLocatorFactory(CLocatorFactory::TCPIPADDRESSRESOLVER); } #endif else { return E_FAIL ; } if (NULL==pObj) { return ResultFromScode(E_OUTOFMEMORY); } hr=pObj->QueryInterface(riid, ppv); if ( FAILED ( hr ) ) { delete pObj ; } return hr ; } //*************************************************************************** // // STDAPI DllCanUnloadNow // // DESCRIPTION: // // Answers if the DLL can be freed, that is, if there are no // references to anything this DLL provides. // // RETURN VALUE: // // S_OK if it is OK to unload // S_FALSE if still in use // //*************************************************************************** extern BOOL g_InitialisationComplete ; extern BOOL g_PipeInitialisationComplete ; #ifdef TCPIP_MARSHALER extern BOOL g_TcpipInitialisationComplete ; #endif STDAPI DllCanUnloadNow () { SCODE sc; //It is OK to unload if there are no objects or locks on the // class factory. sc=(0L==g_cObj && 0L==g_cLock) ? S_OK : S_FALSE; if ( sc == S_OK ) { gThrdPool.Free () ; SetEvent ( g_Terminate ) ; CloseHandle ( g_Terminate ) ; g_InitialisationComplete = FALSE ; g_PipeInitialisationComplete = FALSE ; #ifdef TCPIP_MARSHALER g_TcpipInitialisationComplete = FALSE ; #endif } return ResultFromScode(sc); } //*************************************************************************** // // ObjectCreated // // DESCRIPTION: // // Keeps track of object creation. // // PARAMETERS: // // dwType type of object created. // //*************************************************************************** void ObjectCreated ( DWORD dwType ) { if(dwType < MAX_CLIENT_OBJECT_TYPES) InterlockedIncrement(&ObjectTypeTable[dwType]); } //*************************************************************************** // // void ObjectDestroyed // // DESCRIPTION: // // Keeps track of object deletion. // // PARAMETERS: // // dwType type of object created. // //*************************************************************************** void ObjectDestroyed ( DWORD dwType ) { if(dwType < MAX_CLIENT_OBJECT_TYPES) InterlockedDecrement(&ObjectTypeTable[dwType]); } //*************************************************************************** // // void ShowObjectCounts // // DESCRIPTION: // // Dumps out the object count. Used during shutdown to detect leaks. // //*************************************************************************** void ShowObjectCounts () { DEBUGTRACE((LOG,"\n---COM Object Ref Count Info for marshalling client---\n")); DEBUGTRACE((LOG,"Active Objects = %d\n", g_cObj)); DEBUGTRACE((LOG,"Server locks = %d\n", g_cLock)); DEBUGTRACE((LOG,"Object counts by type:\n")); DEBUGTRACE((LOG,"IWbemLocator counts = %d\n", ObjectTypeTable[OBJECT_TYPE_LOCATOR])); DEBUGTRACE((LOG,"IWbemClassObject counts = %d\n", ObjectTypeTable[OBJECT_TYPE_CLSOBJ])); DEBUGTRACE((LOG,"IWbemServices counts = %d\n", ObjectTypeTable[OBJECT_TYPE_PROVIDER])); DEBUGTRACE((LOG,"IWbemQualifierSet counts = %d\n", ObjectTypeTable[OBJECT_TYPE_QUALIFIER])); DEBUGTRACE((LOG,"IEnumMosClassObject counts = %d\n", ObjectTypeTable[OBJECT_TYPE_OBJENUM])); DEBUGTRACE((LOG,"IClassFactory counts = %d\n", ObjectTypeTable[OBJECT_TYPE_FACTORY])); DEBUGTRACE((LOG,"OBJECT_TYPE_ENUMPROXY counts = %d\n", ObjectTypeTable[OBJECT_TYPE_ENUMPROXY])); DEBUGTRACE((LOG,"OBJECT_TYPE_LOGINPROXY counts = %d\n", ObjectTypeTable[OBJECT_TYPE_LOGINPROXY])); DEBUGTRACE((LOG,"OBJECT_TYPE_LOGIN counts = %d\n", ObjectTypeTable[OBJECT_TYPE_LOGIN])); DEBUGTRACE((LOG,"OBJECT_TYPE_OBJSINKPROXY counts = %d\n", ObjectTypeTable[OBJECT_TYPE_OBJSINKPROXY])); DEBUGTRACE((LOG,"OBJECT_TYPE_PROVPROXY counts = %d\n", ObjectTypeTable[OBJECT_TYPE_PROVPROXY])); DEBUGTRACE((LOG,"OBJECT_TYPE_COMLINK counts = %d\n", ObjectTypeTable[OBJECT_TYPE_COMLINK])); DEBUGTRACE((LOG,"OBJECT_TYPE_CSTUB counts = %d\n", ObjectTypeTable[OBJECT_TYPE_CSTUB])); DEBUGTRACE((LOG,"OBJECT_TYPE_RQUEUE counts = %d\n", ObjectTypeTable[OBJECT_TYPE_RQUEUE])); DEBUGTRACE((LOG,"OBJECT_TYPE_PACKET_HEADER counts = %d\n", ObjectTypeTable[OBJECT_TYPE_PACKET_HEADER])); DEBUGTRACE((LOG,"OBJECT_TYPE_SECHELP counts = %d\n", ObjectTypeTable[OBJECT_TYPE_SECHELP])); DEBUGTRACE((LOG,"OBJECT_TYPE_RESPROXY counts = %d\n", ObjectTypeTable[OBJECT_TYPE_RESPROXY])); DEBUGTRACE((LOG,"---End of ref count dump---\n")); } //*************************************************************************** // // AddGUIDToStackOrder // // Purpose: Inserts a GUID into the "Stack Order" multistring. // //*************************************************************************** void AddGUIDToStackOrder(LPTSTR szGUID, Registry & reg) { long lRes; DWORD dwSize; TCHAR * pData = NULL; pData = reg.GetMultiStr(s_stackOrder, dwSize); if(pData) { // The value already exists. Allocate enough data to store the data. TCHAR * pTest; for(pTest = pData; *pTest; pTest += lstrlen(pTest) + 1) if(!lstrcmpi(pTest, szGUID)) break; if(*pTest == NULL) { // our isnt in the list, add it to the end; careful with // the trailing double NULL. DWORD dwDataSize = pTest - pData + 1; TCHAR * pNew = new TCHAR[dwDataSize + GUID_SIZE]; memcpy (pNew, pData, dwDataSize - 1); // Omit last NULL lstrcpy(pNew + dwDataSize - 1, szGUID); pNew [dwDataSize + GUID_SIZE - 1] = NULL; // Double the final NULL lRes = reg.SetMultiStr(s_stackOrder, pNew, dwDataSize + GUID_SIZE); delete []pNew; } delete []pData; } else { // The value does not exist. Create it with just our entry in it TCHAR * pNew = new TCHAR[GUID_SIZE + 1]; lstrcpy(pNew, szGUID); pNew[GUID_SIZE] = 0; // put in the double null which is needed for REG_MULTI_SZ lRes = reg.SetMultiStr(s_stackOrder, pNew, GUID_SIZE + 1); delete []pNew; } } //*************************************************************************** // // CreateLPSTRFromGUID // // Purpose: Creates narrow string version of a guid // //*************************************************************************** void CreateLPSTRFromGUID(IN GUID guid, IN OUT TCHAR * pNarrow, IN DWORD dwSize) { WCHAR wcID[GUID_SIZE]; if(0 ==StringFromGUID2(guid, wcID, GUID_SIZE)) return; #ifdef UNICODE lstrcpy(pNarrow, wcID); #else wcstombs(pNarrow, wcID, dwSize * sizeof(TCHAR)); #endif } //*************************************************************************** // // AddDisplayName // // Purpose: Adds a "Display Name" string to the registry which will contain the // guid of the internationalization string. It then adds the string to the // english part of the internationization table. // //*************************************************************************** void AddDisplayName(Registry & reg, GUID guid, LPTSTR pDescription) { TCHAR cGuid[GUID_SIZE]; CreateLPSTRFromGUID(guid, cGuid, GUID_SIZE); reg.SetStr(s_displayName, cGuid); Registry reglang(s_localizations); reglang.SetStr(cGuid, pDescription); } //*************************************************************************** // // AddSupportedAddressTypes // // Purpose: Inserts a GUID into the "Supported Address Types" multistring. // //*************************************************************************** void AddSupportedLocalAddressTypes(Registry & reg) { long lRes; TCHAR * pNew = new TCHAR[GUID_SIZE + 1]; lstrcpy(pNew, s_localaddressType); pNew[GUID_SIZE] = 0; // put in the double null which is needed for REG_MULTI_SZ lRes = reg.SetMultiStr(s_supportedAddressTypes, pNew, GUID_SIZE + 1); delete []pNew; } #ifdef TCPIP_MARSHALER void AddSupportedTcpipAddressTypes(Registry & reg) { long lRes; char * pNew = new char[2*GUID_SIZE + 1]; lstrcpy(pNew, s_localaddressType); lstrcpy(pNew+GUID_SIZE, s_tcpipaddressType); pNew[2*GUID_SIZE] = 0; // put in the double null which is needed for REG_MULTI_SZ lRes = reg.SetMultiStr(s_supportedAddressTypes, pNew, 2*GUID_SIZE + 1); delete []pNew; } #endif #ifdef TCPIP_MARSHALER //*************************************************************************** // // CreateAddResModEntries // // Purpose: Creates the registry entries for the Address Resolution Modules // //*************************************************************************** void CreateAddResModEntries() { // create a narrow string version of the local name resolver CLSID TCHAR szLocalAddRes[GUID_SIZE]; CreateLPSTRFromGUID(CLSID_IWbemAddressResolver_Tcpip, szLocalAddRes, GUID_SIZE); // The StackOrder value is a multistring list of the CLSIDs of the network // transports. Create it with a single entry if it doesnt already exist, or // just put DCOM at the from of the list if it doesnt exist. Registry reg(s_AddResPath); AddGUIDToStackOrder(szLocalAddRes, reg); // Now add an entry for local address resolution module // It will contain // "Name" REG_SZ, documentary name // "Display Name" REG_SZ, GUID of display name in localization key // "Supporte Address Type" REG_MULTI_SZ: reg.MoveToSubkey(szLocalAddRes); reg.SetStr("Name", s_tcpipAddressName); TCHAR cSupportedTypes[2*GUID_SIZE+1]; memset(cSupportedTypes, 0, (2*GUID_SIZE+1)*sizeof(TCHAR)); CreateLPSTRFromGUID(UUID_IWbemAddressResolver_Tcpip, cSupportedTypes, GUID_SIZE); CreateLPSTRFromGUID(UUID_LocalAddrType, cSupportedTypes+GUID_SIZE, GUID_SIZE); reg.SetMultiStr("Supported Address Types", cSupportedTypes, 2*GUID_SIZE+1); AddDisplayName(reg, UUID_IWbemAddressResolver_TcpipName, s_tcpipAddressName); } //*************************************************************************** // // CreateAddrTypesList // // Purpose: Creates the address types list // //*************************************************************************** void CreateAddrTypesList() { // create a narrow string LocalMachine addr CLSID TCHAR szLocalType[GUID_SIZE]; CreateLPSTRFromGUID(UUID_IWbemAddressResolver_Tcpip, szLocalType, GUID_SIZE); Registry reg(WBEM_REG_WBEM __TEXT("\\TRANSPORTS\\AddressTypes\\")); reg.MoveToSubkey(szLocalType); // Now add an entry for local address type // It will contain // "Description" REG_SZ, documentary name // "Display Name" REG_SZ, GUID of display name in localization key reg.SetStr(__TEXT("Description"), __TEXT("TcpIp")); AddDisplayName(reg, UUID_Tcpip, __TEXT("TcpIp")); } #endif //*************************************************************************** // // RegisterClientMarshaler // // Purpose: Creates the registry entries for the client marshaler // //*************************************************************************** void RegisterClientMarshaler() { // create a narrow string version of the Pipes transport CLSID TCHAR szPipesGUID[GUID_SIZE]; CreateLPSTRFromGUID(CLSID_IWbemLocator_Pipes, szPipesGUID, GUID_SIZE); // The StackOrder value is a multistring list of the CLSIDs of the network // transports. Create it with a single entry if it doesnt already exist, or // just put PIPES at the end of the list if it doesnt exist. Registry pipereg(s_modTranPath); AddGUIDToStackOrder(szPipesGUID, pipereg); // Now add an entry for pipes. Identify it as a dependent client marshaler pipereg.MoveToSubkey(szPipesGUID); pipereg.SetStr(s_name, s_pipesName); pipereg.SetDWORD(s_independent, 0); AddSupportedLocalAddressTypes (pipereg); AddDisplayName(pipereg, UUID_PipesName, s_pipesName); #ifdef TCPIP_MARSHALER TCHAR szTcpipGUID[GUID_SIZE]; CreateLPSTRFromGUID(CLSID_IWbemLocator_Tcpip, szTcpipGUID, GUID_SIZE); Registry tcpipreg(s_modTranPath); AddGUIDToStackOrder(szTcpipGUID, tcpipreg); // Now add an entry for tcpip. Identify it as a dependent client marshaler tcpipreg.MoveToSubkey(szTcpipGUID); tcpipreg.SetStr(s_name, s_tcpipName); tcpipreg.SetDWORD(s_independent, 0); AddSupportedTcpipAddressTypes (tcpipreg); AddDisplayName(tcpipreg, UUID_TcpipName, s_tcpipName); #endif } //*************************************************************************** // // DllRegisterServer // // Purpose: Called during setup or by regsvr32. // // Return: NOERROR if registration successful, error otherwise. //*************************************************************************** #define LocatorPipePROGID __TEXT("WBEMPipesLocator") #ifdef TCPIP_MARSHALER #define LocatorTcpipPROGID __TEXT("WBEMTcpipLocator") #define AddressTcpipPROGID __TEXT("WBEMTcpipAddressResolver") #endif STDAPI DllRegisterServer(void) { RegisterDLL(ghModule, CLSID_IWbemLocator_Pipes, __TEXT("WBEM Pipes Locator"), __TEXT("Both"), LocatorPipePROGID); #ifdef TCPIP_MARSHALER RegisterDLL(ghModule, CLSID_IWbemLocator_Tcpip, "WBEM Tcpip Locator", "Both", LocatorTcpipPROGID); RegisterDLL(ghModule, CLSID_IWbemAddressResolver_Tcpip, __TEXT("WBEM Tcpip Address Resolver"), __TEXT("Both"), AddressTcpipPROGID); CreateAddResModEntries () ; CreateAddrTypesList () ; #endif // Register the client marshaler RegisterClientMarshaler (); return NOERROR; } //*************************************************************************** // // DllUnregisterServer // // Purpose: Called when it is time to remove the registry entries. // // Return: NOERROR if registration successful, error otherwise. //*************************************************************************** STDAPI DllUnregisterServer(void) { UnRegisterDLL(CLSID_IWbemLocator_Pipes,LocatorPipePROGID); #ifdef TCPIP_MARSHALER UnRegisterDLL(CLSID_IWbemLocator_Tcpip,LocatorTcpipPROGID); UnRegisterDLL(CLSID_IWbemAddressResolver_Tcpip,AddressTcpipPROGID); #endif return NOERROR; }