あるC言語で作成されたDLLの関数を使用するとアドレスの配列が返されます。
DLL内ではchar***,unsigned int*で定義されています。
このアドレスをIntegerで受け取り、+4バイトした値のアドレスの中身にアクセスし、配列の中身をすべて取得したいのですが方法がわかりません。
どなたかお教えください。
DLLの内容が不明なのでとりあえずパラメータなしでDLL中の関数名をGetAddressと想定して
implementation
type
TAbc = function : integer; stdcall;
ボタンクリックしたときのイベントとして
procedure TForm1mButton1Click(Sender: TObject);
var
DllHandle: THandle;
Abc: TAbc;
APos: integer;
begin
DllHandle := LoadLibrary('ABC.DLL'); //DLL呼び出し
if DllHandle < 32 then //エラーコードはWin32Apiを参照してネ
raise DllError.Create('ABC.DLLが見つかりません');
@Abc := GetProcAddeess(DllHandle, 'GetAddress'); //関数セット
if @Abc = nil then
raise DllError.Create('GetAddressが見つかりません');
APos := Abc; //DLLのGetAddressを実行
FreeLibrary(DllHandle);
end;
これでDLLからポインターのIntegerを取得できると思うのですが。
AVAさま
ありがとうございます。
早速、教えていただいたDLLの動的リンクで試すにあたって、Win32APIのSleep関数を呼び出そうとしたのですが、なぜか、関数のハンドルはGetできたのですが実行すると固まってしまいます。
※ソース
implementation
type
TAbc = procedure Sleep( milSec : integer); stdcall;
procedure TestDllDynLoadFunc;
DllHandle: THandle;
Abc: TAbc;
begin
try
//kernel32.DLL呼び出し
DllHandle := LoadLibrary('kernel32.DLL');
if DllHandle = 0 then
begin
//エラーコードはWin32Apiを参照してネ
raise DllError.Create('kernel32.DLLが見つかりません');
end;
//関数セット
@Abc := GetProcAddeess(DllHandle, 'Sleep');
if @Abc = nil then
begin
raise DllError.Create('Sleepが見つかりません');
end;
//DLLのSleepを実行すると固まる…><
Abc(5000);
finally
if DllHandle <> 0 then
begin
FreeLibrary(DllHandle);
end;
end;
end;
<DLLの内容が不明なのでとりあえずパラメータなしでDLL中の関数名を<GetAddressと想定して
DLLの内容は出力可能なプリンタの一覧を返す関数が入っています。第一引数char***のほうにプリンタ一覧が返ってくるのですが、
char***なんて配列をDelphiでどう定義してどのように渡したら良いのか
分からないので、配列の先頭アドレスから順々にアクセスしようとか
考えています。
(ちなみに.NETだとStringBuilderクラスを引数にすればできます)
すみませんDllErrorの宣言を忘れてました。
public
{public宣言}
end;
DllError = class(Exception); ←これを入れる
var
Form1: TForm1;
implementation
ところでプリンターの一覧を取得するのにDLLを使用する必要はあるのですか?
usesにPrintersを追加して
Printer.Printers
とやればプリンターの一覧を取得できますが。
<すみませんDllErrorの宣言を忘れてました。
コンパイルが通らないのでDllErrorの宣言は行ないました。
だけど、Sleep関数で処理が返ってきません・・・orz
そもそもSleep関数等のWindows.pasに定義されている関数は
呼び出すことはダメなのでしょうか?
(VC++で作成された自作DLLの関数呼び出しはOKだったので・・・)
<ところでプリンターの一覧を取得するのにDLLを使用する必要はあるのですか?
システム全体の仕様上そのDLLを使用しないと、
プリンタの一覧取得だけでなく印刷処理等も行えないのです。
char***で宣言されている関数呼び出しの場合は何を渡せば良いのか
非常に悩んでいます。
どうかご教授ください。。。。。
理解するために.....
h ttp://itpro.nikkeibp.co.jp/article/COLUMN/20061206/256198/
Sleepの動的呼び出しはちゃんと動作したのにと悩んでいたのですがわかりました
TAbc = procedure Sleep( milSec : integer); stdcall;
を
TAbc = procedure (milSec: integer); stdcall;
にしてください。
結局のところ、DLL側の仕様がわからないと
なんとも言えなくないですか?
char***は、宣言だけなら、PCharのポインタののポインタですから、
type
PPChar = ^PChar;
PPPChar = ^PPChar;
ですが、
それを渡すと言うことは、あらかじめ、配列を確保して渡すわけで、
PCharが文字列と考えると、その配列の配列?になるんでしょうか。
つまり、文字列の2次元配列でしょうか。
とりあえず、与えられた情報では、ここまでしか分からんです。
どれくらい配列を確保しなければいけないのか、とかは、与えられた仕様によりけりでしょうし。
結局は、仕様がわからんと、わからんという話に……。
と、私もポインタに関しては、あいまいなので、識者の方つっこんでください。
type
TAList = array[0..2] of array[0..255] of PAnsiChar;
TAbc = function (var FList: TAList): integer; stdcall;
ボタンクリックしたときのイベントとして
procedure TForm1mButton1Click(Sender: TObject);
var
DllHandle: THandle;
Abc: TAbc;
APos: integer;
FList: TAList;
begin
DllHandle := LoadLibrary('ABC.DLL'); //DLL呼び出し
if DllHandle < 32 then //エラーコードはWin32Apiを参照してネ
raise DllError.Create('ABC.DLLが見つかりません');
@Abc := GetProcAddeess(DllHandle, 'GetAddress'); //関数セット
if @Abc = nil then
raise DllError.Create('GetAddressが見つかりません');
APos := Abc(FList); //DLLのGetAddressを実行
FreeLibrary(DllHandle);
end;
かな?
返事が遅くなり大変申し訳ございません。
AVAさま。
当方のミスでした。stdcallを付けていませんでした。
Sleep関数は無事に呼び出すことができました。
TOBYさま
DLL側の仕様しましては、
int GetPrtAddress( char*** prtInf,int* size,int* Num );
第1引数:プリンタ名一覧
第2引数:prtInfで確保した領域のサイズ
第3引数:プリンタ名一覧件数
戻り値 :0で成功、0以外は失敗
です。
pekesukeさま
TAList = array[0..2] of array[0..255] of PAnsiChar;
を使用して呼び出して見ましたが、うまく動きませんでした。
配列数に関しては、第3引数に格納されるのでそれを利用しようと
考えてるので宣言時は適当な数で宣言しました。
ツイート | ![]() |