Files
UA-.NETStandard/ComIOP/Wrapper/Common/COpcClassFactory.cpp
T
2019-02-14 12:34:33 +02:00

718 lines
20 KiB
C++

/* ========================================================================
* Copyright (c) 2005-2019 The OPC Foundation, Inc. All rights reserved.
*
* OPC Foundation MIT License 1.00
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* The complete license agreement can be found here:
* http://opcfoundation.org/License/MIT/1.00/
* ======================================================================*/
#include "StdAfx.h"
#include "COpcClassFactory.h"
#include "COpcString.h"
#include "OpcRegistry.h"
#include "ntsecapi.h"
// #include "DCOM Config/dcomperm.h"
//============================================================================
// Local Functions
// InstallService
static bool InstallService(
LPCTSTR szServiceName,
LPCTSTR szServiceDescription,
LPCTSTR tsFilePath
)
{
bool bResult = false;
SC_HANDLE hSCM = NULL;
SC_HANDLE hService = NULL;
TRY
{
// open service control manager.
hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM == NULL)
{
THROW_(bResult, false);
}
SC_HANDLE hService = OpenService(hSCM, szServiceName, SERVICE_QUERY_CONFIG);
// check if sevice already installed.
if (hService != NULL)
{
GOTOFINALLY();
}
// create service.
hService = CreateService(
hSCM,
szServiceName,
szServiceDescription,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
tsFilePath,
NULL,
NULL,
_T("RPCSS\0"),
NULL,
NULL);
if (hService == NULL)
{
THROW_(bResult, false);
}
}
CATCH
{
}
FINALLY
if (hService != NULL) CloseServiceHandle(hService);
if (hService != NULL) CloseServiceHandle(hSCM);
return bResult;
}
// UninstallService
static void UninstallService(LPCTSTR szServiceName)
{
SC_HANDLE hSCM = NULL;
SC_HANDLE hService = NULL;
TRY
{
// open service control manager.
hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM == NULL)
{
GOTOFINALLY();
}
hService = OpenService(hSCM, szServiceName, SERVICE_STOP | DELETE);
// check if sevice already uninstalled.
if (hService == NULL)
{
GOTOFINALLY();
}
// send control message to service - ignore errors.
SERVICE_STATUS cStatus;
ZeroMemory(&cStatus, sizeof(cStatus));
ControlService(hService, SERVICE_CONTROL_STOP, &cStatus);
// mark service for deletion.
DeleteService(hService);
}
CATCH
{
}
FINALLY
if (hService != NULL) CloseServiceHandle(hService);
if (hService != NULL) CloseServiceHandle(hSCM);
}
// UnregisterApplication
static void UnregisterApplication(
const COpcString& cModuleName,
const COpcString& cApplicationName,
const GUID& cAppID
)
{
COpcString cSubKey;
// uninstall service.
UninstallService(cApplicationName);
// delete exe sub key.
cSubKey = _T("AppID\\") + cModuleName + _T(".exe");
OpcRegDeleteKey(HKEY_CLASSES_ROOT, cSubKey);
// delete app id sub key.
cSubKey = _T("AppID\\") + (COpcString)cAppID;
OpcRegDeleteKey(HKEY_CLASSES_ROOT, cSubKey);
}
// RegisterApplication
static HRESULT RegisterApplication(
const COpcString& cModuleName,
const COpcString& cModulePath,
const COpcString& cApplicationName,
const COpcString& cApplicationDescription,
const GUID& cAppID,
bool bService,
bool bEveryone
)
{
HRESULT hResult = S_OK;
TRY
{
// create exe sub key.
COpcString cSubKey = _T("AppID\\") + cModuleName + _T(".exe");
if (!OpcRegSetValue(HKEY_CLASSES_ROOT, cSubKey, NULL, (COpcString)cAppID))
{
THROW_(hResult, SELFREG_E_CLASS);
}
// create app id sub key.
cSubKey = _T("AppID\\") + (COpcString)cAppID;
if (!OpcRegSetValue(HKEY_CLASSES_ROOT, cSubKey, NULL, (cApplicationDescription.IsEmpty())?cApplicationName:cApplicationDescription))
{
THROW_(hResult, SELFREG_E_CLASS);
}
/*
// Set application LaunchPermission and AccessPermission to "Everyone".
if (bEveryone)
{
// create authenication sub key.
if (!OpcRegSetValue(HKEY_CLASSES_ROOT, cSubKey, _T("AuthenticationLevel"), (DWORD)1))
{
THROW_(hResult, SELFREG_E_CLASS);
}
// check for OSes earlier than XP SP2
if (IsLegacySecurityModel())
{
static BYTE pEveryone[] = {
0x01,0x00,0x04,0x80,0x34,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x14,0x00,0x00,0x00,0x02,0x00,0x20,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x18,0x00,
0x01,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x01,0x05,0x00,0x00,0x00,0x00,0x00,0x05,0x15,0x00,0x00,0x00,
0xa0,0x5f,0x84,0x1f,0x5e,0x2e,0x6b,0x49,0xce,0x12,0x03,0x03,0xf4,0x01,0x00,0x00,
0x01,0x05,0x00,0x00,0x00,0x00,0x00,0x05,0x15,0x00,0x00,0x00,0xa0,0x5f,0x84,0x1f,
0x5e,0x2e,0x6b,0x49,0xce,0x12,0x03,0x03,0xf4,0x01,0x00,0x00};
// create launch permission sub key.
if (!OpcRegSetValue(HKEY_CLASSES_ROOT, cSubKey, _T("LaunchPermission"), pEveryone, sizeof(pEveryone)))
{
THROW_(hResult, SELFREG_E_CLASS);
}
// create access permission sub key.
if (!OpcRegSetValue(HKEY_CLASSES_ROOT, cSubKey, _T("AccessPermission"), pEveryone, sizeof(pEveryone)))
{
THROW_(hResult, SELFREG_E_CLASS);
}
}
// use the APIs to set permissions for OSes later than or equal XP S2.
else
{
DWORD dwResult = ChangeAppIDAccessACL(
(LPTSTR)(LPCTSTR)(COpcString)cAppID,
_T("Everyone"),
TRUE,
TRUE,
COM_RIGHTS_EXECUTE_LOCAL | COM_RIGHTS_EXECUTE_REMOTE | COM_RIGHTS_EXECUTE);
if (dwResult != ERROR_SUCCESS)
{
// could not set access permissions.
THROW_(hResult, SELFREG_E_CLASS);
}
dwResult = ChangeAppIDLaunchAndActivateACL(
(LPTSTR)(LPCTSTR)(COpcString)cAppID,
_T("Everyone"),
TRUE,
TRUE,
COM_RIGHTS_ACTIVATE_LOCAL | COM_RIGHTS_EXECUTE_LOCAL | COM_RIGHTS_ACTIVATE_REMOTE | COM_RIGHTS_EXECUTE_REMOTE | COM_RIGHTS_EXECUTE);
if (dwResult != ERROR_SUCCESS)
{
// could hResult set launch and activate permissions.
THROW_(hResult, SELFREG_E_CLASS);
}
}
}
*/
// register as a service.
if (bService)
{
// set service application parameters.
if (!OpcRegSetValue(HKEY_CLASSES_ROOT, cSubKey, _T("LocalService"), cApplicationName))
{
THROW_(hResult, SELFREG_E_CLASS);
}
if (!OpcRegSetValue(HKEY_CLASSES_ROOT, cSubKey, _T("ServiceParameters"), _T("-Service")))
{
THROW_(hResult, SELFREG_E_CLASS);
}
// install service.
hResult = InstallService(cApplicationName, cApplicationDescription, cModulePath);
if (FAILED(hResult))
{
THROW();
}
}
}
CATCH
{
UnregisterApplication(cModuleName, cApplicationName, cAppID);
}
return hResult;
}
// GetModuleInfo
static HRESULT GetModuleInfo(
HINSTANCE hModule,
COpcString& cPath,
COpcString& cName,
COpcString& cExtension
)
{
// initialize return parameters.
cPath.Empty();
cName.Empty();
cExtension.Empty();
// lookup the module path.
TCHAR tsModulePath[MAX_PATH+1];
memset(tsModulePath, 0, sizeof(tsModulePath));
DWORD dwResult = GetModuleFileName(hModule, tsModulePath, MAX_PATH);
if (dwResult == 0)
{
return E_UNEXPECTED;
}
cPath = tsModulePath;
// parse module name.
cName = tsModulePath;
int iIndex = cName.ReverseFind(_T("\\"));
if (iIndex != -1)
{
cName = cName.SubStr(iIndex+1);
}
// parse extension.
iIndex = cName.ReverseFind(_T("."));
if (iIndex != -1)
{
cExtension = cName.SubStr(iIndex+1).ToUpper();
cName = cName.SubStr(0, iIndex);
}
// check for valid values.
if (cName.IsEmpty() || cExtension.IsEmpty())
{
return E_UNEXPECTED;
}
return S_OK;
}
//============================================================================
// OpcGetClassObject
HRESULT OpcGetClassObject(
REFCLSID rclsid,
REFIID riid,
LPVOID* ppv,
const TOpcClassTableEntry* pClasses)
{
// find the class factory for a COM server.
for (int ii = 0; pClasses[ii].tsClassName != NULL; ii++)
{
if (*(pClasses[ii].pClsid) == rclsid)
{
// create the class factory - adds a reference.
COpcClassFactory* pFactory = new COpcClassFactory(&(pClasses[ii]));
// query for the desired interface - adds another reference.
HRESULT hResult = pFactory->QueryInterface(riid, ppv);
// release the local reference.
pFactory->Release();
return hResult;
}
}
// clsid was not found in module.
return CLASS_E_CLASSNOTAVAILABLE;
}
//============================================================================
// OpcRegisterClassObjects
OPCUTILS_API HRESULT OpcRegisterClassObjects(
const TOpcClassTableEntry* pClasses,
DWORD dwContext,
DWORD dwFlags,
DWORD* pdwRegister)
{
HRESULT hResult = S_OK;
// register each server in the table.
for (int ii = 0; pClasses[ii].tsClassName != NULL; ii++)
{
IUnknown* ipUnknown = NULL;
// create the class factory - adds a reference.
COpcClassFactory* pFactory = new COpcClassFactory(&(pClasses[ii]));
// query for the IUnknown interface - adds another reference.
hResult = pFactory->QueryInterface(IID_IUnknown, (void**)&ipUnknown);
// release the local reference.
pFactory->Release();
if (FAILED(hResult))
{
return hResult;
}
// register the class factory.
hResult = CoRegisterClassObject(
*(pClasses[ii].pClsid),
ipUnknown,
dwContext,
dwFlags,
&(pdwRegister[ii]));
// release the local reference again.
ipUnknown->Release();
if (FAILED(hResult))
{
return hResult;
}
}
// success.
return S_OK;
}
//============================================================================
// OpcRevokeClassObjects
OPCUTILS_API HRESULT OpcRevokeClassObjects(
const TOpcClassTableEntry* pClasses,
DWORD* pdwRegister)
{
// unregister each server in the table.
for (int ii = 0; pClasses[ii].tsClassName != NULL; ii++)
{
CoRevokeClassObject(pdwRegister[ii]);
}
// success.
return S_OK;
}
//============================================================================
// OpcRegisterServer
HRESULT OpcRegisterServer(
HINSTANCE hModule,
LPCTSTR tsVendorName,
LPCTSTR tsApplicationName,
LPCTSTR tsApplicationDescription,
const GUID& cAppID,
bool bService,
const TOpcClassTableEntry* pClasses,
const TClassCategories* pCategories,
bool bEveryone)
{
HRESULT hResult = S_OK;
TRY
{
// get module information.
COpcString cModulePath;
COpcString cModuleName;
COpcString cModuleExtension;
hResult = GetModuleInfo(hModule, cModulePath, cModuleName, cModuleExtension);
if (FAILED(hResult))
{
THROW_(hResult, SELFREG_E_CLASS);
}
// determine if registering an out of process server.
bool bIsExe = (cModuleExtension == _T("EXE"));
// register application
if (cAppID != GUID_NULL)
{
hResult = RegisterApplication(
cModuleName,
cModulePath,
tsApplicationName,
tsApplicationDescription,
cAppID,
bService,
bEveryone
);
if (FAILED(hResult))
{
THROW();
}
}
// construct type library path
COpcString cTypeLib(cModulePath);
// register type library
ITypeLib* ipTypeLib = NULL;
hResult = LoadTypeLibEx((LPCWSTR)cTypeLib, REGKIND_REGISTER, &ipTypeLib);
if (SUCCEEDED(hResult))
{
ipTypeLib->Release();
}
hResult = S_OK;
// add clsid and prog id registy keys for each class.
for (UINT ii = 0; pClasses[ii].tsClassName != NULL; ii++)
{
COpcString cSubKey;
COpcString cValue;
// create clsid string.
COpcString cClsid;
cClsid.FromGuid(*(pClasses[ii].pClsid));
// create version independent prog id.
COpcString cVersionIndependentProgID;
cVersionIndependentProgID += tsVendorName;
cVersionIndependentProgID += _T(".");
cVersionIndependentProgID += pClasses[ii].tsClassName;
// create prog id.
COpcString cProgID;
cProgID += cVersionIndependentProgID;
cProgID += _T(".");
cProgID += pClasses[ii].tsClassVersion;
// determine class description.
COpcString cClassDescription = pClasses[ii].tsClassDescription;
if (cClassDescription.IsEmpty())
{
cClassDescription = cProgID;
}
// set description in clsid sub key.
cSubKey = _T("CLSID\\") + cClsid;
if (!OpcRegSetValue(HKEY_CLASSES_ROOT, cSubKey, NULL, cClassDescription))
{
THROW_(hResult, SELFREG_E_CLASS);
}
// register application.
if (cAppID != GUID_NULL)
{
if (!OpcRegSetValue(HKEY_CLASSES_ROOT, cSubKey, _T("AppID"), (COpcString)cAppID))
{
THROW_(hResult, SELFREG_E_CLASS);
}
}
// set the prog id sub key.
cSubKey = _T("CLSID\\") + cClsid + _T("\\ProgID");
if (!OpcRegSetValue(HKEY_CLASSES_ROOT, cSubKey, NULL, cProgID))
{
THROW_(hResult, SELFREG_E_CLASS);
}
// set the version independent prog id sub key.
cSubKey = _T("CLSID\\") + cClsid + _T("\\VersionIndependentProgID");
if (!OpcRegSetValue(HKEY_CLASSES_ROOT, cSubKey, NULL, cVersionIndependentProgID))
{
THROW_(hResult, SELFREG_E_CLASS);
}
// set LocalServer32 or InprocServer32 sub key.
cSubKey = _T("CLSID\\");
cSubKey += cClsid;
cSubKey += (bIsExe)?_T("\\LocalServer32"):_T("\\InprocServer32");
if (!OpcRegSetValue(HKEY_CLASSES_ROOT, cSubKey, NULL, cModulePath))
{
THROW_(hResult, SELFREG_E_CLASS);
}
// set threading model.
if (!OpcRegSetValue(HKEY_CLASSES_ROOT, cSubKey, _T("ThreadingModel"), _T("Free")))
{
THROW_(hResult, SELFREG_E_CLASS);
}
// set description in prog id sub key.
cSubKey = cProgID;
if (!OpcRegSetValue(HKEY_CLASSES_ROOT, cSubKey, NULL, cClassDescription))
{
THROW_(hResult, SELFREG_E_CLASS);
}
// set clsid in prog id sub key.
cSubKey = cProgID + _T("\\CLSID");
if (!OpcRegSetValue(HKEY_CLASSES_ROOT, cSubKey, NULL, cClsid))
{
THROW_(hResult, SELFREG_E_CLASS);
}
// set description in version independent prog id sub key.
cSubKey = cVersionIndependentProgID;
if (!OpcRegSetValue(HKEY_CLASSES_ROOT, cSubKey, NULL, cClassDescription))
{
THROW_(hResult, SELFREG_E_CLASS);
}
// set clsid in version independent prog id sub key.
cSubKey = cVersionIndependentProgID + _T("\\CLSID");
if (!OpcRegSetValue(HKEY_CLASSES_ROOT, cSubKey, NULL, cClsid))
{
THROW_(hResult, SELFREG_E_CLASS);
}
// set current version prog id in version independent prog id sub key.
cSubKey = cVersionIndependentProgID + _T("\\CurVer");
if (!OpcRegSetValue(HKEY_CLASSES_ROOT, cSubKey, NULL, cProgID))
{
THROW_(hResult, SELFREG_E_CLASS);
}
}
// add categories.
for (ii = 0; pCategories[ii].pClsid != NULL; ii++)
{
RegisterClsidInCategory(*(pCategories[ii].pClsid), *(pCategories[ii].pCategory), pCategories[ii].szDescription);
}
}
CATCH
{
OpcUnregisterServer(hModule, tsVendorName, tsApplicationName, cAppID, pClasses, pCategories);
}
return hResult;
}
//============================================================================
// OpcUnregisterServer
HRESULT OpcUnregisterServer(
HINSTANCE hModule,
LPCTSTR tsVendorName,
LPCTSTR tsApplicationName,
const GUID& cAppID,
const TOpcClassTableEntry* pClasses,
const TClassCategories* pCategories
)
{
// remove categories.
for (int ii = 0; pCategories[ii].pClsid != NULL; ii++)
{
UnregisterClsidInCategory(*(pCategories[ii].pClsid), *(pCategories[ii].pCategory));
}
// remove clsid and prog id registy keys for each class.
for (ii = 0; pClasses[ii].tsClassName != NULL; ii++)
{
COpcString cSubKey;
// delete clsid sub key.
COpcString cClsid;
cClsid.FromGuid(*(pClasses[ii].pClsid));
cSubKey = _T("CLSID\\") + cClsid;
OpcRegDeleteKey(HKEY_CLASSES_ROOT, cSubKey);
// delete version independent prog id.
COpcString cVersionIndependentProgID;
cVersionIndependentProgID += tsVendorName;
cVersionIndependentProgID += _T(".");
cVersionIndependentProgID += pClasses[ii].tsClassName;
cSubKey = cVersionIndependentProgID;
OpcRegDeleteKey(HKEY_CLASSES_ROOT, cSubKey);
// delete prog id.
COpcString cProgID;
cProgID += cVersionIndependentProgID;
cProgID += _T(".");
cProgID += pClasses[ii].tsClassVersion;
cSubKey = cProgID;
OpcRegDeleteKey(HKEY_CLASSES_ROOT, cSubKey);
}
// unregister application.
COpcString cModulePath;
COpcString cModuleName;
COpcString cModuleExtension;
HRESULT hResult = GetModuleInfo(hModule, cModulePath, cModuleName, cModuleExtension);
if (SUCCEEDED(hResult))
{
UnregisterApplication(cModuleName, tsApplicationName, cAppID);
}
return S_OK;
}