簡體   English   中英

包括來自 C++ 的 C-DLL

[英]Including C-DLL from C++

這感覺像是一個菜鳥問題,所以如果這是一個騙局,請指出我正確的位置:)

我嘗試將用 C 編寫的 DLL 包含到 C++ 程序中。 它沒有用; gcc說

test.cpp: xxx: 錯誤: 函數參數太多。

這是一個最小的工作示例:

DLL 函數的包裝器:

/* myWrapper.h */

#ifndef _MYWRAPPER_H
#define _MYWRAPPER_H
#include <windows.h>

#ifdef __cplusplus
extern "C" {
#endif

extern  FARPROC   EXPORTED_functionNameP;

int GetDLLpointers();

#ifdef __cplusplus
}
#endif

#endif

其實施:

/* myWrapper.c */
#include <windows.h>
#include "myHeader.h"

#ifdef __cplusplus
extern "C" {
#endif

HINSTANCE drvsHANDLE;

extern  FARPROC   EXPORTED_functionNameP;

int GetDLLpointers()
{
    static int result;

    drvsHANDLE = LoadLibrary("myLibrary.dll");
    if (drvsHANDLE == NULL) return (result=0);

    EXPORTED_functionNameP = GetProcAddress(
        drvsHANDLE, "originalFunctionName");    
    if (EXPORTED_functionNameP == NULL) return (result = 0);

    return (result = 1);
}

#ifdef __cplusplus
}
#endif

自然地,我自己沒有寫過這些,也沒有寫過庫,最好是,它們都應該保持原樣。 然而,我確實添加了extern "C"行。

然后,我的主文件:

// my Main
#include <windows.h>
#include "myHeader.h"

int main(int argc, char **argv)
{
    int arg = 1;
    EXPORTED_functionNameP(arg);

    return 0;
}

構建命令:

gcc -I. -c -o myHeader.o myHeader.c -L. -lmyLibrary
g++ -I. -o main.exe myMain.cpp myHeader.o -L. -lmyLibrary

如果我將main.cpp重寫為有效的 C 並使用gcc而不是g++編譯,它會正常工作。

我嘗試將extern "C"更改為extern "C++"無濟於事,我為兩個構建命令嘗試了所有排列或gccg++ ,但沒有。

我知道這與名稱修改有關,但我認為當您包含extern "C"行時, gcc會處理這個問題……有人可以解釋一下我在這里遺漏了什么嗎?

萬一重要——

Windows XP Pro(以后會是Win7)

(MinGW) gcc 4.6.2

FARPROC類型是不帶參數的函數的函數指針。 您應該像這樣聲明EXPORTED_functionNameP (用函數真正返回的任何內容替換void ):

extern void (*EXPORTED_functionNameP)(int);

並像這樣初始化它(從GetProcAddress()返回的值幾乎總是需要轉換為正確的類型):

EXPORTED_functionNameP = (void (*)(int)) GetProcAddress(drvsHANDLE, "originalFunctionName");    

函數類型的typedef可能會使事情更具可讀性。

在谷歌快速搜索后,似乎FARPROC是這樣定義的:

typedef int (FAR WINAPI *FARPROC)();

也就是說, FARPROC是一個返回int且不帶參數的函數。 所以你不能將它用於任何其他情況。

而是像這樣聲明EXPORTED_functionNameP

extern void (*EXPORTED_functionNameP)(int);

現在EXPORTED_functionNameP是一個指向一個函數的指針,該函數接受一個int參數並且不返回任何值。

C 和 C++ 之間存在差異。

int (FAR WINAPI * FARPROC) () 

在 C 中,FARPROC 聲明指示具有未指定參數列表的回調函數。 但是,在 C++ 中,聲明中的空參數列表表示函數沒有參數。

CallWindowProc 上MSDN 頁面解釋了更多。

我知道這是一個非常古老的問題,但我遇到了完全相同的問題,但是關於編寫通用包裝模板來包裝對 LoadLibrary() 和 GetProcAddress() 的調用

