将Embarcadero C ++ Builder XE3 DLL导入Embarcadero C ++ Builder XE3

时间:2013-03-20 11:28:18

标签: dll c++builder stdcall c++builder-xe getprocaddress

我尝试在Embarcadero C ++ Builder XE3中创建一个DLL,并在同一环境中的测试项目中使用它。

我在一个教程中举例说明哪些代码对我没有好处(!):http://docwiki.embarcadero.com/RADStudio/XE3/en/Tutorial:_Using_Dynamic_Linked_Libraries_in_C%2B%2BBuilder_Applications

以下是我的DLL的内容:

BaseAuth.h文件:

#ifndef   BaseAuthH
#define   BaseAuthH

#include <System.hpp>
class TBaseAuth
{
public:
    virtual void TestMessage() = 0;
};
#endif // BaseAuthH

Auth.h文件:

//---------------------------------------------------------------------------
#ifndef AuthH
#define AuthH
//---------------------------------------------------------------------------
#include "BaseAuth.h"
class TAuth : public TBaseAuth
{
public:
    TAuth();
    ~TAuth();   
    void TestMessage();
};
#endif

Auth.cpp文件:

//---------------------------------------------------------------------------
#pragma hdrstop
#include "Auth.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
TAuth::TAuth()
{
}
TAuth::~TAuth()
{
}
void TAuth::TestMessage()
{
    MessageBox(0, "Test message", "Test", MB_OK);
}

和File1.cpp:

#pragma hdrstop
#pragma argsused

#include "Auth.h"
extern "C" __declspec(dllexport) void* __stdcall GetClassInstance()
{
    return static_cast<void*>(new TAuth());
}
extern "C" int _libmain(unsigned long reason)
{
    return 1;
}    

现在在测试应用程序中我有:

  • 相同的BaseAuth.h文件

  • 带有按钮的表单:

Test_DLLAuthOrga.h:

#ifndef Test_DLLAuthOrgaH
#define Test_DLLAuthOrgaH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
#include "BaseAuth.h"
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // Composants gérés par l'EDI
    TButton *Button2;
    void __fastcall Button2Click(TObject *Sender);
private:    // Déclarations utilisateur
    TBaseAuth *mpAuth;
public:     // Déclarations utilisateur
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

Test_DLLAuthOrga.cpp:

//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Test_DLLAuthOrga.h"
#include "BaseAuth.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
const wchar_t* library = L"DLLAuthOrga.dll";
extern "C" __declspec(dllimport) void* __stdcall GetClassInstance();
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
    HINSTANCE load;
    try
    { load = LoadLibrary(library); }
    catch(Exception &e)
    { ShowMessage(e.Message); }
    if (load)
    {
        ShowMessage("Library Loaded!");
        void *myFunc;
        myFunc = (void *)GetProcAddress(load, "GetClassInstance");
        mpAuth = (AuthParent*)myFunc;
    }
    else { ShowMessage("Library not loaded!"); }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    if (mpAuth == NULL) return;
    try { pRes = mpAuth->TestMessage(); }
    catch(Exception &e) { ShowMessage(e.Message); return; }
}

结果是:

指针mpAuth有一个地址。

但它的方法没有地址,当我调用一个简单的方法,如“void TestMessage()”时,它会引发访问冲突。

=&GT;它首先似乎是字符串兼容性的问题(但在“C ++ Builder XE3”和“C ++ Builder XE3”之间我希望使用相同的字符串格式?!):Error calling DLL with Unicode Delphi

=&GT;我发现了一个类似的问题但用C ++ DLL进入Delphi,而不是C ++ DLL进入C ++ ...:Call C++ DLL in Delphi app

=&GT;我尝试使用“HMODULE”代替“HINSTANCE load”; :结果相同。

=&GT;我尝试使用

没有成功
mpAuth = static_cast<AuthParent*>(myFunc);

而不是:

mpAuth = (AuthParent*)myFunc;

=&GT;我也尝试用“__cdecl”或“”(删除)替换“__stdcall”:libray加载但GetProcAdress返回NULL。

=&GT;在尝试调用DLL的方法“TestMessage()”时,我做错了什么?

1 个答案:

答案 0 :(得分:0)

要从dll正确绑定函数,您应该给它完整的定义,包括调用约定,参数,返回类型和__dllexport/__dllimport修饰符。最简单的方法 - 使用typedef而不是输入(在Test_DLLAuthOrga.cpp中)

void *myFunc;
myFunc = (void *)GetProcAddress(load, "GetClassInstance");

使用

typedef __declspec(dllimport) void (__stdcall *MyFuncPointerType)(void);
MyFuncPointerType myFunc;
myFunc = (MyFuncPointerType)GetProcAddress(load, "GetClassInstance");

如果您使用__cdecl约定,则还应将下划线添加到目标函数名称

typedef __declspec(dllimport) void (__cdecl *MyFuncPointerType)(void);
MyFuncPointerType myFunc;
myFunc = (MyFuncPointerType)GetProcAddress(load, "_GetClassInstance");

您还可以明确定义AuthParent*作为工厂函数的返回类型,以便将不必要的强制类型转换为void*并返回AuthParent*(在File1.cpp和Test_DLLAuthOrga.cpp中) )所以,最终的代码片段如下所示:

typedef __declspec(dllimport) AuthParent* (__cdecl *MyFuncPointerType)(void);
MyFuncPointerType myFunc;
myFunc = (MyFuncPointerType)GetProcAddress(load, "_GetClassInstance");
mpAuth = myFunc();