summaryrefslogblamecommitdiffstats
path: root/private/ole32/common/olescm.cxx
blob: ecfafb1cf8c1eda2a9032ea0ed4a4c7af778aeb7 (plain) (tree)














































































































































































































































































































































































                                                                                         
//+---------------------------------------------------------------------------
//
//  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;
}