https://blog.benoitblanchon.fr/getprocaddress-like-a-boss/為靈感,他似乎將 FARPROC 視為一種“Windows 函數的 void*”,然后將其轉換為正確的類型。

我需要稍微調整一下代碼才能為我工作,並在此處重現它:

class ProcPtr
{
public:
    explicit ProcPtr(FARPROC ptr) : m_ptr(ptr) {}

    template <typename T>
    operator T* () const { return reinterpret_cast<T*>(m_ptr); }

private:
    FARPROC m_ptr;
};

class DllHelper
{
public:
    explicit DllHelper(LPCTSTR filename) : m_module(LoadLibrary(filename)) {}
    ~DllHelper() { FreeLibrary(m_module); }

    ProcPtr operator[](LPCSTR proc_name) const
    {
        return ProcPtr(::GetProcAddress(m_module, proc_name));
    }

private:
    HMODULE m_module;
};

因此,有了現在可用的輔助代碼,我們可以使用它來編寫一個包裝類,該類封裝了 Advapi32 庫中的幾個函數:

class Advapi32
{
public:
    Advapi32() : m_dll(TEXT("Advapi32"))
    {
        getUserName    = m_dll["GetUserNameA"];
        openSCManager  = m_dll["OpenSCManagerA"];
        bogusFunction  = m_dll["BogusFunctionThatDoesNotExist"];
    }

    decltype(GetUserNameA)*         getUserName;
    decltype(OpenSCManagerA)*       openSCManager;
    decltype(GetWindowsDirectoryA)* bogusFunction;

private:
    DllHelper m_dll;
};

bogusFunction 是一個與 GetWindowsDirectoryA 具有相同簽名但在 Advapi32 中不存在的函數。 這就是我想要實現的 - 在可能沒有特定功能的舊操作系統上優雅回退。

所以,最后一個測試應用程序......

int main()
{
    Advapi32 advapi32;

    auto func1 = advapi32.getUserName;
    if (func1)
    {
        TCHAR  infoBuf[256];
        DWORD  bufCharCount = sizeof(infoBuf);

        if (func1(infoBuf, &bufCharCount))
        {
            std::cout << "Username: " << infoBuf << std::endl;
        }
    }

    auto func2 = advapi32.openSCManager;
    if (func2)
    {
        SC_HANDLE handle = func2(NULL, NULL, SC_MANAGER_CONNECT);
        if (handle)
        {
            std::cout << "opened SC Manager" << std::endl;
        }
    }

    auto func3 = advapi32.bogusFunction;
    if (func3)
    {
        std::cerr << "This should not happen!" << std::endl;
    }
    else
    {
        std::cout << "Function not supported" << std::endl;
    }
}

輸出:

Username: TestAccount 
opened SC Manager 
Function not supported

注意:這是在 VS2019 下使用 VS2015_XP 工具集編譯為帶有 MBCS 而不是 Unicode 的 Windows 32 位控制台應用程序,因為這是我需要的目標(不要問)。

FARPROC 定義為

typedef int (FAR WINAPI *FARPROC)();

當你傳遞一個額外的參數時,盡管原型的參數列表是空的,你會得到錯誤。

您需要PORTED_functionNameP的正確原型定義, PORTED_functionNameP GetProcAddress的結果轉換為GetDLLPopinters函數中的該類型。

這是因為 FARPROC 被定義為:

int (FAR WINAPI * FARPROC) ()

所以你不能在 C++ 中將任何參數傳遞給這樣的函數。 為了修復它,您應該將EXPORTED_functionNameP定義為指向具有 DLL 庫中定義的相同語義的函數的指針。 例如:

typedef (void* EXPORTED_functionNameP)(int value);
EXPORTED_functionNameP ExportedFns;
...
ExportedFns = GetProcAddress(drvsHANDLE, "originalFunctionName");

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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