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

を有効なCに書き直して、の代わりにでmain.cppコンパイルすると、正常に動作します。gccg++

私はアベイルズに変更しようとしextern "C"ましextern "C++"た、私はすべての順列を試しました、またはgcc2g++つのビルドコマンドについては何もしませんでした。

名前マングリングと関係があることは知ってい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には存在しません。これは私が達成しようとしていたことです-特定の機能を持たないかもしれない古いOSでの優雅なフォールバック。

だから、ついにテストアプリ...

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

注:これは、VS2015_XPツールセットを使用したVS2019で、UnicodeではなくMBCSを使用するWindows 32ビットコンソールアプリケーションとしてコンパイルされました。これは、ターゲットにする必要があるためです(質問しないでください)。

于 2020-01-08T22:51:29.697 に答える
1

グーグルで簡単に検索すると、次のようにFARPROC定義されているようです。

typedef int (FAR WINAPI *FARPROC)();

つまり、FARPROCはを返し、int引数をとらない関数です。したがって、他の場合には使用できません。

EXPORTED_functionNameP代わりに、次のように宣言します。

extern void (*EXPORTED_functionNameP)(int);

Nowは、引数を取り、値を返さないEXPORTED_functionNameP関数へのポインターです。int

于 2012-09-03T07:20:19.880 に答える
1

CとC++には違いがあります。

int (FAR WINAPI * FARPROC) () 

Cでは、FARPROC宣言は、パラメーターリストが指定されていないコールバック関数を示します。ただし、C ++では、宣言内の空のパラメーターリストは、関数にパラメーターがないことを示しています。

CallWindowProcのMSDNページでは、もう少し詳しく説明しています。

于 2012-09-03T07:21:11.717 に答える
0

FARPROCは次のように定義されます

typedef int (FAR WINAPI *FARPROC)();

プロトタイプの引数リストが空であるにもかかわらず追加の引数を渡すと、エラーが発生します。

関数内のそのタイプPORTED_functionNamePの結果を適切なプロトタイプ定義に変換する必要があります。GetProcAddressGetDLLPopinters

于 2012-09-03T07:20:08.037 に答える
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 に答える