【问题标题】:Calling Win32 DLL from C++从 C++ 调用 Win32 DLL
【发布时间】:2013-08-07 09:44:45
【问题描述】:

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

我想调用CreateNewScanner,它会创建一个新的扫描器对象并在 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??
  }
}

【问题讨论】:

  • 我已经编辑了问题,只是添加了更好的文本格式。

标签: c++ winapi dll


【解决方案1】:

首先,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等等。

【讨论】:

  • 注意,我使用了 C 风格转换,因为我不确定提问者是否已经为 C++ 风格转换做好了准备。
【解决方案2】:

如果你想遵循LoadLibrary/GetProcAddress/FreeLibrary的方法,考虑下面的“代码路径”(注意如果你有DLL公共头文件和对应的.lib文件,只需@987654326 @公共 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 *);

然后您尝试加载 DLL 使用 LoadLibrary

//
// 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&lt;&gt;),而不是旧的 C 风格的强制转换。
而且,由于函数指针的type是在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(这简化了管理库加载/释放部分的代码)。
例如

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)的自动调用,在错误路径的情况下也是如此。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-25
    • 1970-01-01
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多