[英]Calling Win32 DLL from C++
我是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??
}
}
首先, 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
等。
如果您想遵循LoadLibrary
/ GetProcAddress
/ FreeLibrary
方法,請考慮以下“代碼路徑”(請注意,如果您有DLL公共頭文件和相應的.lib文件,只需#include
公共DLL頭,並鏈接到.lib文件,只需使用其原型在DLL頭中定義的函數,就像使用從C ++代碼調用的普通C函數一樣。
為指向從DLL導出的函數的指針定義typedef
。
請注意,指定了調用約定 (通常,帶有純C接口的Win32 DLL使用__stdcall
調用約定 ):
//
// 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模式 ,並使用析構函數定義一個自動釋放DLL的類(這簡化了管理庫加載/釋放部分的代碼)。
例如
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
),代碼如何被簡化 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.