2

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

我想调用CreateNewScannerwhich 创建一个新的扫描仪对象并在 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??
  }
}
4

2 回答 2

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);

没有必要乱来LoadLibraryGetProcAddress等等。

于 2013-08-07T09:52:15.177 回答
3

如果你想遵循LoadLibrary//的方法GetProcAddressFreeLibrary考虑下面的“代码路径”(注意,如果你有 DLL 公共头文件和对应的 .lib 文件,只有#include公共 DLL 头文件,并与 .lib 文件链接,并且只需使用其原型在 DLL 头文件中定义的函数,就像使用从 C++ 代码调用的普通 C 函数一样)。

定义一个typedef指向从 DLL 导出的函数的指针。
请注意,指定了调用约定(通常,具有纯 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 *);

然后您尝试使用以下方法加载 DLLLoadLibrary

//
// 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是在 中指定的,在语句开头重复也没用,所以auto可以使用new C++11的关键字。

您可以使用返回的函数指针来调用 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!!!

请注意,由于自动调用destrutor(等等),代码是如何被简化的,在错误路径的情况下也是如此。RaiiDllFreeLibrary

于 2013-08-07T10:43:43.523 回答