|
|
/*******************************************************************************
* * (C) COPYRIGHT MICROSOFT CORP., 1997 * * TITLE: CFactory.Cpp * * VERSION: 2.0 * * AUTHOR: ReedB * * DATE: 26 Dec, 1997 * * DESCRIPTION: * Class factory implementation for ImageIn. * *******************************************************************************/ #include "precomp.h"
#include "stiexe.h"
//#include <assert.h>
#include "wiacfact.h"
#include <sddl.h>
extern HINSTANCE g_hInst;
BOOL setValue(LPCTSTR, LPCTSTR, LPCTSTR); BOOL setBinValue(LPCTSTR, LPCTSTR, DWORD, BYTE*); BOOL setKeyAndValue(LPCTSTR, LPCTSTR, LPCTSTR); BOOL SubkeyExists(LPCTSTR, LPCTSTR); LONG recursiveDeleteKey(HKEY, LPCTSTR);
BOOL GetWiaDefaultDCOMSecurityDescriptor( VOID **ppSecurityDescriptor, ULONG *pulSize) { ULONG ulAclSize = 0; BOOL bRet = FALSE;
//
// Create our security descriptor. We do this using a string format security
// descriptor, which we then convert to a real security descriptor.
//
// NOTE: Caller has to free the security descriptor with LocalFree...
//
if ( ConvertStringSecurityDescriptorToSecurityDescriptor(wszDefaultDaclForDCOMAccessPermission, SDDL_REVISION_1, (PSECURITY_DESCRIPTOR*)ppSecurityDescriptor, pulSize)) { bRet = TRUE; } else { DBG_ERR(("ConvertStringSecurityDescriptorToSecurityDescriptor Failed")); } return bRet;
}
/*******************************************************************************
* * RegisterServer * * DESCRIPTION: * Register a COM component in the Registry. From Inside COM. * * PARAMETERS: * *******************************************************************************/
HRESULT RegisterServer( LPCTSTR szModuleFileName, const CLSID* pclsid, LPCTSTR szFriendlyName, LPCTSTR szVerIndProgID, LPCTSTR szProgID, LPCTSTR szService, const GUID* plibid, BOOLEAN bOutProc) { BOOL bResult = TRUE;
//
// Fill in the path to the module file name.
//
TCHAR szModule[MAX_PATH] = {0};
if (!GetModuleFileName(g_hInst, szModule, sizeof(szModule)/sizeof(szModule[0]) - 1)) { #ifdef DEBUG
OutputDebugString(TEXT("Error extracting service module name.")); #endif
return E_FAIL; }
//
// Strip the filename from the path
//
TCHAR *pChar = &szModule[lstrlen(szModule)]; while ((pChar > szModule) && (*pChar != '\\')) { pChar--; }
if (pChar == szModule) { #ifdef DEBUG
OutputDebugString(TEXT("Error extracting Still Image service path.")); #endif
return E_FAIL; } else { pChar++; *pChar = '\0'; }
if (szModuleFileName) { if (lstrlen(szModuleFileName) > (int)((sizeof(szModule) / sizeof(szModule[0]) - lstrlen(szModule)))) { #ifdef DEBUG
OutputDebugString(TEXT("szModuleFileName parameter is too long.")); #endif
return E_INVALIDARG; } } else { #ifdef DEBUG
OutputDebugString(TEXT("NULL szModuleFileName parameter")); #endif
return E_INVALIDARG; }
//
// Concatenate server module name (XXXXX.exe) with path
//
if( lstrcat(szModule, szModuleFileName) == NULL) { #ifdef DEBUG
OutputDebugString(TEXT("Error concatenating module file name and path")); #endif
return E_FAIL; }
// Convert the CLSID into a char.
LPOLESTR pszCLSID; LPOLESTR pszLIBID; TCHAR szCLSID[64]; TCHAR szLIBID[64];
HRESULT hr = StringFromCLSID(*pclsid, &pszCLSID); if (FAILED(hr)) { return hr; }
hr = StringFromCLSID(*plibid, &pszLIBID); if (FAILED(hr)) { return hr; }
#ifdef UNICODE
lstrcpy(szCLSID, pszCLSID); lstrcpy(szLIBID, pszLIBID); #else
WideCharToMultiByte(CP_ACP, 0, pszCLSID, -1, szCLSID, sizeof(szCLSID), NULL, NULL); WideCharToMultiByte(CP_ACP, 0, pszLIBID, -1, szLIBID, sizeof(szLIBID), NULL, NULL); #endif
// Build the key CLSID\\{...}
TCHAR szKey[64] = TEXT("CLSID\\");
lstrcat(szKey, szCLSID);
// Add the CLSID to the registry.
bResult &= setKeyAndValue(szKey, NULL, szFriendlyName) ;
// Add the server filename subkey under the CLSID key.
if (bOutProc) { bResult &= setKeyAndValue(szKey, TEXT("LocalServer32"), szModule);
// If the server is implemented as a service add the service
// AppID keys and values.
if (szService) { // Add the service AppID value to the CLSID key.
bResult &= setValue(szKey, TEXT("AppID"), szCLSID);
// Add the AppID key.
TCHAR szAppID[64] = TEXT("AppID\\");
lstrcat(szAppID, szCLSID); bResult &= setKeyAndValue(szAppID, NULL, szFriendlyName);
bResult &= setValue(szAppID, TEXT("LocalService"), szService);
//
// Add an ACL to protect instantiation.
//
DWORD dwSize = 0; PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
if (GetWiaDefaultDCOMSecurityDescriptor((VOID**)&pSecurityDescriptor, &dwSize)) { //
// Write this self-relative security descriptor to the AccessPermission value
// under our AppID
//
setBinValue(szAppID, TEXT("AccessPermission"), dwSize, (BYTE*)pSecurityDescriptor); LocalFree(pSecurityDescriptor); pSecurityDescriptor = NULL; } else { DBG_ERR(("GetWiaDefaultDCOMSecurityDescriptor failed")); } } } else { bResult &= setKeyAndValue(szKey, TEXT("InprocServer32"), szModule); }
// Add the ProgID subkey under the CLSID key.
bResult &= setKeyAndValue(szKey, TEXT("ProgID"), szProgID) ;
// Add the version-independent ProgID subkey under CLSID key.
bResult &= setKeyAndValue(szKey, TEXT("VersionIndependentProgID"), szVerIndProgID) ;
// Add the Type Library ID subkey under the CLSID key.
bResult &= setKeyAndValue(szKey, TEXT("TypeLib"), szLIBID) ;
// Add the version-independent ProgID subkey under HKEY_CLASSES_ROOT.
bResult &= setKeyAndValue(szVerIndProgID, NULL, szFriendlyName) ; bResult &= setKeyAndValue(szVerIndProgID, TEXT("CLSID"), szCLSID) ; bResult &= setKeyAndValue(szVerIndProgID, TEXT("CurVer"), szProgID) ;
// Add the versioned ProgID subkey under HKEY_CLASSES_ROOT.
bResult &= setKeyAndValue(szProgID, NULL, szFriendlyName) ; bResult &= setKeyAndValue(szProgID, TEXT("CLSID"), szCLSID) ; CoTaskMemFree(pszCLSID); CoTaskMemFree(pszLIBID);
if (bResult) { return S_OK; } else { return E_FAIL; } }
/*******************************************************************************
* * UnregisterServer * * DESCRIPTION: * Remove a COM component from the registry. From Inside COM. * * PARAMETERS: * *******************************************************************************/
HRESULT UnregisterServer( const CLSID* pclsid, LPCTSTR szVerIndProgID, LPCTSTR szProgID, LPCTSTR szService) { // Convert the CLSID into a char.
LPOLESTR pszCLSID;
HRESULT hr = StringFromCLSID(*pclsid, &pszCLSID);
if (FAILED(hr) || !pszCLSID) { return E_UNEXPECTED; }
TCHAR szCLSID[64];
#ifdef UNICODE
lstrcpy(szCLSID, pszCLSID); #else
WideCharToMultiByte(CP_ACP, 0, pszCLSID, -1, szCLSID, sizeof(szCLSID), NULL, NULL); #endif
// Build the key CLSID\\{...}
TCHAR szKey[64] = TEXT("CLSID\\"); lstrcat(szKey, szCLSID) ;
// Delete the CLSID Key - CLSID\{...}
LONG lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, szKey); if ((lResult != ERROR_SUCCESS) && (lResult != ERROR_FILE_NOT_FOUND)) { return HRESULT_FROM_WIN32(lResult); }
// Delete the AppID Key - AppID\{...}
if (szService) { TCHAR szAppID[64] = TEXT("AppID\\"); lstrcat(szAppID, szCLSID) ;
lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, szAppID); if ((lResult != ERROR_SUCCESS) && (lResult != ERROR_FILE_NOT_FOUND)) { return HRESULT_FROM_WIN32(lResult); } }
// Delete the version-independent ProgID Key.
lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, szVerIndProgID); if ((lResult != ERROR_SUCCESS) && (lResult != ERROR_FILE_NOT_FOUND)) { return HRESULT_FROM_WIN32(lResult); }
// Delete the ProgID key.
lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, szProgID); if ((lResult != ERROR_SUCCESS) && (lResult != ERROR_FILE_NOT_FOUND)) { return HRESULT_FROM_WIN32(lResult); }
CoTaskMemFree(pszCLSID); return S_OK ; }
/*******************************************************************************
* * recursiveDeleteKey * * DESCRIPTION: * Delete a key and all of its descendents. From Inside COM. * PARAMETERS: * *******************************************************************************/
LONG recursiveDeleteKey( HKEY hKeyParent, LPCTSTR lpszKeyChild ) { // Open the child.
HKEY hKeyChild ; LONG lRes = RegOpenKeyEx(hKeyParent, lpszKeyChild, 0, KEY_ALL_ACCESS, &hKeyChild) ; if (lRes != ERROR_SUCCESS) { return lRes ; }
// Enumerate all of the decendents of this child.
FILETIME time ; TCHAR szBuffer[256] ; DWORD dwSize = 256 ; while (RegEnumKeyEx(hKeyChild, 0, szBuffer, &dwSize, NULL, NULL, NULL, &time) == S_OK) { // Delete the decendents of this child.
lRes = recursiveDeleteKey(hKeyChild, szBuffer) ; if (lRes != ERROR_SUCCESS) { // Cleanup before exiting.
RegCloseKey(hKeyChild) ; return lRes; } dwSize = 256 ; }
// Close the child.
RegCloseKey(hKeyChild) ;
// Delete this child.
return RegDeleteKey(hKeyParent, lpszKeyChild) ; }
/*******************************************************************************
* * SubkeyExists * * DESCRIPTION: * Determine if a particular subkey exists. From Inside COM. * * PARAMETERS: * *******************************************************************************/
BOOL SubkeyExists( LPCTSTR pszPath, LPCTSTR szSubkey ) { HKEY hKey ; TCHAR szKeyBuf[80]; UINT uSubKeyChars = 0;
if (!pszPath) { return FALSE; }
if (szSubkey) { // The "+1" is for the TEXT("\\")
uSubKeyChars = lstrlen(szSubkey) + 1; }
if ((lstrlen(pszPath)+uSubKeyChars) > (sizeof(szKeyBuf) / sizeof(szKeyBuf[0]) - 1)) { return FALSE; }
// Copy keyname into buffer.
lstrcpy(szKeyBuf, pszPath) ;
// Add subkey name to buffer.
if (szSubkey != NULL) { lstrcat(szKeyBuf, TEXT("\\")) ; lstrcat(szKeyBuf, szSubkey ) ; }
// Determine if key exists by trying to open it.
LONG lResult = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, szKeyBuf, 0, KEY_READ, &hKey) ; if (lResult == ERROR_SUCCESS) { RegCloseKey(hKey) ; return TRUE ; } return FALSE ; }
/*******************************************************************************
* * setKeyAndValue * * DESCRIPTION: * Create a key and set its value. From Inside OLE. * * PARAMETERS: * *******************************************************************************/
BOOL setKeyAndValue( LPCTSTR szKey, LPCTSTR szSubkey, LPCTSTR szValue) { HKEY hKey; TCHAR szKeyBuf[1024] ; BOOL bVal = FALSE; UINT uSubKeyChars = 0;
if (!szKey) { return FALSE; }
if (szSubkey) { // the "+1" is for the TEXT("\\")
uSubKeyChars = lstrlen(szSubkey) + 1; }
if ((lstrlen(szKey)+uSubKeyChars) > (sizeof(szKeyBuf) / sizeof(szKeyBuf[0]) - 1)) { return FALSE; }
// Copy keyname into buffer.
lstrcpy(szKeyBuf, szKey) ;
// Add subkey name to buffer.
if (szSubkey != NULL) { lstrcat(szKeyBuf, TEXT("\\")) ; lstrcat(szKeyBuf, szSubkey ) ; }
// Create and open key and subkey.
long lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT , szKeyBuf, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) ; if (lResult != ERROR_SUCCESS) { return FALSE ; }
// Set the Value.
if (szValue != NULL) { lResult = RegSetValueEx(hKey, NULL, 0, REG_SZ, (BYTE *)szValue, (lstrlen(szValue)+1) * sizeof(TCHAR)) ; if (lResult == ERROR_SUCCESS) { bVal = TRUE; } }
RegCloseKey(hKey) ; return bVal; }
/*******************************************************************************
* * setValue * * DESCRIPTION: * Create and set a value. * * PARAMETERS: * *******************************************************************************/
BOOL setValue( LPCTSTR pszKey, LPCTSTR pszValueName, LPCTSTR pszValue) { HKEY hKey; DWORD dwSize; BOOL bRet = FALSE;
if (RegOpenKey(HKEY_CLASSES_ROOT, pszKey, &hKey) == ERROR_SUCCESS) {
dwSize = (lstrlen(pszValue) + 1) * sizeof(TCHAR); if (RegSetValueEx(hKey, pszValueName, 0, REG_SZ, (PBYTE) pszValue, dwSize) == ERROR_SUCCESS) { bRet = TRUE; //
// NOTE: Leak here on failure - this should be moved out of this block
//
RegCloseKey(hKey); } } return bRet; }
/*******************************************************************************
* * setBinValue * * DESCRIPTION: * Create and set a binary value. * * PARAMETERS: * *******************************************************************************/ BOOL setBinValue( LPCTSTR pszKey, LPCTSTR pszValueName, DWORD dwSize, BYTE *pbValue) { HKEY hKey; BOOL bRet = FALSE;
if (RegOpenKey(HKEY_CLASSES_ROOT, pszKey, &hKey) == ERROR_SUCCESS) {
if (RegSetValueEx(hKey, pszValueName, 0, REG_BINARY, pbValue, dwSize) == ERROR_SUCCESS) { bRet = TRUE; } RegCloseKey(hKey); } return bRet; }
/*******************************************************************************
* * S T A T I C D A T A * *******************************************************************************/
LONG CFactory::s_cServerLocks = 0; // Count of server locks
HMODULE CFactory::s_hModule = NULL; // DLL module handle
DWORD CFactory::s_dwThreadID = 0;
/*******************************************************************************
* * CFactory constructor * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/
CFactory::CFactory(PFACTORY_DATA pFactoryData): m_cRef(1) { m_pFactoryData = pFactoryData; }
/*******************************************************************************
* * CFactory::QueryInterface * * DESCRIPTION: * IUnknown implementation. * * PARAMETERS: * *******************************************************************************/
HRESULT __stdcall CFactory::QueryInterface(REFIID iid, void** ppv) { if ((iid == IID_IUnknown) || (iid==IID_IClassFactory)) { *ppv = (IClassFactory*)this; } else { return E_NOINTERFACE; } AddRef(); return S_OK; }
/*******************************************************************************
* * CFactory::AddRef * CFactory::Release * * DESCRIPTION: * Reference counting methods. * * PARAMETERS: * *******************************************************************************/
ULONG __stdcall CFactory::AddRef() { return ::InterlockedIncrement(&m_cRef); }
ULONG __stdcall CFactory::Release() { if (::InterlockedDecrement(&m_cRef) == 0) { delete this; return 0 ; } return m_cRef; }
/*******************************************************************************
* * CreateInstance * LockServer * * DESCRIPTION: * Class Factory Interface. * * PARAMETERS: * *******************************************************************************/
HRESULT __stdcall CFactory::CreateInstance( IUnknown* pOuter, const IID& iid, void** ppv ) { *ppv = NULL;
// No support for aggregation, if we have an outer class then bail.
if (pOuter) { return CLASS_E_NOAGGREGATION; }
return m_pFactoryData->CreateInstance(iid, ppv); }
HRESULT __stdcall CFactory::LockServer(BOOL bLock) { if (bLock) { CWiaSvc::AddRef(); } else { CWiaSvc::Release(); }
return S_OK; }
/*******************************************************************************
* * CFactory::CanUnloadNow * * DESCRIPTION: * Determine if the component can be unloaded. * * PARAMETERS: * *******************************************************************************/
HRESULT CFactory::CanUnloadNow() { if (IsLocked()) { return S_FALSE; } else { return S_OK; } }
/*******************************************************************************
* * CFactory::RegisterUnregisterAll * * DESCRIPTION: * Register/Unregister all components. * * PARAMETERS: * *******************************************************************************/
HRESULT CFactory::RegisterUnregisterAll( PFACTORY_DATA pFactoryData, UINT uiFactoryDataCount, BOOLEAN bRegister, BOOLEAN bOutProc ) { HRESULT hr = E_FAIL; UINT i;
for (i = 0; i < uiFactoryDataCount; i++) { if (bRegister) { hr = RegisterServer(pFactoryData[i].szModuleFileName, pFactoryData[i].pclsid, pFactoryData[i].szRegName, pFactoryData[i].szVerIndProgID, pFactoryData[i].szProgID, pFactoryData[i].szService, pFactoryData[i].plibid, bOutProc); } else { hr = UnregisterServer(pFactoryData[i].pclsid, pFactoryData[i].szVerIndProgID, pFactoryData[i].szProgID, pFactoryData[i].szService);
}
if (FAILED(hr)) { break; } } return hr; }
/*******************************************************************************
* * CFactory::StartFactories * * DESCRIPTION: * Start the class factories. * * PARAMETERS: * *******************************************************************************/
BOOL CFactory::StartFactories( PFACTORY_DATA pFactoryData, UINT uiFactoryDataCount ) { PFACTORY_DATA pData, pStart = pFactoryData; PFACTORY_DATA pEnd = &pFactoryData[uiFactoryDataCount - 1];
for (pData = pStart; pData <= pEnd; pData++) {
// Initialize the class factory pointer and cookie.
pData->pIClassFactory = NULL; pData->dwRegister = NULL;
// Create the class factory for this component.
IClassFactory* pIFactory = new CFactory(pData); if (pIFactory) { // Register the class factory.
DWORD dwRegister; HRESULT hr = ::CoRegisterClassObject( *(pData->pclsid), static_cast<IUnknown*>(pIFactory), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dwRegister);
if (FAILED(hr)) { DBG_ERR(("CFactory::StartFactories, CoRegisterClassObject CFactory Failed 0x%X", hr)); pIFactory->Release(); return FALSE; }
// Set the data.
pData->pIClassFactory = pIFactory; pData->dwRegister = dwRegister; } else { DBG_ERR(("CFactory::StartFactories, New CFactory Failed")); } } DBG_TRC(("CFactory::StartFactories, Success")); return TRUE; }
/*******************************************************************************
* * CFactory::StopFactories * * DESCRIPTION: * Stop the class factories. * * PARAMETERS: * *******************************************************************************/
void CFactory::StopFactories( PFACTORY_DATA pFactoryData, UINT uiFactoryDataCount ) { PFACTORY_DATA pData, pStart = pFactoryData; PFACTORY_DATA pEnd = &pFactoryData[uiFactoryDataCount - 1];
for (pData = pStart; pData <= pEnd; pData++) {
// Get the magic cookie and stop the factory from running.
DWORD dwRegister = pData->dwRegister; if (dwRegister != 0) { ::CoRevokeClassObject(dwRegister); }
// Release the class factory.
IClassFactory* pIFactory = pData->pIClassFactory ; if (pIFactory != NULL) { pIFactory->Release() ; } } }
|