簡體   English   中英

從C ++調用Win32 DLL

[英]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);

無需亂搞LoadLibraryGetProcAddress等。

如果您想遵循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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM