这感觉像是一个菜鸟问题,所以如果是骗子,请指向正确的位置:)
我尝试将用C编写的DLL包含到C ++程序中。它没有用; gcc说
test.cpp:xxx:错误:太多参数无法使用。
这是一个最小的工作示例:
DLL函数包装器:
/* myWrapper.h */
#ifndef _MYWRAPPER_H
#define _MYWRAPPER_H
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif
extern FARPROC EXPORTED_functionNameP;
int GetDLLpointers();
#ifdef __cplusplus
}
#endif
#endif
其实现:
/* myWrapper.c */
#include <windows.h>
#include "myHeader.h"
#ifdef __cplusplus
extern "C" {
#endif
HINSTANCE drvsHANDLE;
extern FARPROC EXPORTED_functionNameP;
int GetDLLpointers()
{
static int result;
drvsHANDLE = LoadLibrary("myLibrary.dll");
if (drvsHANDLE == NULL) return (result=0);
EXPORTED_functionNameP = GetProcAddress(
drvsHANDLE, "originalFunctionName");
if (EXPORTED_functionNameP == NULL) return (result = 0);
return (result = 1);
}
#ifdef __cplusplus
}
#endif
[自然,我也没有自己写这些,也不是我的库,最好它们都保持不变。我did但是添加extern "C"
行。
然后,我的主文件:
// my Main
#include <windows.h>
#include "myHeader.h"
int main(int argc, char **argv)
{
int arg = 1;
EXPORTED_functionNameP(arg);
return 0;
}
构建命令:
gcc -I. -c -o myHeader.o myHeader.c -L. -lmyLibrary
g++ -I. -o main.exe myMain.cpp myHeader.o -L. -lmyLibrary
如果我将main.cpp
重写为有效的C并使用gcc
而不是g++
进行编译,则效果很好。
我尝试将extern "C"
更改为extern "C++"
无济于事,我尝试了所有排列或两个构建命令的gcc
和g++
,什么都没有。
[我知道这与名称修改有关,但是当您包含gcc
行时,我认为extern "C"
会解决这个问题……有人可以解释一下我在这里缺少的内容吗?
如果有关系-
Windows XP Pro(稍后将是Win7)
((MinGW)gcc 4.6.2
C和C ++之间有区别。
int (FAR WINAPI * FARPROC) ()
在C中,FARPROC声明指示具有未指定参数列表的回调函数。但是,在C ++中,声明中的空参数列表指示函数没有参数。
FARPROC
类型是不带参数的函数的函数指针。您应该这样声明EXPORTED_functionNameP
(用函数实际返回的值替换void
):
extern void (*EXPORTED_functionNameP)(int);
并像这样初始化它(GetProcAddress()
的返回值几乎总是需要转换为正确的类型:]
EXPORTED_functionNameP = (void (*)(int)) GetProcAddress(drvsHANDLE, "originalFunctionName");
对于函子类型的typedef
可能会使事情更具可读性。
经过Google的快速搜索后,似乎FARPROC
定义如下:
typedef int (FAR WINAPI *FARPROC)();
即FARPROC
是一个返回int
且不带参数的函数。因此,不能在其他任何情况下使用它。
而不是像这样声明EXPORTED_functionNameP
:
extern void (*EXPORTED_functionNameP)(int);
现在EXPORTED_functionNameP
是指向带有int
自变量但不返回值的函数的指针。
由于FARPROC被定义为:
int (FAR WINAPI * FARPROC) ()
因此,您不能在C ++中将任何参数传递给此类函数。为了进行修复,您应该将EXPORTED_functionNameP
定义为具有与DLL库中定义的相同语义的函数的指针。例如:
typedef (void* EXPORTED_functionNameP)(int value);
EXPORTED_functionNameP ExportedFns;
...
ExportedFns = GetProcAddress(drvsHANDLE, "originalFunctionName");
FARPROC定义为
typedef int (FAR WINAPI *FARPROC)();
尽管原型的参数列表为空,但您传递了一个附加参数时,则会出现错误。
您需要为PORTED_functionNameP
提供适当的原型定义,并将GetProcAddress
的结果与GetDLLPopinters
函数中的类型关联。
我知道这是一个非常老的问题,但是我遇到了完全相同的问题,但是与编写用于包装对LoadLibrary()和GetProcAddress()的调用的通用包装器模板有关。
以https://blog.benoitblanchon.fr/getprocaddress-like-a-boss/为灵感,他似乎将FARPROC视为一种“函数的void *”,然后将其强制转换为正确的类型。
我需要稍微修改一下代码才能为我工作,并在此处复制它:
class ProcPtr { public: explicit ProcPtr(FARPROC ptr) : m_ptr(ptr) {} template <typename T> operator T* () const { return reinterpret_cast<T*>(m_ptr); } private: FARPROC m_ptr; }; class DllHelper { public: explicit DllHelper(LPCTSTR filename) :m_module(LoadLibrary(filename)) {} ~DllHelper() { FreeLibrary(m_module); } ProcPtr operator[](LPCSTR proc_name) const { return ProcPtr(::GetProcAddress(m_module, proc_name)); } private: HMODULE m_module; };
因此,有了该辅助代码,我们可以使用它编写一个包装类,该类将Advapi32库中的几个函数封装在一起:
class Advapi32 { public: Advapi32() : m_dll(TEXT("Advapi32")) { getUserNameA = m_dll["GetUserNameA"]; openSCManager = m_dll["OpenSCManagerA"]; bogusFunction = m_dll["BogusFunctionThatDoesNotExist"]; } decltype(GetUserNameA)* getUserNameA; decltype(OpenSCManagerA)* openSCManager; decltype(GetWindowsDirectoryA)* bogusFunction; private: DllHelper m_dll; };
bogusFunction是一个具有与GetWindowsDirectoryA相同的签名的函数,但是Advapi32中不存在。这就是我想要达到的目标-在旧版OS上进行优美的后备。
所以,最终是一个测试应用程序...
int main() { Advapi32 advapi32; auto func1 = advapi32.getUserNameA; if (func1) { TCHAR infoBuf[256]; DWORD bufCharCount = sizeof(infoBuf); if (func1(infoBuf, &bufCharCount)) { std::cout << "Username: " << infoBuf << std::endl; } } auto func2 = advapi32.openSCManager; if (func2) { SC_HANDLE handle = func2(NULL, NULL, SC_MANAGER_CONNECT); if (handle) { std::cout << "opened SC Manager" << std::endl; } } auto func3 = advapi32.bogusFunction; if (func3) { std::cerr << "This should not happen!" << std::endl; } else { std::cout << "Function not supported" << std::endl; } }
输出:
Username: TestAccount opened SC Manager Function not supported
[注意:这是使用VS2015_XP工具集在VS2019下使用MBCS而不是Unicode编译为Windows 32位控制台应用程序,因为这是我需要定位的(不要问)。