2016-09-10 2 views
2

これはかなり簡単ですが、以下のコードは機能しません。BPLパッケージ内の関数を動的にロードして呼び出す方法

BPL:

procedure DoSomething(); 
begin 
    LogEvent('Did'); 
end; 

exports 
    DoSomething; 

メインEXE:

procedure CallModuleFunc; 
var 
    H: THandle; 
    P: procedure(); 
begin 
    H := LoadPackage('mymod.bpl'); 
    try 
    if (H <> 0) then 
    begin 
     @P := GetProcAddress(H, 'DoSomething'); 
     if Assigned(P) then 
     P(); 
    end; 
    finally 
    UnloadPackage(H); 
    end; 
end; 

今すぐエラーがLoadPackage()が、GetProcAddress()戻りはnilで正常にBPLの負荷は、ありません。どうして?おそらく名前のmangling。私はstdcall(エクスポートされた関数とPの宣言の両方)を追加しようとしましたが、それは問題を解決しませんでした。私はこのように動作するはずのWeb上で数百の例を見てきました。私もGetProcAddress(H, 'DoSomething$qqsv')を試しましたが、うまくいきませんでした。私はここで何が欠けていますか?

+1

私は、Delphi XE7にあなたのコードを試してみましたが、それが動作します。あなたのプロジェクトは、パッケージをコンパイルするために使用されたものと同じDelphiバージョンを使用してコンパイルされていますか?そうでなければ、私は確信が持てませんが、うまくいかないと思います。 – Hwau

+0

これは、パッケージから機能をエクスポートする方法ではありません。パッケージは、暗黙的にリンクされたときに最も効果的です。ここでデモンストレーションする機能を公開する場合は、DLLを使用します。ほとんどの場合、コードをモジュールに分けて、複雑さや問題を導入する必要はありません。すべてのコードを1つの実行可能ファイルに入れます。 –

+0

Delphiのコマンドライン[TDUMP.EXE](http://docwiki.embarcadero.com/RADStudio/en/TDUMP.EXE,_the_File_Dumping_Utility)ユーティリティを使用して、エクスポートされている* exact *名前を表示してからコピーできますその名前を 'GetProcAddress()'呼び出しに追加します。 –

答えて

1

数時間の検索と試行錯誤の後、私はそれが私が何かやっていたことや違ったやり方でなければならないことに気付きました。問題は、mymod.bplの私の最初のバージョンが、DelphiのデフォルトのBPL出力ディレクトリ(エクスポートされていない、DoSomething()なし)に置かれていたことです。次に、BPL出力ディレクトリをプロジェクトのルートソースディレクトリに変更して、ソースとbplモジュールを1か所で見ることができました。 exeはDelphi 7で使用されていたソースが存在する場所に配置されませんでしたが、DebugまたはReleaseフォルダの下にありました。 LoadPackage()がexeの現在のディレクトリ(Debug/Release)でモジュールを見つけることができない場合、Delphiのデフォルトのパッケージフォルダ(これは最初と間違ったバージョンのbplがあります)を見てロードします。エラーが発生しましたが、DoSomething()もモジュールのコンパイルによって更新されていないため、DoSomething()も呼び出されませんでした。

私は、この説明が似たような問題を抱えている可能性のある誰かを助けてくれることを願っています。これと書いたコメントを読む時間を割いた皆様に感謝します。

+0

@dummzeuchあまりにも遅いです。これは、もはや再現することができない問題、または単純な誤植で引き起こされた問題として、オフトピックに近い投票に該当します*。しかし、不思議なことに、それは再開されてよりナンセンスな答えが加えられ、質問との関連がないこの答えは2つのアップフォースを得ます。本当に、このような振る舞いが悪い質問を奨励するこの種の行動は、サイトの質には役立ちません。 –

+0

このコードはいくつかの点で問題なく動作します。 (1)BPLをEXEファイルの同じディレクトリに配置するか、LoadLibraryで完全パスを使用します。 (2)stdcallは使用しないでください。 –

-2

宣言にstdCallを追加する必要があります。

procedure DoSomething();stdcall; 
begin 
    LogEvent('Did'); 
end; 

exports 
    DoSomething; 
+1

絶対にありません。現在、2つの関数プロトタイプが異なります。重要なことは、どの呼び出し規約が選択されているのではなく、同じ呼び出し規約が使用されているかどうかです。 –

-1

下記のコードを参照してください。 Delphi XE3で動作しています。

unit Unit1; 

interface 
uses Vcl.Forms; 

procedure Test(); stdcall; 

exports 
    Test; 

implementation 

procedure Test(); 
var F : TForm; 
begin 
    F := TForm.Create(nil); 
    F.ShowModal; 
    F.Release; 
end; 

end. 

試験BPL計画Unit1.pas

// Package declaration 
package Package1; 

{$R *.res} 
{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 
{$ALIGN 8} 
{$ASSERTIONS ON} 
{$BOOLEVAL OFF} 
{$DEBUGINFO ON} 
{$EXTENDEDSYNTAX ON} 
{$IMPORTEDDATA ON} 
{$IOCHECKS ON} 
{$LOCALSYMBOLS ON} 
{$LONGSTRINGS ON} 
{$OPENSTRINGS ON} 
{$OPTIMIZATION OFF} 
{$OVERFLOWCHECKS OFF} 
{$RANGECHECKS OFF} 
{$REFERENCEINFO ON} 
{$SAFEDIVIDE OFF} 
{$STACKFRAMES ON} 
{$TYPEDADDRESS OFF} 
{$VARSTRINGCHECKS ON} 
{$WRITEABLECONST OFF} 
{$MINENUMSIZE 1} 
{$IMAGEBASE $400000} 
{$DEFINE DEBUG} 
{$ENDIF IMPLICITBUILDING} 
{$IMPLICITBUILD ON} 

requires 
    rtl, 
    vcl; 

contains 
    Unit1 in 'Unit1.pas'; 

end. 

ユニット。 1つのTButtonで1つのTformのみが含まれます。 (Package1.bplがProject1.exeのと同じディレクトリにある)

unit Unit2; 

interface 

uses 
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; 

type 
    TForm2 = class(TForm) 
    Button1: TButton; 
    procedure Button1Click(Sender: TObject); 
    private 
    { Déclarations privées } 
    public 
    { Déclarations publiques } 
    end; 

var 
    Form2: TForm2; 

implementation 

{$R *.dfm} 

procedure TForm2.Button1Click(Sender: TObject); 
type 
    TProcTest = procedure; 
var 
    PackageModule: HModule; 
    proc : TProcTest; 
begin 
    PackageModule := LoadPackage('Package1.bpl'); 
    if PackageModule <> 0 then 
    begin 
    @Proc := GetProcAddress(PackageModule, 'Test'); 
    if @Proc <> nil then 
     Proc; 
    UnloadPackage(PackageModule); 
    end; 
end; 

end. 
+0

これはリモートから質問に答えません。さらに、一方の側で 'register'呼び出し規約を使用し、他方で' stdcall'を使用します。彼らは一致する必要があります。引数なしの関数では重要ではありませんが、 'stdcall'がエクスポート時に使用するものであると誤解しているようです。 –

関連する問題