[英]Including C-DLL from C++
This feels like a noob question, so if it's a dupe, please point me to the right location :)这感觉像是一个菜鸟问题,所以如果这是一个骗局,请指出我正确的位置:)
I tried including a DLL written in C into a C++ program.我尝试将用 C 编写的 DLL 包含到 C++ 程序中。 It didn't work;它没有用; gcc said gcc说
test.cpp: xxx: error: too many arguments to function. test.cpp: xxx: 错误: 函数参数太多。
Here's a minimal working example:这是一个最小的工作示例:
Wrapper for DLL functions: 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
Implementation thereof:其实施:
/* 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
Naturally, I haven't written these nor the library myself, and preferably, they should all stay untouched.自然地,我自己没有写过这些,也没有写过库,最好是,它们都应该保持原样。 I did however add the extern "C"
lines.然而,我确实添加了extern "C"
行。
Then, my main file:然后,我的主文件:
// my Main
#include <windows.h>
#include "myHeader.h"
int main(int argc, char **argv)
{
int arg = 1;
EXPORTED_functionNameP(arg);
return 0;
}
Build commands:构建命令:
gcc -I. -c -o myHeader.o myHeader.c -L. -lmyLibrary
g++ -I. -o main.exe myMain.cpp myHeader.o -L. -lmyLibrary
It works fine if I rewrite my main.cpp
into valid C and compile with gcc
instead of g++
.如果我将main.cpp
重写为有效的 C 并使用gcc
而不是g++
编译,它会正常工作。
I tried changing extern "C"
into extern "C++"
to no avail, I tried all permutations or gcc
and g++
for the two build commands, nothing.我尝试将extern "C"
更改为extern "C++"
无济于事,我为两个构建命令尝试了所有排列或gcc
和g++
,但没有。
I know it's something to do with name mangling, but I thought gcc
would take care of that when you include the extern "C"
lines...Can someone please explain what I'm missing here?我知道这与名称修改有关,但我认为当您包含extern "C"
行时, gcc
会处理这个问题……有人可以解释一下我在这里遗漏了什么吗?
In case it matters --万一重要——
Windows XP Pro (will be Win7 later on) Windows XP Pro(以后会是Win7)
(MinGW) gcc 4.6.2 (MinGW) gcc 4.6.2
The FARPROC
type is a function pointer for a function that takes no parameters. FARPROC
类型是不带参数的函数的函数指针。 You should declare EXPORTED_functionNameP
like so (replacing void
with whatever the function really returns):您应该像这样声明EXPORTED_functionNameP
(用函数真正返回的任何内容替换void
):
extern void (*EXPORTED_functionNameP)(int);
And initialize it like so (the returned value from GetProcAddress()
pretty much always needs to be cast to the correct type):并像这样初始化它(从GetProcAddress()
返回的值几乎总是需要转换为正确的类型):
EXPORTED_functionNameP = (void (*)(int)) GetProcAddress(drvsHANDLE, "originalFunctionName");
A typedef
for the funciton type might make things a bit more readable.函数类型的typedef
可能会使事情更具可读性。
After a quick Google search, it seems that FARPROC
is defined as this:在谷歌快速搜索后,似乎FARPROC
是这样定义的:
typedef int (FAR WINAPI *FARPROC)();
That is, FARPROC
is a function that returns an int
and takes no arguments.也就是说, FARPROC
是一个返回int
且不带参数的函数。 So you can't use it for any other case.所以你不能将它用于任何其他情况。
Instead declare EXPORTED_functionNameP
like this:而是像这样声明EXPORTED_functionNameP
:
extern void (*EXPORTED_functionNameP)(int);
Now EXPORTED_functionNameP
is a pointer to a function that takes an int
argument and returns no value.现在EXPORTED_functionNameP
是一个指向一个函数的指针,该函数接受一个int
参数并且不返回任何值。
There is a difference between C and C++. C 和 C++ 之间存在差异。
int (FAR WINAPI * FARPROC) ()
In C, the FARPROC declaration indicates a callback function that has an unspecified parameter list.在 C 中,FARPROC 声明指示具有未指定参数列表的回调函数。 In C++, however, the empty parameter list in the declaration indicates that a function has no parameters.但是,在 C++ 中,声明中的空参数列表表示函数没有参数。
The MSDN page on CallWindowProc explains a bit more. CallWindowProc 上的MSDN 页面解释了更多。
I know this is a very old question, but I am having exactly the same issues but in relation to writing a generic wrapper template for wrapping calls to LoadLibrary() and GetProcAddress()我知道这是一个非常古老的问题,但我遇到了完全相同的问题,但是关于编写通用包装模板来包装对 LoadLibrary() 和 GetProcAddress() 的调用
Taking https://blog.benoitblanchon.fr/getprocaddress-like-a-boss/ as inspiration, it looks like he is taking FARPROC as a kind of "void* for Windows functions" and then casting it to the correct type subsequently.以https://blog.benoitblanchon.fr/getprocaddress-like-a-boss/为灵感,他似乎将 FARPROC 视为一种“Windows 函数的 void*”,然后将其转换为正确的类型。
I needed to tweak that code a little to work for me, and reproduce it here:我需要稍微调整一下代码才能为我工作,并在此处重现它:
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;
};
So, with that helper code now available we can use it to write a wrapper class that encapsulates several functions in the Advapi32 library:因此,有了现在可用的辅助代码,我们可以使用它来编写一个包装类,该类封装了 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 is a function with the same signature as GetWindowsDirectoryA but which doesn't exist in Advapi32. bogusFunction 是一个与 GetWindowsDirectoryA 具有相同签名但在 Advapi32 中不存在的函数。 This is what I was trying to achieve - graceful fallback on an older OS which might not have a certain function.这就是我想要实现的 - 在可能没有特定功能的旧操作系统上优雅回退。
So, finally a test app...所以,最后一个测试应用程序......
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;
}
}
Output:输出:
Username: TestAccount
opened SC Manager
Function not supported
Note: This was compiled as a Windows 32-bit console application with MBCS rather than Unicode, under VS2019 with the VS2015_XP toolset, since that is what I am needing to target (don't ask).注意:这是在 VS2019 下使用 VS2015_XP 工具集编译为带有 MBCS 而不是 Unicode 的 Windows 32 位控制台应用程序,因为这是我需要的目标(不要问)。
FARPROC is defined as FARPROC 定义为
typedef int (FAR WINAPI *FARPROC)();
When you pass an additional argument although the argument list of the prototype is empty you get the error.当你传递一个额外的参数时,尽管原型的参数列表是空的,你会得到错误。
You need a proper prototype definition for PORTED_functionNameP
and cas the result from GetProcAddress
to that type in your GetDLLPopinters
functions.您需要PORTED_functionNameP
的正确原型定义, PORTED_functionNameP
GetProcAddress
的结果转换为GetDLLPopinters
函数中的该类型。
It is because of FARPROC is defined as:这是因为 FARPROC 被定义为:
int (FAR WINAPI * FARPROC) ()
So you can not pass any parameters to such function in C++.所以你不能在 C++ 中将任何参数传递给这样的函数。 For fix it you should define EXPORTED_functionNameP
as pointer to function with equal semantics as defined in DLL-library.为了修复它,您应该将EXPORTED_functionNameP
定义为指向具有 DLL 库中定义的相同语义的函数的指针。 For example:例如:
typedef (void* EXPORTED_functionNameP)(int value);
EXPORTED_functionNameP ExportedFns;
...
ExportedFns = GetProcAddress(drvsHANDLE, "originalFunctionName");
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.