• ベストアンサー

ポインターのポインターについて教えてください。

vb6.0のstring型の配列をvc6.0で作ったdllに渡したいのですが どうすればいいのでしょうか? VB側の宣言で Private Declare Function test Lib "strr.dll" (ByRef a() As String, ByVal b As String) As Long Byrefで渡すとそのアドレスが入ってるらしいですが C側でうけとるときこの場合 char ***aという形でうけとるのでしょうか? 実際***aでうけとると、最初の1文字目はdll側で受け取れます。 ただその場合どのようにしてポインタを動かせばいいのかわかりません。 普通に1文字ずらすのは(**a)++というのでは駄目なのでしょうか? (*a)++でもa++でも コンパイルはできるのですが、実行するとフリーズします。 (***a)++だと当然のごとくアスキーコードの値が1増えるだけでした。 例えば vbのa(0)="abcd",a(1)="efgh"をvcで作ったdllを使ってb="abcdefgh"にする場合どのようにすればいいのでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
noname#2009
noname#2009
回答No.1

VBでは文字列の配列は、他の数値配列等とは扱いが 異なっていて、VCに渡すには多分COMにして SafeArrayとゆうモンを使わないとできません。 で、VBの文字列のString型はVCでは BSTR に該当し ます。 ByValで値渡しにすると丁度良くVCのLPSTR型(char*型) に該当し、うまい具合になる という仕組みです。 なので、VCで作ったDLLのDeclare 宣言が >Private Declare Function test Lib "strr.dll" >(ByRef a() As String, ByVal b As String) As > Long になる?のは元々ムリがあるような気がします。 どうしても1つの引数で複数の文字列を渡す必要が あるのなら --------VB側--------------------------- Private Declare Function testnew Lib "strr.dll" (ByVal a As String, ByVal b As String) As Long Dim str As String Dim dlmt As String Dim b As String * 255 dlmt = "," str = "abcd" & dlmt & "efgh" & dlmt & "ijklmnopqrstu~" testnew str, b --------VC側--------------------------- extern"C"__declspec(dllexport) long testnew(char* a, char* b) { char buf[256]; char* param[16]; char* p; char dlmt[] = ","; int i; strcpy(buf, a); p = strtok(buf, dlmt); for(i = 0; p != NULL; i++) { param[i] = p; p = strtok(NULL, dlmt); } // 結果 // param[0] ・・・ "abcd" // param[1] ・・・ "efgh" // param[2] ・・・ "ijklmnopqrstu~" // 戻り値 "abcd" + "efgh" strcpy(b, param[0]); strcat(b, param[1]); return 0; } とゆーふーにしたらどうかと思われます(打ちミスは勘弁で) 『そんなことはねー、文字列配列をまるごと渡せるぞ、』 という方は容赦無く否定して下さい。自信は無しなので

参考URL:
http://www1.ocn.ne.jp/~ajinoya/VisualBasic/UseAPI_FunctionsBasic/
sha-girl
質問者

お礼

ありがとうございます。やはり固定長でくくって送るしかないんでしょうか。参考になりました。

その他の回答 (1)

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.2

VBの文字列型の配列をCのDLLに渡すのは、試したけども無理そうです。 案として、VB側で、SJISにしてから渡すのはどうでしょうか? Private Declare Function test Lib "strr.dll" (ByRef a As Long, ByVal b As String) As Long Dim a(0 To 1) As Long Dim s1() As Byte Dim s2() As Byte s1 = StrConv("abcd", vbFromUnicode) s2 = StrConv("efgh", vbFromUnicode) a(0) = VarPtr(s1) 'もしかしたらVarPtr(s1(0))かも a(1) = VarPtr(s2) Call test(a(0), "文字列") ってな感じで。 C側のプロトタイプはLPSTR* で平気です。 なお、VarPtr()はVBの隠し関数で、変数のアドレスを取得できます。

sha-girl
質問者

お礼

隠し関数なんてあるんですか。 とりあえずバイト型に直して色々やってみたいと思います。 大変参考になりました。ありがとうございました。

関連するQ&A

  • dllを使用しVB側に文字列を返す2

    No.280310の質問の続きになってしまいますが 「VCで作ったdllを使用し VBに文字列を返すことはできますか」 でVCで作ったdllをVBを呼び出す事ができるようになりました。 Declare宣言で疑問に思ったのですが Declare Function TxtCnt Lib "hoge.dll" (ByVal a As String) As Long aはなぜ値渡しなのでしょうか? 変数が書き換えられて戻ってくるので、byrefで指定していました。 それが問題が起こしていた原因一つでした。 ちなみにint型の数値をポインタで渡した場合はbyrefでうまくいきます。 ご教授願います。

  • VB6.0からVB.NETへの移行

    VB6.0から.NETへの移行を行うこととなりましたが、C++で作成したDLL呼び出し方法がわからず悩んでいます。 C++側で作成したDLLは修正が出来ない為、.NET側のみで修正しなければならない状況です。 VB6.0側のプログラムは以下のような感じです。 Public FName() As String Declare Function A Lib "Test.dll" (ByRef field As Variant) As Long ReDim FName(4) As String FName(1) = "1" FName(2) = "22" FName(3) = "333" FName(4) = "4444" Call A(fieldName) C++側は、以下の形で受けているようです。 A(variant *field); SAFEARRAY *psa = *(field->pparray); VB.NET側で以下の様にしてみたのですが、まともに動いてくれません。 Public FName() As String Declare Function A Lib "Test.dll" (ByRef field As Object) As Integer ReDim FName(3) As String FName(0) = "1" FName(1) = "22" FName(2) = "333" FName(3) = "4444" Call A(FName) VB.NETに詳しい方であれば、すごく基本的なことなのではないかと思いますが、よろしくお願いいたします。

  • VB6からVCで作成したDLLへのvoidポインタの受け渡し

    VB6でVCで作成されたDLLの関数から戻り値としてvoidポインタを受け取り、 それをDLLの別の関数を呼び出す際に引数として渡すプログラムを作成しようとして 詰まっています。以下サンプルです。 ===VB側 Public Type Param   sStr As String   lNum As Long End Type Declare Function Create Lib "test.dll" (ByRef tParam As Param) As Long Declare Function Free Lib "test.dll" (ByVal pSt As Any) As Long Dim pSt As Long Dim lRet As Long Dim tParam As Param With tParam   .sStr = "test" & Chr(0)   .lNum = 10 End With pSt = Conn(tParam) lRet = Free(pSt) ===VC側 typedef struct stParaA {   char * aaa;   char * bbb; } PARAM_A; typedef struct stParaB {   char * ccc;   int iNum; } PARAM_B; extern "C" void * __stdcall Create(PARAM_B* stParaB) {   PARAM_A stParaA;   //stParaAの各メンバ領域をMallocで確保   return((void*)stParaA); } extern "C" int __stdcall Free(void* stParaA) {   //stParaAの各メンバ領域をfree   return 0; //正常終了の場合 } VC側でデバッグしてみたところ、stParaBの各メンバの値はVC側で取得できているので、 DLLの呼び出し自体には問題はないようですが、Create()でreturnする時と、Free()に 入ってきたときではstParaAのアドレスが変わってしまい、異常終了します。 VC側はソースはあるのでデバッグは可能なのですが、DLLの修正自体は不可となって いるため、VB側を直すしかないのですが、どのようにすればアドレスの受け渡しが できるのでしょうか。

  • VB.netの配列とVB6の配列の違い

    VB6で画面を作成し、演算処理を行うDLLをVC6で作成しています。 下記のコードでVB6でSingle型の2次元配列を宣言しま、VCのDLLでエクスポートしている関数に渡 します。 VC6DLL側のコード---------- EXPORT void __stdcall TESTFUNC (float *pfData,long nSize{ } VB側のコード---------- 宣言 Declare Function TESTFUNC Lib "TEST.dll" (ByRef pfData As Single, ByVal nSize As Long) As Long 配列宣言 Public sngDat(999,1) as single 呼び出し TESTFUNC sngDat(0,0),1000 このように呼び出した場合、VC6のTESTFUNC にブレークポイントを設定し、停止するとpfDataの ポインタをインクリメントした場合、sngDat(0,0),sngDat(1,0),sngDat(2,0)と、1次元目の添え字を インクリメントした状態になるように、メモリに格納されています。 この動作を前提として、VB.net側でも同じように呼び出してみました。 VB.net側のコード---------- 宣言 Declare Function TESTFUNC Lib "TEST.dll" (ByRef pfData As Single, ByVal nSize As Integer) As Integer 配列宣言 Public sngDat(999,1) as single 呼び出し TESTFUNC(sngDat(0,0),1000) VC側は全く同じコードを利用するとします。 同じように、VC6のTESTFUNC にブレークポイントを設定し、停止するとpfDataの ポインタをインクリメントした場合、sngDat(0,0),sngDat(0,1),sngDat(1,0)と,sngDat(1,1)、と1次元目の添え字を インクリメントせず、2次元目の添え字をインクリメントした状態になるように、メモリに格納されています。 VB6→VC6のDLLの場合の配列渡しと、VB.net→VC6のDLLの場合の配列渡しで違いがあるのは 何故でしょうか?また、VB.net側の配列渡しの仕様を、VB6側の仕様に合わせる方法は無いのでしょうか? よろしくお願いいたします。

  • VB.NET DLL 参照型String読込み

    VCで作成されたDLLの参照型Stringの読込みに困っております。 ご存じの方、お教え下さい。 VB6では次のような定義で、問題なく実行できます。 Private Declare Function VcToVb _ Lib "xxxxxxx.dll" Alias "VcToVb" _ (ByVal Input_DATA As String, ByVal Input_DATA_Cnt As Long, _ ByRef strData As String, ByRef Err_Cnt As Long, ByRef Err_DATA As String) As Long ------------------------------------ Out_Str , Err_Str の領域を確保 iRent = Check_VcToVb1(Input_STR, Input_Cnt, Out_STR, Err_Cnt, Err_STR) これを VB.NETで実施 Private Declare Ansi Function VcToVb _  Lib "xxxxxxx.dll" Alias "VcToVb" _ (ByVal Input_DATA As String, ByVal Input_DATA_Cnt As Int32, _ <MarshalAs(UnmanagedType.LPStr)> ByRef strData As StringBuilder, _ ByRef err_cnt As Int32, ByRef Err_DATA As StringBuilder) As Int32 (テストのため、strDataのみ) -------------------------------------- Out_Str , Err_Str の領域を確保 iRent = Check_VcToVb1(Input_STR, Input_Cnt, Out_STR, Err_Cnt, Err_STR) ******************************************* 調べた結果、VB.NETでは参照型は簡単にはいかないみたいで、StringBuilderを使用するとか、色々な方法を試しました。 結果は戻ってくるのですが、問題は DLLが文字列を返すときに、文字列内の項目区切文字として chr(0)を設定します。 このため、結果は Chr(0)の前までしか設定されません。 (VB.NETが Chr(0)を文字列の最後と判断する?) これを解決する方法はありますでしょうか。 現在は VB6で呼出す DLLを作成し、VB.NETはこれを使用していますが、 C#.Netならできるのでしょうか。 よろしくお願い申し上げます。

  • Cで作成したDLLをVBで呼出

    Cで作成したDLLの関数をVB6.0から呼び出す事ができず、悩んでおります。 ご教授お願いします。 どの様な関数を呼び出そうとしているのかというと、以下の通りです。 <DLL Cで作成(コンパイラVC6)> void WINAPI hoge(BSTR pgname,BSTR fmt,...){ ~処理~ } /* 宣言では頭にDLLExport*/ <呼出側 VB6.0で作成> '宣言 Public Declare Function hoge Lib "hoge" _ (ByRef pgname as String , _ ByRef fmt as String , _ ParamArray args()) '呼出 call hoge("foo","baa","array1",2) この様なコードを書いております。 C側、VB側ともに固定数の引数にしてみたところ、 通ったので「ParamArray args()」の定義が違うのではないか・・・?と思っているのですが、 どの様に宣言したらよい物なのでしょうか? もしくは、そもそも全然違う箇所を間違っているのでしょうか? 宜しくお願いします。 ※ 説明の足りない箇所があれば、仰ってください。

  • VBのString型の配列をVCで受け取るには?

    VBでString型の配列として定義されている変数を VCのプログラムで受け取るにはどうすればよいのでしょうか? 試しにVBでString型の配列を作って DLLのC_TESTというファンクションを呼び出すという 処理を作ってみたのですが、コンパイルエラーになってしまいます。 なにかおかしいところありますか? そもそもVCにはString型ってないんですよね? プログラミング初心者ですので、変な言葉遣いに なってるかもしれませんが宜しくお願いします。 VB Declare Function C_TEST Lib "\test.dll" (ByVal data() As String) As Integer Dim A(1) As String dim rtn as Integer A(0)="あああ" A(1)="いいい" rtn= C_TEST(A) VCのプログラム int _stdcall C_TEST(LPSTR A[2] ){ AfxMessageBox( A[0] ); return(0); }

  • VCのDLL内でmallocした構造体をVBで使用

    題名通りですが、 VC側のDLLにてmallocで構造体の領域を確保しています。 この領域をVB側で使用したいのですが、やり方がわかりません。 イメージは Public Declare Function GetData Lib "xxx.dll" (ByRef datas As KOUZOUTAI, ByRef dataCnt As Long) As Boolean みたいな形で、datasに構造体のデータ、及び dataCntに領域確保したデータ数を取得出来ればなと思っております。 VB側では、これもイメージですが、 dim datas() as KOUZOUTAI dim dataCnt as long GetData(datas, dataCnt) for cnt=0 to dataCnt - 1 msgbox datas(cnt).a msgbox datas(cnt).b msgbox datas(cnt).c next みたいな感じで処理をしたいと思っております。 お聞きしたい事は 1)そもそも可能なのか? 2)declare宣言のdatasのところが???です。 3)dim datas() as KOUZOUTAIのところも宣言が???です。 4)datas(cnt).a等としているところも配列?として処理出来るのかが???です。 以上、よろしくお願いします。

  • DLL VBとC++

    VBAからVC++2005のDLLを呼び出すプログラムを書いています。 VB側で作成したcpp_proc関数を呼ぶとVBアプリ自体が落ちました。 DLLのreturnの直前に以下のMessageBoxで表示させるとそこまでは表示され、 リターンを押すと、落ちました。 VB側の引数の値 String * 8192が悪いのでしょうか? return直前まで動作していたので、DLLの戻り値に何か原因があるのでしょうか? ついでの質問ですが、DEFの @1は無くても動くのでしょうか? 意味が知りたいです。 // ----- C++ (DLL側) ----- int __stdcall cpp_proc(LPCSTR inp, LPSTR out) { ... 省略 MessageBox(0, "ここまで通過", "debug", MB_OK); return 0; } // ----- DEF ----- LIBRARY "example" DESCRIPTION 'テスト' EXPORTS ; 明示的なエクスポートはここへ記述できます cpp_proc @1 '----- VB側 ----- Public Declare Function cpp_proc Lib "example.dll" _ (ByVal inp As String, ByRef out As String) As Integer Public Sub Test() Dim ret As Integer Dim inp As String Dim out As String * 8192 ret = cpp_proc(inp, out) MsgBox("ret=[" & Cstr(ret) & "]"); End Sub

  • MFC-DLL VBからCallしStackError[No.741430の続き]

    #DLLをCOMにしたり、タイプライブラリを作成すればString型(BSTR)でも 特に問題はなくなります。 VC++で文字列を返すDLLを作ってVBで呼んでいます。 DLLの中でのスタック(Stack)サイズの問題みたいですが、 DLLは自分のスタックを持たなくてそれを使うAppのスタックを使うとしていますが、間違っていたら教えてください。そしてどうすればこのエラーを避けることができて、ただしくデータをVB側で受け取ることができるのでしょうか。 しかし返すデータが大きく(たとえば3MBの文字列)なると『実行エラー28 スタック領域が不足しています。』というエラーメッセージが出て終了されます。 VC++6.0 __declspec(dllexport) VARIANT WINAPI FunA() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); COleVariant vntA = <3MB程度の文字列> ; return vntA.Detach(); } VB6.0 Private Declare Function FunA _ Lib "Communication.dll" () As Variant Dim strRet As String strRet = FunA()

専門家に質問してみよう