我是DLL世界的新手。我得到了一个Win32 DLL,它有很多功能。需要从C ++中调用这些DLL函数
我想调用CreateNewScanner
来创建一个新的扫描程序对象,并用C ++获取结果。
DLL中提到的函数是:
BOOL CreateNewScanner(NewScanner *newScan);
和NewScanner
是struct
,如下所示,
// Structure NewScanner is defined in "common.h" .
typedef struct{
BYTE host_no; // <- host_no =0
LONG time; // <- command timeout (in seconds)
BYTE status; // -> Host adapter status
HANDLE obj; // -> Object handle for the scanner
}NewScanner;
我该如何调用此功能?从C ++开始,这就是我所管理的,
#include <iostream>
#include <windows.h>
using namespace std;
int main(){
HINSTANCE hInstance;
if(!(hInstance=LoadLibrary("WinScanner.dll"))){
cout << "could not load library" << endl;
}
/* get pointer to the function in the dll*/
FARPROC handle = GetProcAddress(HMODULE(hInstance), "CreateNewScanner");
if(!handle){
// Handle the error
FreeLibrary(hInstance);
return "-1";
}else{
// Call the function
//How to call here??
}
}
答案 0 :(得分:5)
首先,return "-1"
并不好。您应该返回一个整数。所以你肯定是return -1
。
现在回答这个问题。不是将函数指针声明为FARPROC
,而是将其声明为函数指针类型更容易。
typedef BOOL (*CreateNewScannerProc)(NewScanner*);
然后像这样调用GetProcAddress:
HMODULE hlib = LoadLibrary(...);
// LoadLibrary returns HMODULE and not HINSTANCE
// check hlib for NULL
CreateNewScannerProc CreateNewScanner =
(CreateNewScannerProc) GetProcAddress(hlib, "CreateNewScanner");
if (CreateNewScanner == NULL)
// handle error
// now we can call the function
NewScanner newScan;
BOOL retval = CreateNewScanner(&newScan);
说完所有这些之后,通常一个库会带有一个头文件(你显然应该包含它)和一个用于加载时链接的.lib文件。确保将.lib文件传递给链接器,您只需执行此操作:
#include "NameOfTheHeaderFileGoesHere.h"
....
NewScanner newScan;
BOOL retval = CreateNewScanner(&newScan);
无需使用LoadLibrary
,GetProcAddress
等等。
答案 1 :(得分:3)
如果您想要遵循LoadLibrary
/ GetProcAddress
/ FreeLibrary
方法,请考虑以下“代码路径”(请注意,如果您有DLL公共头文件和相应的。 lib文件,只有#include
公共DLL头,并与.lib文件链接,只需使用其原型在DLL头中定义的函数,就像使用从C ++代码调用的普通C函数一样。
为指向从DLL导出的函数的指针定义typedef
请注意,指定了调用约定(通常,带有纯C接口的Win32 DLL使用__stdcall
calling convention):
//
// Prototype of the DLL function, with *calling convention* specified
// (usually it's __stdcall for DLL with pure-C interface).
//
typedef BOOL (__stdcall *CreateNewScannerPtr)(NewScanner *);
然后使用 LoadLibrary
尝试加载DLL :
//
// Try loading the DLL.
//
HMODULE hDll = LoadLibrary(L"WinScanner.dll"); // <--- Note the use of L"..." for Unicode
if (! hDll)
{
.... error
}
请注意,DLL的文件名是 Unicode字符串(请注意L"..."
装饰)。通常,您应该在现代C ++ / Win32代码中使用Unicode。
然后你可以使用 GetProcAddress
尝试获取函数指针:
//
// Try getting the pointer to CreateNewScanner DLL function.
//
auto pCreateNewScanner = reinterpret_cast<CreateNewScannerPtr>
(
GetProcAddress
(
hDll, // DLL handle
"CreateNewScanner" // Function name
)
);
if (! pCreateNewScanner)
{
.... error
// Release the DLL
FreeLibrary(hDll);
// Avoid dangling references
hDll = nullptr;
}
请注意,由于您使用的是C ++,因此最好使用 C ++ - 样式转换(在本例中为reinterpret_cast<>
),而不是旧的C风格转换。
此外,由于函数指针的类型在reinterpret_cast
中指定,因此在语句的开头重复它是没用的,所以新的C ++ 11的关键字auto
可以使用。
您可以使用返回的函数指针来调用DLL函数:
BOOL retCode = pCreateNewScanner( .... );
// Note: some other common prefix used in this case is "pfn"
// as "pointer to function" (e.g. pfnCreateNewScanner).
使用完DLL后,您可以发布,拨打 FreeLibrary
:
//
// Release the DLL
//
FreeLibrary(hDll);
hDll = nullptr;
此外,请注意您可以使用C++ RAII pattern,并使用析构函数定义一个自动释放DLL的类(这简化了管理库加载/释放部件的代码) )。
e.g。
class RaiiDll
{
public:
// Load the DLL.
explicit RaiiDll(const std::wstring& filename) // may also provide an overload
// with (const wchar_t*)
{
m_hDll = ::LoadLibrary(filename.c_str());
if (! m_hDll)
{
// Error
throw std::runtime_error("Can't load the DLL - LoadLibrary() failed.");
// .... or use some other exception...
}
}
// Safely and automatically release the DLL.
~RaiiDll()
{
if (m_hDll)
{
::FreeLibrary(m_hDll);
m_hDll = nullptr;
}
}
// Get DLL module handle.
HMODULE Get() const
{
return m_hDll;
}
private:
HMODULE m_hDll; // DLL instance handle
//
// Ban copy (if compiler supports new C++11 =delete, use it)
//
private:
RaiiDll( RaiiDll & );
RaiiDll & operator=( RaiiDll & );
};
然后,在某些代码块中,您可以:
{
// Load the library (throws on error).
RaiiDll scannerDll(L"WinScanner.dll");
// Get DLL function pointer
auto pCreateNewScanner = reinterpret_cast<CreateNewScannerPtr>(
GetProcAddress(scannerDll.Get(), "CreateNewScanner"));
if (! pCreateNewScanner)
{
.... error.
}
.... use the function
} // <--- DLL automatically released thanks to RaiiDll destructor!!!
注意代码简化,感谢自动调用RaiiDll
destrutor(以及FreeLibrary
),同样在错误路径的情况下