包括来自C++的 C-DLL
Including C-DLL from C++
这感觉像是一个菜鸟问题,所以如果这是一个骗局,请指出我正确的位置:)
我尝试将用 C 编写的 DLL 包含在C++程序中。它没有用;海湾合作委员会 说
测试.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
当然,我自己也没有写过这些,图书馆也没有写过,最好,它们都应该保持不变。但是,我确实添加了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++
两个构建命令,什么都没有。
我知道这与名称重整有关,但我认为当您包含extern "C"
行时,gcc
会解决这个问题......有人可以解释一下我在这里错过了什么吗?
万一重要的话——
Windows XP Pro(稍后将是Win7(
(MinGW( gcc 4.6.2
这是一个非常古老的问题,但我遇到了完全相同的问题,但与编写通用包装器模板以包装对 LoadLibrary(( 和 GetProcAddress(( 的调用有关
以 https://blog.benoitblanchon.fr/getprocaddress-like-a-boss/为灵感,看起来他正在将 FARPROC 作为一种"Windows 函数的空白*",然后将其转换为正确的类型。
我需要稍微调整一下该代码才能为我工作,并在此处重现它:
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"))
{
getUserName = m_dll["GetUserNameA"];
openSCManager = m_dll["OpenSCManagerA"];
bogusFunction = m_dll["BogusFunctionThatDoesNotExist"];
}
decltype(GetUserNameA)* getUserName;
decltype(OpenSCManagerA)* openSCManager;
decltype(GetWindowsDirectoryA)* bogusFunction;
private:
DllHelper m_dll;
};
bogusFunction是一个与GetWindowsDirectoryA具有相同签名的函数,但在Advapi32中不存在。这就是我想要实现的目标 - 在可能没有特定功能的旧操作系统上优雅地回退。
所以,终于有一个测试应用程序...
int main()
{
Advapi32 advapi32;
auto func1 = advapi32.getUserName;
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
注意:这是在VS2019下编译为具有MBCS而不是Unicode的Windows 32位控制台应用程序,该工具集VS2015_XP,因为这是我需要的目标(不要问(。
FARPROC
类型是不带参数的函数的函数指针。 你应该像这样声明EXPORTED_functionNameP
(用函数真正返回的任何内容替换void
(:
extern void (*EXPORTED_functionNameP)(int);
并像这样初始化它(GetProcAddress()
返回的值几乎总是需要转换为正确的类型(:
EXPORTED_functionNameP = (void (*)(int)) GetProcAddress(drvsHANDLE, "originalFunctionName");
函数类型的typedef
可能会使事情更具可读性。
C 和 C++ 之间是有区别的。
int (FAR WINAPI * FARPROC) ()
在 C 语言中,FARPROC 声明指示具有未指定参数列表的回调函数。但是,在C++中,声明中的空参数列表指示函数没有参数。
CallWindowProc 上的 MSDN 页面解释了更多内容。
经过快速的谷歌搜索,似乎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
,并在GetDLLPopinters
函数中将GetProcAddress
到该类型的结果。
- 挂起和取消挂起一个文件DLL
- std::threads可以从Windows DLL中的全局变量创建/销毁吗?
- 导入库可以跨dll版本工作吗
- 从C++dll访问C#中的一行主要参数
- 链接到自行创建的dll失败
- 为什么使用 P/Invoke 调用 dll 时,某些计算机中的 LoadLibrary 失败?
- 在调用FreeLibrary后,释放动态链接到具有相同版本的CRT堆的DLL的内存
- 如何指定我希望我的LIB链接到的DLL文件?-Visual Studio 2019
- 如何将图像传输到c++(dll)中的缓冲区,然后在c#的缓冲区中读/写
- C++:将外部库链接到dll库
- 在 Windows 上,是否可以让 dll 在不使用 PATH 环境变量的情况下在另一个文件夹中查找依赖项?
- 不同的Visual Studio版本中缺少.dll
- 从DLL中删除类的实例
- 如何包装第三方DLL在R中使用
- 使用c#访问c++dll中带有char*参数的函数时发生AccessViolationException
- 系统.将数组移交给c#中动态加载的c++DLL时发生AccessViolationException
- 为什么导入Mixed native/CLR lib.dll的本机C++应用程序没有在Mixed lib.dll中的外部变
- 当我使用 C++ 中的 C# dll 来使用 Selenium 时,存在异常处理问题
- Python ctypes:不会按预期加载 dll
- 在 C++/CLI 中将 .NET 事件从一个 DLL 引发到另一个 DLL