mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
466 lines
14 KiB
466 lines
14 KiB
//---------------------------------------------------------------------------
|
|
//
|
|
// Copyright (c) Microsoft Corporation 1991-1993
|
|
//
|
|
// File: ole2dup.c
|
|
//
|
|
// This file contains all the duplicated code from OLE 2.0 DLLs to avoid
|
|
// any link to their DLLs from the shell. If we decided to have links to
|
|
// them, we need to delete these files.
|
|
//
|
|
// History:
|
|
// 12-29-92 SatoNa Created.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "shellprv.h"
|
|
#pragma hdrstop
|
|
|
|
// scan lpsz for a number of hex digits (at most 8); update lpsz, return
|
|
// value in Value; check for chDelim; return TRUE for success.
|
|
BOOL HexStringToDword(LPCTSTR * lplpsz, DWORD * lpValue, int cDigits, TCHAR chDelim)
|
|
{
|
|
int ich;
|
|
LPCTSTR lpsz = *lplpsz;
|
|
DWORD Value = 0;
|
|
BOOL fRet = TRUE;
|
|
|
|
for (ich = 0; ich < cDigits; ich++)
|
|
{
|
|
TCHAR ch = lpsz[ich];
|
|
if (InRange(ch, TEXT('0'), TEXT('9')))
|
|
{
|
|
Value = (Value << 4) + ch - TEXT('0');
|
|
}
|
|
else if ( InRange( (ch |= (TEXT('a')-TEXT('A'))), TEXT('a'), TEXT('f')) )
|
|
{
|
|
Value = (Value << 4) + ch - TEXT('a') + 10;
|
|
}
|
|
else
|
|
return(FALSE);
|
|
}
|
|
|
|
if (chDelim)
|
|
{
|
|
fRet = (lpsz[ich++]==chDelim);
|
|
}
|
|
|
|
*lpValue = Value;
|
|
*lplpsz = lpsz+ich;
|
|
|
|
return fRet;
|
|
}
|
|
|
|
// parse above format; return TRUE if succesful; always writes over *pguid.
|
|
STDAPI_(BOOL) GUIDFromString(LPCTSTR lpsz, LPGUID pguid)
|
|
{
|
|
DWORD dw;
|
|
if (*lpsz++ != TEXT('{') /*}*/ )
|
|
return FALSE;
|
|
|
|
if (!HexStringToDword(&lpsz, &pguid->Data1, SIZEOF(DWORD)*2, TEXT('-')))
|
|
return FALSE;
|
|
|
|
if (!HexStringToDword(&lpsz, &dw, SIZEOF(WORD)*2, TEXT('-')))
|
|
return FALSE;
|
|
|
|
pguid->Data2 = (WORD)dw;
|
|
|
|
if (!HexStringToDword(&lpsz, &dw, SIZEOF(WORD)*2, TEXT('-')))
|
|
return FALSE;
|
|
|
|
pguid->Data3 = (WORD)dw;
|
|
|
|
if (!HexStringToDword(&lpsz, &dw, SIZEOF(BYTE)*2, 0))
|
|
return FALSE;
|
|
|
|
pguid->Data4[0] = (BYTE)dw;
|
|
|
|
if (!HexStringToDword(&lpsz, &dw, SIZEOF(BYTE)*2, TEXT('-')))
|
|
return FALSE;
|
|
|
|
pguid->Data4[1] = (BYTE)dw;
|
|
|
|
if (!HexStringToDword(&lpsz, &dw, SIZEOF(BYTE)*2, 0))
|
|
return FALSE;
|
|
|
|
pguid->Data4[2] = (BYTE)dw;
|
|
|
|
if (!HexStringToDword(&lpsz, &dw, SIZEOF(BYTE)*2, 0))
|
|
return FALSE;
|
|
|
|
pguid->Data4[3] = (BYTE)dw;
|
|
|
|
if (!HexStringToDword(&lpsz, &dw, SIZEOF(BYTE)*2, 0))
|
|
return FALSE;
|
|
|
|
pguid->Data4[4] = (BYTE)dw;
|
|
|
|
if (!HexStringToDword(&lpsz, &dw, SIZEOF(BYTE)*2, 0))
|
|
return FALSE;
|
|
|
|
pguid->Data4[5] = (BYTE)dw;
|
|
|
|
if (!HexStringToDword(&lpsz, &dw, SIZEOF(BYTE)*2, 0))
|
|
return FALSE;
|
|
|
|
pguid->Data4[6] = (BYTE)dw;
|
|
if (!HexStringToDword(&lpsz, &dw, SIZEOF(BYTE)*2, /*(*/ TEXT('}')))
|
|
return FALSE;
|
|
|
|
pguid->Data4[7] = (BYTE)dw;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// StringFromGUID2A
|
|
//
|
|
// converts GUID into (...) form without leading identifier; returns
|
|
// amount of data copied to lpsz if successful; 0 if buffer too small.
|
|
//
|
|
|
|
// An endian-dependant map of what bytes go where in the GUID
|
|
// text representation.
|
|
//
|
|
// Do NOT use the TEXT() macro in GuidMap... they're intended to be bytes
|
|
//
|
|
|
|
static const BYTE GuidMap[] = { 3, 2, 1, 0, '-', 5, 4, '-', 7, 6, '-',
|
|
8, 9, '-', 10, 11, 12, 13, 14, 15 };
|
|
|
|
static const TCHAR szDigits[] = TEXT("0123456789ABCDEF");
|
|
|
|
STDAPI_(int) StringFromGUID2A(UNALIGNED REFGUID rguid, LPTSTR lpsz, int cbMax)
|
|
{
|
|
int i;
|
|
|
|
const BYTE * pBytes = (const BYTE *) rguid;
|
|
|
|
if (cbMax < GUIDSTR_MAX)
|
|
return 0;
|
|
|
|
*lpsz++ = TEXT('{');
|
|
|
|
for (i = 0; i < SIZEOF(GuidMap); i++)
|
|
{
|
|
if (GuidMap[i] == '-') // don't TEXT() this line
|
|
{
|
|
*lpsz++ = TEXT('-');
|
|
}
|
|
else
|
|
{
|
|
*lpsz++ = szDigits[ (pBytes[GuidMap[i]] & 0xF0) >> 4 ];
|
|
*lpsz++ = szDigits[ (pBytes[GuidMap[i]] & 0x0F) ];
|
|
}
|
|
}
|
|
*lpsz++ = TEXT('}');
|
|
*lpsz = TEXT('\0');
|
|
|
|
|
|
return GUIDSTR_MAX;
|
|
}
|
|
|
|
// translate string form of CLSID into binary form; tries Ole1Class too.
|
|
// errors: E_INVALIDARG, CO_E_CLASSSTRING, REGDB_E_WRITEREGDB
|
|
STDAPI SHCLSIDFromString(LPCTSTR lpsz, LPCLSID lpclsid)
|
|
{
|
|
if (lpsz == NULL) {
|
|
*lpclsid = CLSID_NULL;
|
|
return NOERROR;
|
|
}
|
|
|
|
return GUIDFromString(lpsz,lpclsid) ? NOERROR : ResultFromScode(CO_E_CLASSSTRING);
|
|
}
|
|
|
|
//
|
|
// This needs to stay CHAR because it is used with
|
|
// GetProcAddress, which is NOT Unicode.
|
|
CHAR const c_szDllGetClassObject[] = "DllGetClassObject";
|
|
|
|
HRESULT _CreateInstance(const CLSID FAR* pclsid, LPCTSTR szDllName, LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppv)
|
|
{
|
|
HRESULT hres = ResultFromScode(REGDB_E_CLASSNOTREG);
|
|
LPFNGETCLASSOBJECT lpfn = SHGetHandlerEntry(szDllName, c_szDllGetClassObject, NULL);
|
|
if (lpfn)
|
|
{
|
|
IClassFactory *pCF;
|
|
hres = lpfn(pclsid, &IID_IClassFactory, &pCF);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
if (IsBadReadPtr(pCF, SIZEOF(pCF->lpVtbl))
|
|
|| IsBadReadPtr(pCF->lpVtbl, SIZEOF(*pCF->lpVtbl))
|
|
|| IsBadCodePtr(pCF->lpVtbl->CreateInstance))
|
|
{
|
|
DebugMsg(DM_ERROR, TEXT("sh ER - DllGetClassObject returned invalid object (%s)"), szDllName);
|
|
Assert(0);
|
|
hres = ResultFromScode(E_UNEXPECTED);
|
|
}
|
|
else
|
|
{
|
|
hres = pCF->lpVtbl->CreateInstance(pCF, pUnkOuter, riid, ppv);
|
|
pCF->lpVtbl->Release(pCF);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("sh TR CoCreateInstance: GetClassObject failed (%s, %x)"), szDllName, hres);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DWORD err = GetLastError();
|
|
hres = HRESULT_FROM_WIN32(err);
|
|
DebugMsg(DM_TRACE, TEXT("sh TR CoCreateInstance: SHGetHandlerEntry failed (%s, %x)"), szDllName, hres);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
typedef struct _shregclass {
|
|
CLSID clsid;
|
|
LPUNKNOWN pUnk;
|
|
} SHREGCLASS;
|
|
|
|
static HDSA hdsaRegClasses = NULL;
|
|
static UINT s_iClasses = 0;
|
|
|
|
HRESULT _FindRegisteredClass(const CLSID *pclsid, IClassFactory **ppCF)
|
|
{
|
|
INT i;
|
|
|
|
*ppCF = NULL;
|
|
|
|
if (!hdsaRegClasses)
|
|
return REGDB_E_CLASSNOTREG; // A nice sounding error code...
|
|
|
|
for (i = DSA_GetItemCount(hdsaRegClasses) - 1; i >= 0; i--)
|
|
{
|
|
SHREGCLASS *lpsrc;
|
|
lpsrc = DSA_GetItemPtr(hdsaRegClasses, i);
|
|
if (lpsrc != NULL && lpsrc->pUnk != NULL)
|
|
{
|
|
if (IsEqualIID(pclsid, &lpsrc->clsid))
|
|
return lpsrc->pUnk->lpVtbl->QueryInterface(lpsrc->pUnk, &IID_IClassFactory, ppCF);
|
|
}
|
|
}
|
|
return REGDB_E_CLASSNOTREG; // A nice sounding error code...
|
|
}
|
|
|
|
STDAPI SHCoRegisterClassObject( const CLSID *pclsid, LPUNKNOWN pUnk,
|
|
DWORD dwClsContext, DWORD dwFlags, LPDWORD lpdwRegister)
|
|
{
|
|
HRESULT hres = E_OUTOFMEMORY;
|
|
|
|
Assert(dwClsContext == CLSCTX_INPROC_SERVER);
|
|
Assert(dwFlags == REGCLS_MULTIPLEUSE);
|
|
if (dwClsContext != CLSCTX_INPROC_SERVER || dwFlags != REGCLS_MULTIPLEUSE)
|
|
return E_INVALIDARG; // We don't support this other stuff
|
|
|
|
if (!hdsaRegClasses)
|
|
{
|
|
hdsaRegClasses = DSA_Create(SIZEOF(SHREGCLASS), 4);
|
|
}
|
|
if (hdsaRegClasses)
|
|
{
|
|
SHREGCLASS src;
|
|
|
|
src.clsid = *pclsid;
|
|
src.pUnk = pUnk;
|
|
pUnk->lpVtbl->AddRef(pUnk);
|
|
*lpdwRegister = DSA_InsertItem(hdsaRegClasses, 0x7FFF, &src);
|
|
s_iClasses++;
|
|
hres = S_OK;
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
|
|
STDAPI SHCoRevokeClassObject(DWORD dwRegister)
|
|
{
|
|
SHREGCLASS *lpsrc;
|
|
|
|
if (!hdsaRegClasses)
|
|
return E_INVALIDARG;
|
|
|
|
lpsrc = DSA_GetItemPtr(hdsaRegClasses, dwRegister);
|
|
if (lpsrc && lpsrc->pUnk) {
|
|
lpsrc->pUnk->lpVtbl->Release(lpsrc->pUnk);
|
|
lpsrc->pUnk = NULL;
|
|
--s_iClasses;
|
|
if (s_iClasses == 0)
|
|
{
|
|
DSA_Destroy(hdsaRegClasses);
|
|
hdsaRegClasses = NULL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
else
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
const TCHAR c_szInProcServer[]= TEXT("\\InProcServer32");
|
|
const TCHAR c_szThreadingModel[] = TEXT("ThreadingModel");
|
|
const TCHAR c_szApartment[] = TEXT("Apartment");
|
|
const TCHAR c_szBoth[] = TEXT("Both");
|
|
|
|
STDAPI SHCoCreateInstance(LPCTSTR pszCLSID, const CLSID * pclsid,
|
|
LPUNKNOWN pUnkOuter, REFIID riid, LPVOID FAR* ppv)
|
|
{
|
|
HRESULT hres = ResultFromScode(REGDB_E_CLASSNOTREG);
|
|
CLSID clsidT;
|
|
TCHAR szClass[GUIDSTR_MAX+ARRAYSIZE(c_szInProcServer)];
|
|
|
|
if (pclsid)
|
|
{
|
|
if (!pszCLSID)
|
|
{
|
|
StringFromGUID2A(pclsid, szClass, ARRAYSIZE(szClass));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pszCLSID)
|
|
{
|
|
lstrcpy(szClass,pszCLSID);
|
|
if (SUCCEEDED(SHCLSIDFromString(pszCLSID, &clsidT)))
|
|
pclsid=&clsidT;
|
|
}
|
|
}
|
|
|
|
|
|
if (pclsid)
|
|
{
|
|
LONG err;
|
|
HKEY hkeyDll;
|
|
IClassFactory *pCF;
|
|
|
|
Assert(hres == ResultFromScode(REGDB_E_CLASSNOTREG));
|
|
|
|
lstrcat(szClass,c_szInProcServer); // Add "\InProcServer32"
|
|
|
|
hres = _FindRegisteredClass(pclsid, &pCF);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = pCF->lpVtbl->CreateInstance(pCF, pUnkOuter, riid, ppv);
|
|
pCF->lpVtbl->Release(pCF);
|
|
}
|
|
else
|
|
{
|
|
if (g_hkcrCLSID && RegOpenKey(g_hkcrCLSID, szClass, &hkeyDll) == ERROR_SUCCESS)
|
|
{
|
|
TCHAR szDllName[MAX_PATH];
|
|
LONG cbValue = SIZEOF(szDllName);
|
|
|
|
// 1 2 3
|
|
// 012345678901234567890123456789012345678 = nul is at 38!
|
|
// "{12345678-1234-1234-1234-123456789012}"
|
|
//
|
|
szClass[38] = TEXT('\0'); // Get rid of "\InProcServer32"
|
|
|
|
err = RegQueryValue(hkeyDll, NULL, szDllName, &cbValue);
|
|
|
|
#ifdef WINNT
|
|
//
|
|
// On NT, we must check to ensure that this CLSID exists in
|
|
// the list of approved CLSIDs that can be used in-process.
|
|
// If not, we fail the creation with ERROR_ACCESS_DENIED.
|
|
// We explicitly allow anything serviced by this DLL
|
|
//
|
|
|
|
if (err == ERROR_SUCCESS && NULL != g_hklmApprovedExt)
|
|
{
|
|
TCHAR szBuf[MAX_PATH];
|
|
|
|
//
|
|
// Check to see if we are using this DLL
|
|
//
|
|
// BUGBUG Assumes no parameters in InProcServer32. We
|
|
// should remove this assumption once we lose shellalt,
|
|
// after which we can just lstrcpyn(,,<length of dll name>);
|
|
|
|
LPCTSTR pszDllName = PathFindFileName(szDllName);
|
|
|
|
if (lstrcmp(pszDllName, TEXT("shell32.dll")) &&
|
|
lstrcmp(pszDllName, TEXT("shellalt.dll")))
|
|
{
|
|
DWORD dwType;
|
|
TCHAR szValue[MAX_PATH];
|
|
DWORD cbSize = SIZEOF(szValue);
|
|
|
|
if (ERROR_SUCCESS != RegQueryValueEx(g_hklmApprovedExt,
|
|
szClass,
|
|
0,
|
|
&dwType,
|
|
(LPBYTE) szValue,
|
|
&cbSize))
|
|
{
|
|
hres = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
|
|
return hres;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (err == ERROR_SUCCESS)
|
|
{
|
|
TCHAR szThreadingModel[MAX_PATH];
|
|
BOOL fMultiThreadAware = FALSE;
|
|
DWORD dwRegType;
|
|
DWORD cbRead = SIZEOF(szThreadingModel);
|
|
|
|
err = RegQueryValueEx(hkeyDll, c_szThreadingModel, NULL,
|
|
&dwRegType, (LPBYTE)szThreadingModel, &cbRead);
|
|
if (err == ERROR_SUCCESS && dwRegType == REG_SZ)
|
|
{
|
|
if (lstrcmpi(szThreadingModel, c_szApartment)==0
|
|
|| lstrcmpi(szThreadingModel, c_szBoth)==0)
|
|
{
|
|
fMultiThreadAware = TRUE;
|
|
}
|
|
}
|
|
|
|
// #define HACK_APARTMENT_ONLY_ASSERT
|
|
#ifdef HACK_APARTMENT_ONLY_ASSERT
|
|
if (!fMultiThreadAware)
|
|
{
|
|
_asm {
|
|
int 3;
|
|
}
|
|
}
|
|
Assert(fMultiThreadAware);
|
|
hres = _CreateInstance(pclsid, szDllName, pUnkOuter, riid, ppv);
|
|
#else
|
|
if (fMultiThreadAware)
|
|
{
|
|
hres = _CreateInstance(pclsid, szDllName, pUnkOuter, riid, ppv);
|
|
}
|
|
else
|
|
{
|
|
Assert(hres == ResultFromScode(REGDB_E_CLASSNOTREG));
|
|
DebugMsg(DM_ERROR, TEXT("sh TR - SHCoCreateInstance !!! InProcServer32 (%s) does not support multi-threading"), szDllName);
|
|
Assert(0);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
RegCloseKey(hkeyDll);
|
|
}
|
|
}
|
|
|
|
if (hres == ResultFromScode(REGDB_E_CLASSNOTREG))
|
|
{
|
|
//
|
|
// Even though the registry is broken, we should be able to
|
|
// create shell stuff.
|
|
//
|
|
hres = _CreateInstance(pclsid, c_szShell32DLL, pUnkOuter, riid, ppv);
|
|
if (hres == ResultFromScode(CLASS_E_CLASSNOTAVAILABLE))
|
|
hres = ResultFromScode(REGDB_E_CLASSNOTREG);
|
|
}
|
|
AssertMsg(SUCCEEDED(hres), TEXT("sh TR CoCreateInstance: failed (%s,%x)"), szClass, hres);
|
|
}
|
|
|
|
return hres;
|
|
}
|