DLLに文字列を受け渡しして、文字列を返すには?

解決


.NETS  2004-11-23 03:46:06  No: 86822

>DLLに文字列を受け渡しして、文字数を返すには
の質問をしていた者です。

今回なのですが、VBからDLLに文字列を渡して、
その文字列を再びVB側に返すには?という質問です。

VBからDLLに文字列をポインタとして渡す部分までは
先の質問でできていますので、それの応用かと思います。

で、以下のようなソースでやってみたのですが、敢無く失敗。

//dll
_declspec(dllexport) int _stdcall strings(char* filename){
    return(*filename);
}

'vb
Private Declare Function strings Lib "strings.dll" (ByVal filename As String) As Integer

Public Sub getStrings()
    textbox2.Text = strings(textbox1.Text)
End Sub

色々調べた結果文字列は構造体で渡すというような記述を
見つけたのですが、どなたか良いヒントをいただけないでしょうか?


split()  2004-11-23 07:34:24  No: 86823

まず、文字列を返そうとしているのに戻値の型がintなのが間違い。
VB6ならCのintをVBのIntegerで表現しているのも間違い。
Cのchar *をVBのStringと思っているのも間違いです。

でサンプル

//dll
_declspec(dllexport) BSTR _stdcall strings(BSTR* filename){
   _bstr_t retStr(*filename,TRUE);
   return retStr.copy();
}

'vb
Private Declare Function strings Lib "strings.dll" (filename As String) As String

Public Sub getStrings()
    textbox2.Text = strings(textbox1.Text)
End Sub


.NETS  2004-11-23 13:12:27  No: 86824

>split()さん

色々な指摘ありがとうございます。

>//dll
>_declspec(dllexport) BSTR _stdcall strings(BSTR* filename){
>   _bstr_t retStr(*filename,TRUE);
>   return retStr.copy();
>}

を試してみたのですが、ビルドに失敗します。
これは何かインクルードする必要があるのでしょうか??


.NETS  2004-11-23 13:26:55  No: 86825

連続投稿で失礼します。
自分で調べて、comdef.hをインクルードして解決できました。

ところで、

>_declspec(dllexport) BSTR _stdcall strings(BSTR* filename){
>   _bstr_t retStr(*filename,TRUE);
>   return retStr.copy();
>}

について、もう少し詳細の解説を頂けないでしょうか?
特にBSTRや_bstr_t、retStr等を調べては見たのですが、
日本のサイトに殆どヒットしないのです。

よろしくお願いします。


龍一郎  2004-11-23 14:28:10  No: 86826

>.netsさん

横から失礼します。

_declspec(dllexport) BSTR _stdcall strings(BSTR* filename){
   _bstr_t retStr(*filename,TRUE);
   return retStr.copy();
}

とすれば文字列を渡して、受け取る事ができるというのは分かったのですが、
今、自分がやろうとしているのは、DLLがVBから文字列を受け取り、
その文字列をfopen(file, mode)のfileに入れることでして、
BSTR* filenameで取得した文字列のポインタ(?)をどうやって
fileまで運べばいいのか、C言語初心者の自分には見当が付きません。
よき解決策はないでしょうか?


  2004-11-23 22:46:44  No: 86827

> 特にBSTRや_bstr_t、retStr等を調べては見たのですが、
> 日本のサイトに殆どヒットしないのです。

そんなことは無いと思います。
http://www.google.com/search?hl=ja&q=BSTR&btnG=Google+%E6%A4%9C%E7%B4%A2&lr=lang_ja
http://www.google.com/search?hl=ja&q=_bstr_t&btnG=Google+%E6%A4%9C%E7%B4%A2&lr=lang_ja


split()  2004-11-24 02:17:11  No: 86828

BSTR,_bstr_tはMSDNライブラリに記載されています。

特に質問点が明確な場合は答えられますが、全般的に教えてとなると
zさんがおっしゃるようにググッて調べてください。
(質問する場合はC++の掲示板の方が良いと思います)

またretStrは作成した_bstr_tオブジェクトに付けた適当な名前
(変数名みたいなもの)なので調べる必要はないです。

>龍一郎さん
VBからの引渡しをByVal filename As Stringにすれば
CのDLLの方ではchar *型で受けることができます。


龍一郎  2004-11-24 03:38:04  No: 86829

split()さん、どうもです。

ソースを以下のようにしてみました。

//dll
FILE *fp1;
char code[10];

_declspec(dllexport) char _stdcall strings(char* filename){

  strcpy(code,".txt");
  strcat(filename,code);
  fp1=fopen(filename,"a");
  xxx = 111.111;
  fprintf(fp1,"%f\n", xxx);
  fclose(fp1);
}

'vb
Private Declare Sub strings Lib "strings.dll" (ByVal filename As String)

Private Sub Command1_Click()
    Call strings(textbox1.Text)
End Sub

うーん、なかなかうまくいきませんねぇ〜(;o;)


split()  2004-11-24 05:05:33  No: 86830

char *で受けることができるといってもBSTRの文字領域の先頭アドレスを
受けているだけです。
その領域に対してstrcatをすると当然不定なメモリ領域に文字を書き込む
ことになります。

同じくzさんのおっしゃる様にBSTRについて調べてみてはどうでしょうか。
で分からないことがあればC++掲示板の方に質問してください。


龍一郎  2004-11-24 06:59:53  No: 86831

