从C ++调用Win32 DLL

时间:2013-08-07 09:44:45

标签: c++ winapi dll

我是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??
  }
}

2 个答案:

答案 0 :(得分: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等等。

答案 1 :(得分:3)

如果您想要遵循LoadLibrary / GetProcAddress / FreeLibrary方法,请考虑以下“代码路径”(请注意,如果您有DLL公共头文件和相应的。 lib文件,只有#include公共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 *);

然后使用 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 pattern,并使用析构函数定义一个自动释放DLL的类(这简化了管理库加载/释放部件的代码) )。
e.g。

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),同样在错误路径的情况下