包括C ++的C-DLL

问题描述 投票:3回答:6

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

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

[自然,我也没有自己写这些,也不是我的库,最好它们都保持不变。我did但是添加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++,什么都没有。

[我知道这与名称修改有关,但是当您包含gcc行时,我认为extern "C"会解决这个问题……有人可以解释一下我在这里缺少的内容吗?

如果有关系-

Windows XP Pro(稍后将是Win7)

((MinGW)gcc 4.6.2

c++ c windows dll mingw
6个回答
1
投票

C和C ++之间有区别。

int (FAR WINAPI * FARPROC) () 

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

MSDN page on CallWindowProc解释了更多。


2
投票

FARPROC类型是不带参数的函数的函数指针。您应该这样声明EXPORTED_functionNameP(用函数实际返回的值替换void):

extern void (*EXPORTED_functionNameP)(int);

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

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

对于函子类型的typedef可能会使事情更具可读性。


1
投票

经过Google的快速搜索后,似乎FARPROC定义如下:

typedef int (FAR WINAPI *FARPROC)();

FARPROC是一个返回int且不带参数的函数。因此,不能在其他任何情况下使用它。

而不是像这样声明EXPORTED_functionNameP

extern void (*EXPORTED_functionNameP)(int);

现在EXPORTED_functionNameP是指向带有int自变量但不返回值的函数的指针。


0
投票

由于FARPROC被定义为:

int (FAR WINAPI * FARPROC) ()

因此,您不能在C ++中将任何参数传递给此类函数。为了进行修复,您应该将EXPORTED_functionNameP定义为具有与DLL库中定义的相同语义的函数的指针。例如:

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

0
投票

FARPROC定义为

typedef int (FAR WINAPI *FARPROC)();

尽管原型的参数列表为空,但您传递了一个附加参数时,则会出现错误。

您需要为PORTED_functionNameP提供适当的原型定义,并将GetProcAddress的结果与GetDLLPopinters函数中的类型关联。


0
投票

我知道这是一个非常老的问题,但是我遇到了完全相同的问题,但是与编写用于包装对LoadLibrary()和GetProcAddress()的调用的通用包装器模板有关。

https://blog.benoitblanchon.fr/getprocaddress-like-a-boss/为灵感,他似乎将FARPROC视为一种“函数的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"))
    {
        getUserNameA   = m_dll["GetUserNameA"];
        openSCManager  = m_dll["OpenSCManagerA"];
        bogusFunction  = m_dll["BogusFunctionThatDoesNotExist"];
    }

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

private:
    DllHelper m_dll;
};

bogusFunction是一个具有与GetWindowsDirectoryA相同的签名的函数,但是Advapi32中不存在。这就是我想要达到的目标-在旧版OS上进行优美的后备。

所以,最终是一个测试应用程序...

int main()
{
    Advapi32 advapi32;

    auto func1 = advapi32.getUserNameA;
    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

[注意:这是使用VS2015_XP工具集在VS2019下使用MBCS而不是Unicode编译为Windows 32位控制台应用程序,因为这是我需要定位的(不要问)。

© www.soinside.com 2019 - 2024. All rights reserved.