//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1993. // // File: olescm.cxx // // Contents: Functions shared between OLE32 and the SCM // // Classes: // // Functions: // // History: 10-03-95 kevinro Created // //---------------------------------------------------------------------------- #include #include #include static const WCHAR wszOle32Dll[] = L"OLE32.DLL"; #define OLE32_DLL wszOle32Dll #define OLE32_BYTE_LEN sizeof(OLE32_DLL) #define OLE32_CHAR_LEN (sizeof(OLE32_DLL) / sizeof(WCHAR) - 1) // // Threading Model Registry Constants // const WCHAR wszDllThreadModel[] = L"ThreadingModel"; const WCHAR wszAptModel[] = L"Apartment"; const WCHAR wszBothModel[] = L"Both"; const WCHAR wszFreeModel[] = L"Free"; const WCHAR wszNeutralModel[] = L"Neutral"; // Thread model match table. The table's first index is the threading // model of the process and can be either APT_THREADED or // FREE_THREADED. The second index is any one of the types of threading // model's for DLLs. BOOL afThreadModelMatch[2][4] = {{TRUE, FALSE, TRUE, TRUE}, {FALSE, TRUE, FALSE, TRUE}}; //+--------------------------------------------------------------------------- // // Function: CompareDllName // // Synopsis: Give a DLL path, this sees if the path is equal to a given // DLL name or the last component of the is the same as the // DLL name. // // Arguments: [pwszPath] -- DLL path // [pwszDllName] -- name of DLL to compare with // // Returns: TRUE - The input path is equal or its last component is equal // to the input Dll name. // FALSE - Not equal at all. // // History: 6-15-95 ricksa Created // // Notes: This is a helper function used by the routines that convert // ole2.dll to ole32.dll and to convert paths that end in ole32.dll // into ole32.dll. // //---------------------------------------------------------------------------- BOOL wCompareDllName(LPCWSTR pwszPath, LPCWSTR pwszDllName, DWORD dwDllNameLen) { BOOL fResult = TRUE; if (lstrcmpiW(pwszDllName, pwszPath) != 0) { // Check if the last component is the same path DWORD dwPathLen = lstrlenW(pwszPath); if (dwPathLen > dwDllNameLen) { // Point to the last where the slash would be if the substitute // path is the last component LPCWSTR pwszLastComponent = pwszPath + dwPathLen - (dwDllNameLen + 1); // Is there a slash in that position if ((*pwszLastComponent == '\\') || (*pwszLastComponent == '/')) { // Point to where the last component should be pwszLastComponent++; // Does the last component match? if (lstrcmpiW(pwszLastComponent, pwszDllName) == 0) { goto CompareDllName_Exit; } } } fResult = FALSE; } CompareDllName_Exit: return fResult; } //+------------------------------------------------------------------------- // // Function: wThreadModelMatch // // Synopsis: Determines whether caller and DLL thread models match // // Arguments: [dwCallerThreadModel] - Caller thread model // [dwDllThreadModel] - DLL thread model // // Returns: TRUE - DLL can be loaded caller // FALSE - DLL cannot be loaded into caller. // // Algorithm: If the caller's thread model is apartment, then check // whether the DLL is one of apartment, single threaded or // both threaded. If it is, then return TRUE. Otherwise, // for free threading return TRUE if the DLL model is either // both or free threaded. If neither of the above is TRUE // then return FALSE. // // History: 10-Nov-94 Ricksa Created // //-------------------------------------------------------------------------- BOOL wThreadModelMatch( DWORD dwCallerThreadModel, DWORD dwDllThreadModel, DWORD dwContext) { BOOL fResult = afThreadModelMatch[dwCallerThreadModel] [dwDllThreadModel]; if (dwContext & CLSCTX_PS_DLL) { fResult = TRUE; } return fResult; } //+------------------------------------------------------------------------- // // Function: wQueryStripRegValue // // Synopsis: Get the DLL information for a 32 bit DLL and // strip off any leading and trailing " // // Arguments: [hkey] - class handle // [pwszSubKey] - key to open // [pwszValue] - where to return data // [pcbValue] - length of above buffer in bytes // // Returns: ERROR_SUCCESS - read DLL path information // Other - registry entries could not be found // // Algorithm: Read the value requested. // If first character is not ", exit // Otherwise, copy data after quote to beginning of buffer. // // // History: 05-Jan-94 BillMo Created // 26-Sep-95 BruceMa Support environment variable expansion // for shell viewers // //-------------------------------------------------------------------------- LONG wQueryStripRegValue(HKEY hKey, // handle of key to query LPCWSTR pwszSubKey, // address of name of subkey to query LPWSTR pwszValue, // address of buffer for returned string PLONG pcbValue) // address of buffer for size of returned string { HKEY hSubKey; DWORD dwType; LONG lErr ; Win4Assert(pwszValue != NULL); Win4Assert(pcbValue != NULL); // // Open the subkey if there is a string // if (pwszSubKey != NULL) { lErr = RegOpenKeyExW(hKey, pwszSubKey, NULL, KEY_READ, &hSubKey); } else { hSubKey = hKey; lErr = ERROR_SUCCESS; } // Read the value into the user's buffer if (lErr == ERROR_SUCCESS) { lErr = RegQueryValueExW(hSubKey, NULL , NULL, &dwType, (BYTE *) pwszValue, (ULONG *) pcbValue); if (lErr == ERROR_SUCCESS) { WCHAR *pwszScan = pwszValue; // used to scan along string WCHAR *pwszDest = pwszValue; // used as destination when copying // if the name is quoted then ... if (*pwszScan == '\"') { pwszScan++; // copy all non-quote characters down to base of buffer // until end of quoted string while (*pwszScan != '\0' && *pwszScan != '\"') { *pwszDest++ = *pwszScan++; } // terminate string and get length in bytes including nul *pwszDest++ = '\0'; *pcbValue = (int)(pwszDest - pwszValue) * sizeof(WCHAR); } // find first non-white space character pwszScan = pwszValue; while (_istspace(*pwszScan)) pwszScan++; // if there are no non-white space characters this will be true if (*pwszScan == L'\0') { lErr = ERROR_FILE_NOT_FOUND; *pcbValue = 0; } // Chicago does not support ExpandEnvironmentStrings #ifndef _CHICAGO_ // If the value type is REG_EXPAND_SZ then do environment variable // expansion if (dwType == REG_EXPAND_SZ) { // Expand any embedded environemnt variable expressions WCHAR wszTemp[MAX_PATH]; lstrcpyW(wszTemp, pwszValue); *pcbValue = ExpandEnvironmentStrings(wszTemp, pwszValue,MAX_PATH); } #endif // !_CHICAGO_ } // // Only close the sub key if we actually opened it. // if (hSubKey != hKey) { RegCloseKey(hSubKey); } } return lErr; } //+------------------------------------------------------------------------- // // Function: GetDllInfo // // Synopsis: Get the DLL information for a 32 bit DLL // // Arguments: [hClsRegEntry] - class handle // [pwszKey] - key to open // [pwszDllName] - where to return DLL path // [pclDllName] - length of above buffer // [pulDllThreadType] - where to return DLL threading information // // Returns: ERROR_SUCCESS - read DLL path information // Other - registry entries could not be found // // Algorithm: Open the DLL key. Then read the DLL path name. Finally read // the threading model information if it is specified. // // History: 09-Nov-94 Ricksa Created // //-------------------------------------------------------------------------- LONG wGetDllInfo( HKEY hClsRegEntry, LPCWSTR pwszKey, LPWSTR pwszDllName, LONG* pclDllName, ULONG* pulDllThreadType) { HKEY hDllEntry = NULL; // // Attempt to open the specified registry key. // LONG lerr = RegOpenKeyW(hClsRegEntry, pwszKey, &hDllEntry); if (ERROR_SUCCESS == lerr) { // // Try to read the DLL name. // lerr = wQueryStripRegValue(hDllEntry, NULL, pwszDllName, pclDllName); if (ERROR_SUCCESS == lerr) { // // A DLL name is registered. If the DLL is OLE32.DLL, then we // know all about and don't have to dig more info from the // the registry. Otherwise, we do need to keep digging. // if (wCompareDllName(pwszDllName, OLE32_DLL, OLE32_CHAR_LEN)) { memcpy(pwszDllName, OLE32_DLL, OLE32_BYTE_LEN); *pclDllName = OLE32_CHAR_LEN; *pulDllThreadType = BOTH_THREADED; } else { // // Assume there is no registry entry. // *pulDllThreadType = SINGLE_THREADED; // // Buffer to hold entry for the registry data. // WCHAR wszModelBuf[MAX_PATH]; DWORD cdwModelBuf = sizeof(wszModelBuf); DWORD dwRegEntType; // // Read the DLL threading model from the registry. // lerr = RegQueryValueExW(hDllEntry, wszDllThreadModel, NULL, &dwRegEntType, (LPBYTE) &wszModelBuf[0], &cdwModelBuf); // // If there is a thread model descriptor, set the thread // type accordingly. // if (ERROR_SUCCESS == lerr) { if (REG_SZ != dwRegEntType) { Win4Assert(L"ThreadingModel Key Type incorrect"); } else if (0 == lstrcmpiW(wszAptModel, wszModelBuf)) { // // An APARTMENT model object. // *pulDllThreadType = APT_THREADED; } else if (0 == lstrcmpiW(wszBothModel, wszModelBuf)) { // // A BOTH model object. // *pulDllThreadType = BOTH_THREADED; } else if (lstrcmpiW(wszFreeModel, wszModelBuf) == 0) { // // A FREE_THREADED model object. // *pulDllThreadType = FREE_THREADED; } else if (0 == lstrcmpiW(wszNeutralModel, wszModelBuf)) { // // A NEUTRAL_THREADED object. // *pulDllThreadType = NEUTRAL_THREADED; } else { Win4Assert(L"ThreadingModel Value incorrect"); } } // // When we get to this point, we got a DLL entry so we remap // any errors to success because they only mean that we could // not get a model from the registry. // lerr = ERROR_SUCCESS; } } RegCloseKey(hDllEntry); } return lerr; }