毎度失礼します。
うまくいきました。

'vb
Private Declare Sub strings Lib "strings.dll" (ByVal filename As String)

Private Sub Command1_Click()
    Call strings(textbox1.Text)
End Sub

//dll
FILE *fp1;
char code[10];
char* filename;

_declspec(dllexport) void _stdcall setFileNameDLL(char* getfilename){
  filename = getfilename;
}

void makeFile(){
    strcpy(code,".txt");
    strcat(filename,code);
    fp1=fopen(filename,"a");
    fprintf(fp1,"making file\n");
    fclose(fp1);
}

とすると、VBで入力したファイル名をDLLに渡してファイルを作成する事ができました。

しかし、その後にVB側をexeファイルにして実行すると
入力したファイル名が"1.txt"や"2.txt"のようになってしまいます…。
これはいったい何が原因なのでしょうか?


  2004-11-24 16:36:51  No: 86832

>char* filename;
…これのポインタが代入されて、そのポインタが有効な間は…
>_declspec(dllexport) void _stdcall setFileNameDLL(char* getfilename){}
の間だけじゃないか?
>makeFile(){}
でfilenameを使っても、存在するか分からない所を参照するだけだと思うのだが…?


ねろ  2004-11-24 21:52:46  No: 86833

話がかなり複雑化していますが、前の質問の解答を完全には理解していないのでは。
VBが使用している文字列の「BSTR」は頭に文字の先頭のアドレスがヘッダーとしてくっついています。
その為にByRefでCのDLLを呼び出すとこの先頭のポインターのポインターが渡ってしまいます。
そこでByValで呼び出しますが、実はこれはが又例外で、ByValで呼び出してもDLLには文字列の先頭
のポインターが渡るのです。従ってByValで渡していながら、
  __declspec(dllexport) void __stdcall strings(LPSTR str)
  {
   while( *str != 0){
    *str = toupper(*str);//大文字に変換        
    str++;
  }
  }
の様に渡した文字列を書き換えることが可能です。
VB側で  
Private Declare Sub strings Lib "foo" (ByVal s As String)
  Private Sub Command1_Click()
    Dim s As String
    s = "hello"
    strings s
    Text1.Text = s
  End Sub
とやって見ると文字列は大文字に変わることがわかります。
ただしこれは文字列がC側に渡した文字列の長さと同じか短い場合の話になります。
書き換える文字列が渡した文字列よりも長い場合は、メモリーの再確保が当然
発生します。この場合渡す文字列を十分長い文字列を渡すか、固定長の文字列を
渡した方がC側でBSTRに対応するより楽でしょう。ここにサンプルが有ります。
http://support.microsoft.com/default.aspx?scid=kb;ja;410837
最初の.NETSさんの質問は、文字列の長さが渡した文字列と同じか、それより短かったら
値を返す必要は無く渡す文字列をVBの側でStringの宣言をすれば良いだけになります。
ユーザー定義型での渡し方は上のサンプルの中にあります。

龍一郎さんの場合は値を返しませんからもっと単純で
  __declspec(dllexport) void __stdcall strings(char* str)
  {
  char s[20];     
  strcpy(s,str);
  str=strcat(s,".txt") ;  
  }
strcatはオーバーフローをチェックしません。
これでいいのでは。


龍一郎  2004-11-25 05:52:36  No: 86834

ぽさん、ねろさん

どうもです。

>>char* filename;
>…これのポインタが代入されて、そのポインタが有効な間は…
>>_declspec(dllexport) void _stdcall setFileNameDLL(char* getfilename){}
>の間だけじゃないか?
>>makeFile(){}
>でfilenameを使っても、存在するか分からない所を参照するだけだと思うのだが…?

えー、つまりsetFileNameDLLを呼び出した瞬間だけfilenameにgetfilenameが代入されていて、
makefileの実行時にはfilenameにgetfilenameは無いということでしょうか??

自分としては、すべてのDLLのソースをひとつにまとめているので
同じDLL内ならば、どこで代入してもDLL実行中は有効だと思っていたのですが…。

同じDLL内でも関数が違えば有効範囲は各々の関数内部のみだということなのでしょうか?

↑意味不明な日本語かもしれませんが…。スミマセン。

>strcatはオーバーフローをチェックしません。
これは1.txtや2.txtになってしまう原因という意味でしょうか??

単純に、VBから文字列をDLLに渡して、
その文字列をファイル名にしたいだけなのに、
こんなに難しい事とは思いませんでした。


。。。  2004-11-25 06:05:54  No: 86835

ねろさんが示されているコードは、そんなに難しいでしょうか?
> __declspec(dllexport) void __stdcall strings(char* str)
> {
>   char s[20];         
>   strcpy(s,str);
>   str=strcat(s,".txt") ;    
> }

メモリ管理の知識があやふやなままコードを組んでしまうのはやめましょう。

なぜsにコピーしなければならないのか理解できたら簡単でしょう。
それに.NETSさんのスレですので疑問があれば別スレ立てたほうがいいんじゃない?


龍一郎  2004-11-25 06:24:06  No: 86836

。。。さん

おっしゃるとおりです。
以降、別にスレッドを立てます。

.NETSさん失礼いたしましたm(__)m


.NETS  2004-11-25 06:50:48  No: 86837

龍一郎さん

いえいえ。
議論が広がって興味深いです。

皆様

解決できました。
遅くなりましたが、解決です。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加