368 lines
11 KiB
C++
368 lines
11 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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 <windows.h>
|
||
|
#include <ole2sp.h>
|
||
|
#include <ole2com.h>
|
||
|
|
||
|
static const TCHAR tszOle32Dll[] = TEXT("OLE32.DLL");
|
||
|
|
||
|
#define OLE32_DLL tszOle32Dll
|
||
|
#define OLE32_BYTE_LEN sizeof(OLE32_DLL)
|
||
|
#define OLE32_CHAR_LEN (sizeof(OLE32_DLL) / sizeof(TCHAR) - 1)
|
||
|
|
||
|
//
|
||
|
// Threading Model Registry Constants
|
||
|
//
|
||
|
|
||
|
const TCHAR tszDllThreadModel[] = TEXT("ThreadingModel");
|
||
|
|
||
|
const TCHAR tszAptModel[] = TEXT("Apartment");
|
||
|
const TCHAR tszBothModel[] = TEXT("Both");
|
||
|
const TCHAR wszFreeModel[] = TEXT("Free");
|
||
|
|
||
|
// 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(LPCTSTR ptszPath, LPCTSTR ptszDllName, DWORD dwDllNameLen)
|
||
|
{
|
||
|
BOOL fResult = TRUE;
|
||
|
|
||
|
if (lstrcmpi(ptszDllName, ptszPath) != 0)
|
||
|
{
|
||
|
// Check if the last component is the same path
|
||
|
DWORD dwPathLen = lstrlen(ptszPath);
|
||
|
|
||
|
if (dwPathLen > dwDllNameLen)
|
||
|
{
|
||
|
// Point to the last where the slash would be if the substitute
|
||
|
// path is the last component
|
||
|
LPCTSTR ptszLastComponent = ptszPath + dwPathLen - (dwDllNameLen + 1);
|
||
|
|
||
|
// Is there a slash in that position
|
||
|
if ((*ptszLastComponent == '\\') || (*ptszLastComponent == '/'))
|
||
|
{
|
||
|
// Point to where the last component should be
|
||
|
ptszLastComponent++;
|
||
|
|
||
|
// Does the last component match?
|
||
|
if (lstrcmpi(ptszLastComponent, ptszDllName) == 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
|
||
|
LPCTSTR ptszSubKey, // address of name of subkey to query
|
||
|
LPTSTR ptszValue, // address of buffer for returned string
|
||
|
PLONG pcbValue) // address of buffer for size of returned string
|
||
|
{
|
||
|
HKEY hSubKey;
|
||
|
DWORD dwType;
|
||
|
LONG lErr ;
|
||
|
|
||
|
Win4Assert(ptszValue != NULL);
|
||
|
Win4Assert(pcbValue != NULL);
|
||
|
|
||
|
//
|
||
|
// Open the subkey if there is a string
|
||
|
//
|
||
|
if (ptszSubKey != NULL)
|
||
|
{
|
||
|
lErr = RegOpenKeyExT(hKey, ptszSubKey, NULL, KEY_READ, &hSubKey);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hSubKey = hKey;
|
||
|
lErr = ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
// Read the value into the user's buffer
|
||
|
if (lErr == ERROR_SUCCESS)
|
||
|
{
|
||
|
lErr = RegQueryValueExT(hSubKey, NULL , NULL, &dwType,
|
||
|
(BYTE *) ptszValue, (ULONG *) pcbValue);
|
||
|
if (lErr == ERROR_SUCCESS)
|
||
|
{
|
||
|
TCHAR *ptszScan = ptszValue; // used to scan along string
|
||
|
TCHAR *ptszDest = ptszValue; // used as destination when copying
|
||
|
|
||
|
// if the name is quoted then ...
|
||
|
if (*ptszScan == '\"')
|
||
|
{
|
||
|
ptszScan++;
|
||
|
|
||
|
// copy all non-quote characters down to base of buffer
|
||
|
// until end of quoted string
|
||
|
while (*ptszScan != '\0' && *ptszScan != '\"')
|
||
|
{
|
||
|
*ptszDest++ = *ptszScan++;
|
||
|
}
|
||
|
|
||
|
// terminate string and get length in bytes including nul
|
||
|
*ptszDest++ = '\0';
|
||
|
*pcbValue = (ptszDest - ptszValue) * sizeof(TCHAR);
|
||
|
}
|
||
|
|
||
|
// find first non-white space character
|
||
|
ptszScan = ptszValue;
|
||
|
while (_istspace(*ptszScan))
|
||
|
ptszScan++;
|
||
|
|
||
|
// if there are no non-white space characters this will be true
|
||
|
if (*ptszScan == 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
|
||
|
TCHAR tszTemp[MAX_PATH];
|
||
|
|
||
|
lstrcpy(tszTemp, ptszValue);
|
||
|
*pcbValue = ExpandEnvironmentStrings(tszTemp, ptszValue,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,
|
||
|
LPCTSTR ptszKey,
|
||
|
LPTSTR ptszDllName,
|
||
|
LONG *pclDllName,
|
||
|
ULONG *pulDllThreadType)
|
||
|
{
|
||
|
HKEY hDllEntry = NULL;
|
||
|
|
||
|
// Open the registry key
|
||
|
LONG lerr = RegOpenKeyT(hClsRegEntry, ptszKey, &hDllEntry);
|
||
|
|
||
|
if (ERROR_SUCCESS == lerr)
|
||
|
{
|
||
|
// Read the DLL name
|
||
|
lerr = wQueryStripRegValue(hDllEntry, NULL, ptszDllName, pclDllName);
|
||
|
|
||
|
// Is there a DLL path?
|
||
|
if (ERROR_SUCCESS == lerr)
|
||
|
{
|
||
|
if (wCompareDllName(ptszDllName,OLE32_DLL,OLE32_CHAR_LEN))
|
||
|
{
|
||
|
memcpy(ptszDllName,OLE32_DLL,OLE32_BYTE_LEN);
|
||
|
*pclDllName = OLE32_CHAR_LEN;
|
||
|
// Ole32 DLL will work anywhere
|
||
|
*pulDllThreadType = BOTH_THREADED;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
// Assume there is no registry entry
|
||
|
*pulDllThreadType = SINGLE_THREADED;
|
||
|
|
||
|
// Buffer to hold entry for the registry data.
|
||
|
TCHAR tszModelBuf[MAX_PATH];
|
||
|
DWORD cdwModelBuf = sizeof(tszModelBuf);
|
||
|
DWORD dwRegEntType;
|
||
|
|
||
|
// Read the DLL threading model from the registry
|
||
|
|
||
|
lerr = RegQueryValueExT(hDllEntry, tszDllThreadModel, NULL,
|
||
|
&dwRegEntType, (LPBYTE) &tszModelBuf[0], &cdwModelBuf);
|
||
|
|
||
|
// Is there an thread model descriptor
|
||
|
if (ERROR_SUCCESS == lerr)
|
||
|
{
|
||
|
if ( REG_SZ != dwRegEntType)
|
||
|
{
|
||
|
// If it wasn't a string, bail
|
||
|
}
|
||
|
// Is it apartment model?
|
||
|
|
||
|
else if (lstrcmpi(tszAptModel, tszModelBuf) == 0)
|
||
|
{
|
||
|
*pulDllThreadType = APT_THREADED;
|
||
|
}
|
||
|
// Is is both threaded?
|
||
|
else if (lstrcmpi(tszBothModel, tszModelBuf) == 0)
|
||
|
{
|
||
|
*pulDllThreadType = BOTH_THREADED;
|
||
|
}
|
||
|
else if (lstrcmpi(wszFreeModel, tszModelBuf) == 0)
|
||
|
{
|
||
|
*pulDllThreadType = FREE_THREADED;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// BUGBUG: Should print a warning here
|
||
|
}
|
||
|
|
||
|
// If neither then we fall back to single threaded
|
||
|
// since this is guaranteed to be safe for the DLL.
|
||
|
}
|
||
|
|
||
|
// 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;
|
||
|
}
|
||
|
|
||
|
|