mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-23 02:00:00 +08:00
718 lines
20 KiB
C++
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;
|
|
}
|