Windows NT 4.0 source code leak
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

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