文章目录
- VS - regsvr32.exe的官方工程
- 概述
- 笔记
- 官方原版实现
- 自己封装一个函数来干活(注册/反注册 COM DLL)
- END
VS - regsvr32.exe的官方工程
概述
如果是要使用COM DLL, 必须先注册。
一般手工注册就要调用regsvr32.exe xx.dll
但是控制的不够细,且一般来说,也就只能通过安装程序来注册COM DLL.
如果是一个绿色版程序集合(e.g. 解压版的程序包),启动主程序后,先判断是否能正常操作COM DLL,如果不能,则自己先在程序实现里面,将解压包内自带的COM DLL先注册一下,再使用COM DLL。
如果是这种场景的话,用系统自带的regsvr32.exe来注册COM DLL, 显然不能达到目的。
即使加 /s 参数(静默),控制的也不够细。
在看资料,里面说道,regsvr32.exe 实际上就是执行COM DLL中的导出函数(DllRegisterServer/DllUnregisterServer)来实现COM DLL的注册和反注册。
就想看一下regsvr32.exe的实现。
翻硬盘时,居然看到微软官方开源库有这个工程的源码:P
那就可以直接看源码了,不用IDA了。
工程位置 - D:\3rd_prj\vs\VCSamples\VC2008Samples\MFC\controls\regsvr
微软官方开源库地址 - https://github.com/microsoft/VCSamples.git
笔记
官方原版实现
// regsvr.cpp : Program to invoke OLE self-registration on a DLL.
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include <windows.h>
#include <ole2.h>
#include <tchar.h>
#include <malloc.h>
#include <stdio.h>
#include "resource.h"
#define FAIL_ARGS 1
#define FAIL_OLE 2
#define FAIL_LOAD 3
#define FAIL_ENTRY 4
#define FAIL_REG 5
const TCHAR _szAppName[] = _T("RegSvr32");
const char _szDllRegSvr[] = "DllRegisterServer";
const char _szDllUnregSvr[] = "DllUnregisterServer";
HINSTANCE _hInstance;
BOOL _bSilent;
BOOL _bConsole;
#define SafePutts(string) ((stdout >= 0) ? _putts(string) : 0)
void
FormatString2(
LPTSTR lpszOut,
int nOutSize,
LPCTSTR lpszFormat,
LPCTSTR lpsz1,
LPCTSTR lpsz2
)
{
LPCTSTR pchSrc = lpszFormat;
LPTSTR pchDest = lpszOut;
while (*pchSrc != '\0') {
if (pchSrc[0] == '%' && (pchSrc[1] >= '1' && pchSrc[1] <= '2')) {
_tcscpy_s(pchDest, nOutSize, (LPCTSTR)(pchSrc[1] == '1' ? lpsz1 : lpsz2));
pchDest += lstrlen(pchDest);
pchSrc += 2;
} else {
if (_istlead(*pchSrc))
*pchDest++ = *pchSrc++; // copy first of 2 bytes
*pchDest++ = *pchSrc++;
}
}
*pchDest = '\0';
}
#define MAX_STRING 1024
void
DisplayMessage(
UINT ids,
LPCTSTR pszArg1 = NULL,
LPCTSTR pszArg2 = NULL,
BOOL bUsage = FALSE,
BOOL bInfo = FALSE
)
{
if (_bSilent && !_bConsole)
return;
TCHAR szFmt[MAX_STRING];
LoadString(_hInstance, ids, szFmt, MAX_STRING);
TCHAR szText[MAX_STRING];
FormatString2(szText, MAX_STRING, szFmt, pszArg1, pszArg2);
if (bUsage) {
int cch = (int)_tcslen(szText);
LoadString(_hInstance, IDS_USAGE, szText + cch, MAX_STRING - cch);
}
if (! _bSilent)
MessageBox(NULL, szText, _szAppName,
MB_TASKMODAL | (bInfo ? MB_ICONINFORMATION : MB_ICONEXCLAMATION));
if (_bConsole) {
TCHAR szMessage[MAX_STRING];
FormatString2(szMessage, MAX_STRING, _T("%1: %2\n"), _szAppName, szText);
SafePutts(szMessage);
}
}
inline void
Usage(
UINT ids,
LPCTSTR pszArg1 = NULL,
LPCTSTR pszArg2 = NULL
)
{
DisplayMessage(ids, pszArg1, pszArg2, TRUE);
}
inline void
Info(
UINT ids,
LPCTSTR pszArg1 = NULL,
LPCTSTR pszArg2 = NULL
)
{
DisplayMessage(ids, pszArg1, pszArg2, FALSE, TRUE);
}
#ifdef _UNICODE
int wmain(int argc, WCHAR *argv[])
#else // !_UNICODE
int main(int argc, char *argv[])
#endif
{
int iReturn = 0;
HRESULT (STDAPICALLTYPE * lpDllEntryPoint)(void);
BOOL bVisualC = FALSE;
BOOL bUnregister = FALSE;
LPCSTR pszDllEntryPoint = _szDllRegSvr;
LPTSTR ptszDllEntryPoint = NULL;
LPCTSTR pszDllName = NULL;
LPCTSTR pszTok;
size_t EntryPointSize = 0;
_hInstance = ::GetModuleHandle(NULL);
// Parse command line arguments.
int iTok;
for (iTok = 1; iTok < argc; iTok++) {
pszTok = argv[iTok];
if ((pszTok[0] == '-') || (pszTok[0] == '/')) {
switch (pszTok[1]) {
case 'v':
case 'V':
bVisualC = TRUE;
break;
case 's':
case 'S':
_bSilent = TRUE;
break;
case 'u':
case 'U':
bUnregister = TRUE;
pszDllEntryPoint = _szDllUnregSvr;
break;
case 'c':
case 'C':
_bConsole = TRUE;
break;
default:
Usage(IDS_UNRECOGNIZEDFLAG, pszTok);
return FAIL_ARGS;
}
} else {
if (pszDllName == NULL) {
pszDllName = pszTok;
break;
} else {
Usage(IDS_EXTRAARGUMENT, pszTok);
return FAIL_ARGS;
}
}
}
if (pszDllEntryPoint != NULL) {
EntryPointSize = (1 + strlen(pszDllEntryPoint)) * (sizeof(TCHAR));
ptszDllEntryPoint = (TCHAR *)_malloca(EntryPointSize); // _malloca may allocate memory on the heap, so we need to call _freea to clean the heap if used
#ifdef _UNICODE
swprintf_s(ptszDllEntryPoint, EntryPointSize, _T("%hs"), pszDllEntryPoint);
#else // !_UNICODE
strcpy_s(ptszDllEntryPoint, EntryPointSize, pszDllEntryPoint);
#endif
}
if (pszDllName == NULL) {
if (bVisualC)
DisplayMessage(IDS_NOPROJECT);
else
Usage(IDS_NODLLNAME);
_freea(ptszDllEntryPoint);
return FAIL_ARGS;
}
// Initialize OLE.
if (FAILED(OleInitialize(NULL))) {
DisplayMessage(IDS_OLEINITFAILED);
_freea(ptszDllEntryPoint);
return FAIL_OLE;
}
SetErrorMode(SEM_FAILCRITICALERRORS); // Make sure LoadLib fails.
for (; iTok < argc; iTok++) {
pszDllName = argv[iTok];
// Load the library.
HINSTANCE hLib = LoadLibraryEx(pszDllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (hLib < (HINSTANCE)HINSTANCE_ERROR) {
TCHAR szError[12];
_stprintf_s(szError, 12, _T("0x%08lx"), GetLastError());
DisplayMessage(IDS_LOADLIBFAILED, pszDllName, szError);
iReturn = FAIL_LOAD;
goto CleanupOle;
}
// Find the entry point.
(FARPROC&)lpDllEntryPoint = GetProcAddress(hLib, pszDllEntryPoint);
if (lpDllEntryPoint == NULL) {
TCHAR szExt[_MAX_EXT];
_tsplitpath_s(pszDllName, NULL, 0, NULL, 0, NULL, 0, szExt, _MAX_EXT);
if ((_tcsicmp(szExt, _T(".dll")) != 0) && (_tcsicmp(szExt, _T(".ocx")) != 0))
DisplayMessage(IDS_NOTDLLOROCX, pszDllName, ptszDllEntryPoint);
else
DisplayMessage(IDS_NOENTRYPOINT, pszDllName, ptszDllEntryPoint);
iReturn = FAIL_ENTRY;
goto CleanupLibrary;
}
// Call the entry point.
if (FAILED((*lpDllEntryPoint)())) {
DisplayMessage(IDS_CALLFAILED, ptszDllEntryPoint, pszDllName);
iReturn = FAIL_REG;
goto CleanupLibrary;
}
Info(IDS_CALLSUCCEEDED, ptszDllEntryPoint, pszDllName);
CleanupLibrary:
FreeLibrary(hLib);
}
CleanupOle:
OleUninitialize();
_freea(ptszDllEntryPoint);
return iReturn;
}
自己封装一个函数来干活(注册/反注册 COM DLL)
//! \file myRegsvr32.cpp
//! \brief 自己封装一个可以可以操作COM DLL注册/反注册的函数
//! \ref D:\3rd_prj\vs\VCSamples\VC2008Samples\MFC\controls\regsvr
//! \note https://github.com/microsoft/VCSamples.git
//! \note exp prj env = vs2019 vc++ unicode x64 console
#include <Windows.h>
#include <iostream>
#include <assert.h>
bool com_dll_Reg_or_unReg(bool isReg, const TCHAR* pszComDllPathName);
int wmain(int argc, WCHAR* argv[])
// int main(int argc, TCHAR** argv)
{
bool b_rc = false;
do {
// argv[1] is COM DLL's path name
if (2 != argc)
{
break;
}
// un register com dll
b_rc = com_dll_Reg_or_unReg(false, argv[1]);
assert(b_rc);
// register com dll
b_rc = com_dll_Reg_or_unReg(true, argv[1]);
assert(b_rc);
} while (false);
return 0;
}
bool com_dll_Reg_or_unReg(bool isReg, const TCHAR* pszComDllPathName)
{
bool b_rc = false;
bool b_com_init_ok = false;
HRESULT hr = S_OK;
HINSTANCE hLib = NULL;
HRESULT(STDAPICALLTYPE * lpDllEntryPoint)(void);
const CHAR* pszDllRegSvr = "DllRegisterServer";
const CHAR* pszDllUnregSvr = "DllUnregisterServer";
const CHAR* pszComDLLApiName = NULL;
do {
if (NULL == pszComDllPathName)
{
break;
}
pszComDLLApiName = (isReg ? pszDllRegSvr : pszDllUnregSvr);
hr = OleInitialize(NULL);
if (FAILED(hr)) {
break;
}
b_com_init_ok = true;
SetErrorMode(SEM_FAILCRITICALERRORS); // Make sure LoadLib fails.
// Load the library.
hLib = LoadLibraryEx(pszComDllPathName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (hLib < (HINSTANCE)HINSTANCE_ERROR) {
break;
}
(FARPROC&)lpDllEntryPoint = GetProcAddress(hLib, pszComDLLApiName);
if (NULL == lpDllEntryPoint) {
break;
}
hr = (*lpDllEntryPoint)();
if (FAILED(hr)) {
break;
}
b_rc = true;
} while (false);
if (NULL != hLib)
{
FreeLibrary(hLib);
hLib = NULL;
}
if (b_com_init_ok)
{
b_com_init_ok = false;
OleUninitialize();
}
return b_rc;
}