Calling Win32 DLL from C++

Calling Win32 DLL from C++

本文关键字:C++ from DLL Win32 Calling      更新时间:2023-10-16

我是DLL世界的新手。我得到了一个Win32 DLL,它有很多功能。需要从C++调用这些DLL函数

我想调用CreateNewScanner,它创建一个新的scanner对象并在C++中获得结果。DLL中提到的函数是:

BOOL CreateNewScanner(NewScanner *newScan);

并且NewScannerstruct,如下所述,

// 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
请注意,调用约定是指定的(通常,具有pure-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)的自动调用,代码是如何简化的,也是在错误路径的情况下。