4

这感觉像是一个菜鸟问题,所以如果它是一个骗子,请指出我正确的位置:)

我尝试将用 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

如果我将 my 重写main.cpp为有效的 C 并使用gcc而不是g++.

我尝试更改extern "C"extern "C++"无济于事,我尝试了所有排列或gcc对于g++两个构建命令,什么都没有。

我知道这与名称修改有关,但我认为gcc当您包含这些行时会处理好extern "C"...有人可以解释一下我在这里缺少什么吗?

以防万一——

Windows XP Pro(稍后将是 Win7)

(MinGW) gcc 4.6.2

4

6 回答 6

2

类型是不带参数的函数的FARPROC函数指针。您应该EXPORTED_functionNameP这样声明(替换void为函数真正返回的任何内容):

extern void (*EXPORTED_functionNameP)(int);

并像这样初始化它(GetProcAddress()几乎总是需要将返回的值转换为正确的类型):

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

函数类型的 Atypedef可能会使事情更具可读性。

于 2012-09-03T07:21:12.003 回答
2

我知道这是一个非常古老的问题,但我遇到了完全相同的问题,但与编写通用包装模板来包装对 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 位控制台应用程序,因为这是我需要的目标(不要问)。

于 2020-01-08T22:51:29.697 回答
1

C 和 C++ 之间存在差异。

int (FAR WINAPI * FARPROC) () 

在 C 中,FARPROC 声明表示具有未指定参数列表的回调函数。然而,在 C++ 中,声明中的空参数列表表示函数没有参数。

CallWindowProc 上的MSDN 页面解释了更多内容。

于 2012-09-03T07:21:11.717 回答
1

快速谷歌搜索后,似乎FARPROC是这样定义的:

typedef int (FAR WINAPI *FARPROC)();

也就是说,FARPROC是一个返回 anint且不带参数的函数。因此,您不能将其用于任何其他情况。

而是EXPORTED_functionNameP像这样声明:

extern void (*EXPORTED_functionNameP)(int);

NowEXPORTED_functionNameP是一个指向函数的指针,该函数接受一个int参数并且不返回任何值。

于 2012-09-03T07:20:19.880 回答
0

这是因为 FARPROC 被定义为:

int (FAR WINAPI * FARPROC) ()

所以你不能在 C++ 中将任何参数传递给这样的函数。要修复它,您应该将其定义EXPORTED_functionNameP为具有相同语义的函数的指针,如 DLL 库中定义的那样。例如:

typedef (void* EXPORTED_functionNameP)(int value);
EXPORTED_functionNameP ExportedFns;
...
ExportedFns = GetProcAddress(drvsHANDLE, "originalFunctionName");
于 2012-09-03T07:30:58.033 回答
0

FARPROC 定义为

typedef int (FAR WINAPI *FARPROC)();

当你传递一个额外的参数时,尽管原型的参数列表是空的,你会得到错误。

您需要一个适当的原型定义,PORTED_functionNameP并将结果从函数GetProcAddress中转换为该类型GetDLLPopinters

于 2012-09-03T07:20:08.037 回答