いつもお世話になっています。
早速なのですが、CorVC(実はよくわからない)で作成されたアプリから
Delphiで作ったDLLを呼び出し、DLLからの返り値が取得できなくて困っています。
extern "C" __declspec(dllexport)
void Function(const char* Input, char* Output);
形式で宣言された DLL内の関数を呼び出すものです。
関数呼び出しのときに, Inputに入力文字列が渡されます。
返り値はOutputのバッファに書き込めます。
これに対して私が書いたソースです
function delhoge(input:string):pwidechar;stdcall;
var
tmp,tmp2,tmp3:string;
begin
//処理の部分は省略
tmp := '[hoge]' + tmp2 + ' [hoge]' + tmp3;
result := SysAllocStringByteLen(PCHAR(tmp), Length(tmp));
end;
exports delhoge;
どなたか分かる方いらっしゃいましたら教えて下さい。宜しくお願い致します。
VC等からでは 引数に stringは使用できません。
PChar等を使用してください。
よく見たら
C側とDelphi側の関数定義の整合性がとれていませんよ。
返信有難う御座います。
DLLに渡されたデータをstringで取らずにPCharで取得しろという事ですか?
アプリ側のCで書かれた定義ですが実はよくわかってません。
単にDLLに入力文字列が渡ってきてresultで返せばいいだけなのだと思っていました。
色々調べながらやってみます。
>DLLに渡されたデータをstringで取らずにPCharで取得しろという事ですか?
そうです Delphiのstringはメモリの管理方法が異なるのでそのままでは VCやVBとやり取りすることは出来ません。
>単にDLLに入力文字列が渡ってきてresultで返せばいいだけなのだと思っていました。
それならC側では(Delph側にあわせるなら)
void Function(const char* Input, char* Output);
ではなくて
char *Function(const char* Input);
ではないでしょうか?
追伸
Delphi側をC側にあわせるなら
procedure delhoge(Input: PChar; Output: PChar); stdcall;
になります。
この定義の場合
Outputのバッファは前もってC側で確保されている必要があります。
>char *Function(const char* Input);
>ではないでしょうか?
その通りだと思います。実際DLL側に渡ってきている引数は1つだけで
Outputにあたる部分をdelphi側でどうすればいいのかわからずにいます。
void Function(const char* Input, char* Output);
をdelphiで現すと
Function(const Input,Output:PChar):PChar;
となると思うのですがこの場合返り値を入れる器を用意してくれていると解釈するのですか?
上の書き込みの半分より下は見なかった事にして下さいorz
質問ばかりで申し訳ありません。合わせてタイトルとは趣旨の違う質問ばかりでごめんなさい。
C側のアプリのヘルプではバッファは用意してあるような事が書いてあります。
この場合、DLL側からはどのようにして返してあげれば良いのでしょうか?
resultを使うと新たに領域を作って返してしまう形になってしまうような気がするのですが。
>void Function(const char* Input, char* Output);
>をdelphiで現すと
>Function(const Input,Output:PChar):PChar;
>となると思うのですがこの場合返り値を入れる器を用意してくれていると解釈するのですか?
いいえ
>Function(const Input,Output:PChar):PChar;
ではなくて
procedure hoge(const Input: PChar; Output:PChar);
ですね。
C側が char *Function(const char* Input);
なら
Delphi側は function hoge(Input:PChar): PChar; stdcall;
となります。
C側での正式な定義を教えていただけませんか?
LimeChatのヘルプの一部です。
転載は許可されてるみたいなので必要ない部分を消してそのまま載せます。
extern "C" __declspec(dllexport)
void Function(const char* Input, char* Output);
形式で宣言された DLL内の関数を呼び出すものです.
Inputに入力文字列が渡されます.
返値は Outputのバッファに書き込めます.
渡されるバッファは 1024バイトまでの文字列を保持できます.つまり,nulターミネータを入れて,1025バイトのバッファを用意しています.
具体的には次のように使います.
$DllString(mydll.dll,Omikuji,大凶)
>上はlimechatでdllを呼び出すためのマクロです$dllstring(ファイル名、関数名、入力文字列
void Omikuji(const char* Input, char* Output)
{
if (lstrcmp(Input, "大凶") == 0) {
lstrcpy(Output, "人生,金だけが頼りです.");
} else if (lstrcmp(Input, "凶") == 0) {
lstrcpy(Output, "捨てる神あれば拾う神あり.");
} else {
lstrcpy(Output, "人並み以上.");
}
}
以上です。宜しくお願い致します。
単純に
procedure Omikuji(const Input: PChar; Output: PChar); stdcall;
begin
if StrComp(Input, '大凶') = 0 then
StrCopy(Output, '人生,金だけが頼りです.')
else if StrComp(Input, '凶') = 0 then
StrCopy(Output, '捨てる神あれば拾う神あり.')
else
StrCopy(Output, "人並み以上.");
end;
ではどうしょうか?
>> StrCopy(Output, "人並み以上.");
SingleQuoteの間違い。ううっ・・・人並み以上にはなれなかった
追伸
C側で stdcall が指定されていない場合は
delphi側では cdecl としてください。
procedure Omikuji(const Input: PChar; Output: PChar); cdecl;
すごい!思うように処理する事ができました!
呼び出し規約はすみません、適当に付けてましたorz勉強してみます。
procedure Omikuji(const Input: PChar; Output: PChar); cdecl;
begin
if StrComp(Input, '大凶') = 0 then
StrCopy(Output, '人生,金だけが頼りです.')
else if StrComp(Input, '凶') = 0 then
StrCopy(Output, '捨てる神あれば拾う神あり.')
else
StrCopy(Output, '人並み以上.');
end;
で上手くLimeChatへ帰ってきました。
返り値という考え方ではなくC側で用意してくれた場所へデータを載せる。
という考え方に近いのでしょうか。ものすごく勉強になりました。
こんな早朝に長くお時間を使わせてしまって本当に申し訳ありません。OTL
おかげで思うような物が作れそうです。
有難う御座いました!
解決にチェックつけるの忘れてた
ツイート | ![]() |