windows-nt/Source/XPSP1/NT/ds/security/services/smartcrd/common/noncom.cpp
2020-09-26 16:20:57 +08:00

493 lines
10 KiB
C++

/*++
Copyright (C) Microsoft Corporation, 1998 - 1999
Module Name:
noncom
Abstract:
This module provides a means to bypass COM, such that typical in-process
COM objects can be called directly in any operating system.
Author:
Doug Barlow (dbarlow) 1/4/1999
Notes:
?Notes?
--*/
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <scardlib.h>
#include <ole2.h>
#include <unknwn.h>
#include <noncom.h>
typedef HRESULT
(STDAPICALLTYPE *GetClassObjectFunc)(
REFCLSID rclsid,
REFIID riid,
LPVOID * ppv);
#ifdef UNDER_TEST
typedef struct {
IID iid;
HINSTANCE hDll;
GetClassObjectFunc pgco;
} NonComModuleStruct;
class NonComControlStruct
{
public:
DWORD dwInitializeCount;
CRITICAL_SECTION csLock;
CDynamicArray<NonComModuleStruct> rgModules;
};
static NonComControlStruct *l_pControl = NULL;
/*++
NoCoInitialize:
This function initializes the NonCOM subsystem.
Arguments:
pvReserved - [in] Reserved; must be NULL.
Return Value:
S_OK - The NonCOM subsystem was initialized correctly.
S_FALSE - The NonCOM library is already initialized.
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 1/4/1999
--*/
STDAPI
NoCoInitialize(
LPVOID pvReserved)
{
HRESULT hReturn = E_UNEXPECTED;
//
// Validate parameters.
//
if (NULL != pvReserved)
{
hReturn = E_INVALIDARG;
goto ErrorExit;
}
//
// Create the Control structure, if necessary.
//
if (NULL == l_pControl)
{
l_pControl = new NonComControlStruct;
if (NULL == l_pControl)
{
hReturn = E_OUTOFMEMORY;
goto ErrorExit;
}
InitializeCriticalSection(&l_pControl->csLock);
CCritSect csLock(&l_pControl->csLock);
// ?code? Database initialization
l_pControl->dwInitializeCount = 1;
}
else
{
CCritSect csLock(&l_pControl->csLock);
ASSERT(0 < l_pControl->dwInitializeCount);
l_pControl->dwInitializeCount += 1;
}
return S_OK;
ErrorExit:
return hReturn;
}
/*++
NoCoUninitialize:
Closes the NonCOM library on the current apartment, unloads all DLLs
loaded by the apartment, frees any other resources that the apartment
maintains, and forces all RPC connections on the apartment to close.
Arguments:
None
Return Value:
None
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 1/4/1999
--*/
STDAPI_(void)
NoCoUninitialize(
void)
{
DWORD dwI;
NonComModuleStruct *pMod;
if (NULL != l_pControl)
{
{
CCritSect csLock(&l_pControl->csLock);
ASSERT(0 < l_pControl->dwInitializeCount);
l_pControl->dwInitializeCount -= 1;
if (0 == l_pControl->dwInitializeCount)
{
for (dwI = l_pControl->rgModules.Count(); 0 < dwI;)
{
pMod = l_pControl->rgModules[--dwI];
FreeLibrary(pMod->hDll);
delete pMod;
}
l_pControl->rgModules.Clear();
}
}
DeleteCriticalSection(&l_pControl->csLock);
delete l_pControl;
l_pControl = NULL;
}
}
#endif
/*++
NoCoGetClassObject:
Provides a pointer to an interface on a class object associated with a
specified CLSID. CoGetClassObject locates, and if necessary, dynamically
loads the executable code required to do this.
Arguments:
rclsid - [in] CLSID associated with the data and code that you will use to
create the objects.
riid - [in] Reference to the identifier of the interface, which will be
supplied in ppv on successful return. This interface will be used to
communicate with the class object.
ppv - [out] Address of pointer variable that receives the interface
pointer requested in riid. Upon successful return, *ppv contains the
requested interface pointer.
Return Value:
S_OK - Location and connection to the specified class object was successful.
REGDB_E_CLASSNOTREG - CLSID is not properly registered. Can also indicate
that the value you specified in dwClsContext is not in the registry.
E_NOINTERFACE - Either the object pointed to by ppv does not support the
interface identified by riid, or the QueryInterface operation on the
class object returned E_NOINTERFACE.
REGDB_E_READREGDB - Error reading the registration database.
CO_E_DLLNOTFOUND - In-process DLL not found.
E_ACCESSDENIED - General access failure.
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 1/4/1999
--*/
STDAPI
NoCoGetClassObject(
REFCLSID rclsid,
REFIID riid,
LPVOID * ppv)
{
DWORD dwStatus;
HRESULT hReturn = E_UNEXPECTED;
TCHAR szGuid[40];
CBuffer szDll;
HINSTANCE hDll = NULL;
GetClassObjectFunc pfGetObject;
#ifdef UNDER_TEST
if (NULL == l_pControl)
{
hReturn = NoCoInitialize(NULL);
if (S_OK != hReturn)
goto ErrorExit;
}
{
DWORD dwI;
CCritSect(&l_pControl->csLock);
for (dwI = l_pControl->rgModules.Count(); 0 < dwI;)
{
dwI -= 1;
if (IsEqualGUID(l_pControl->rgModules[dwI]->iid, rclsid))
{
try
{
hReturn = (*l_pControl->rgModules[dwI]->pgco)(rclsid, riid, ppv);
}
catch (...)
{
hReturn = E_UNEXPECTED;
}
goto ErrorExit;
}
}
}
#endif
StringFromGuid(&rclsid, szGuid);
try
{
//
// Open the Class Registry Database.
//
CRegistry regClsId(
HKEY_CLASSES_ROOT,
TEXT("ClsID"),
KEY_READ);
dwStatus = regClsId.Status(TRUE);
if (ERROR_SUCCESS != dwStatus)
{
hReturn = REGDB_E_READREGDB;
goto ErrorExit;
}
//
// Look up the specified Class.
//
CRegistry regClass(
regClsId,
szGuid,
KEY_READ);
dwStatus = regClass.Status(TRUE);
if (ERROR_SUCCESS != dwStatus)
{
hReturn = REGDB_E_CLASSNOTREG;
goto ErrorExit;
}
//
// Get the registered InProcess Server.
//
CRegistry regServer(
regClass,
TEXT("InprocServer32"),
KEY_READ);
dwStatus = regServer.Status(TRUE);
if (ERROR_SUCCESS != dwStatus)
{
hReturn = REGDB_E_CLASSNOTREG;
goto ErrorExit;
}
//
// Get the handler DLL name.
//
regServer.GetValue(TEXT(""), szDll);
}
catch (DWORD dwError)
{
switch (dwError)
{
case ERROR_OUTOFMEMORY:
hReturn = E_OUTOFMEMORY;
break;
default:
hReturn = HRESULT_FROM_WIN32(dwError);
}
goto ErrorExit;
}
//
// We've got the target DLL. Load it and look for the entrypoint.
//
hDll = LoadLibrary((LPCTSTR)szDll.Access());
if (NULL == hDll)
{
hReturn = CO_E_DLLNOTFOUND;
goto ErrorExit;
}
pfGetObject = (GetClassObjectFunc)GetProcAddress(
hDll,
"DllGetClassObject");
if (NULL == pfGetObject)
{
hReturn = E_NOINTERFACE;
goto ErrorExit;
}
#ifdef UNDER_TEST
{
NonComModuleStruct *pMod = new NonComModuleStruct;
if (NULL == pMod)
{
hReturn = E_OUTOFMEMORY;
goto ErrorExit;
}
pMod->hDll = hDll;
CopyMemory(&pMod->iid, &rclsid, sizeof(IID));
pMod->pgco = pfGetObject;
try
{
l_pControl->rgModules.Add(pMod);
}
catch (...)
{
delete pMod;
}
}
#endif
try
{
hReturn = (*pfGetObject)(rclsid, riid, ppv);
}
catch (...)
{
hReturn = E_UNEXPECTED;
}
if (S_OK != hReturn)
goto ErrorExit;
//
// Add the Handler to our database.
//
// ?code? -- No database yet.
hDll = NULL;
ASSERT(NULL == hDll);
return S_OK;
ErrorExit:
if (NULL != hDll)
FreeLibrary(hDll);
return hReturn;
}
/*++
NoCoCreateInstance:
Creates a single uninitialized object of the class associated with a
specified CLSID. Call CoCreateInstance when you want to create only one
object on the local system.
Arguments:
rclsid - [in] CLSID associated with the data and code that will be used to
create the object.
pUnkOuter - [in] If NULL, indicates that the object is not being created as
part of an aggregate. If non-NULL, pointer to the aggregate object's
IUnknown interface (the controlling IUnknown).
riid - [in] Reference to the identifier of the interface to be used to
communicate with the object.
ppv - [out] Address of pointer variable that receives the interface
pointer requested in riid. Upon successful return, *ppv contains the
requested interface pointer.
Return Value:
S_OK - An instance of the specified object class was successfully created.
REGDB_E_CLASSNOTREG - A specified class is not registered in the
registration database. Also can indicate that the type of server you
requested in the CLSCTX enumeration is not registered or the values
for the server types in the registry are corrupt.
Author:
Doug Barlow (dbarlow) 1/15/1999
--*/
STDAPI
NoCoCreateInstance(
REFCLSID rclsid,
LPUNKNOWN pUnkOuter,
REFIID riid,
LPVOID * ppv)
{
HRESULT hReturn = E_UNEXPECTED;
IClassFactory *pCF = NULL;
hReturn = NoCoGetClassObject(rclsid, IID_IClassFactory, (LPVOID*)&pCF);
if (S_OK != hReturn)
goto ErrorExit;
hReturn = pCF->CreateInstance(pUnkOuter, riid, ppv);
if (S_OK != hReturn)
goto ErrorExit;
pCF->Release();
pCF = NULL;
return S_OK;
ErrorExit:
if (NULL != pCF)
pCF->Release();
return hReturn;
}