C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[7]: C++のVTBYRF|VTBSTRの受け取りに関して


(過去ログ 144 を表示中)

[トピック内 19 記事 (1 - 19 表示)]  << 0 >>

■84635 / inTopicNo.1)  C++のVTBYRF|VTBSTRの受け取りに関して
  
□投稿者/ myzk (1回)-(2017/07/24(Mon) 15:04:20)

分類:[.NET 全般] 

いつもお世話になります。

現在、VB6の環境からC#.NETの環境にコンバートしています。
C++のDLLを呼び出して処理させる箇所を修正していまして
呼び出す型に関して困っています。

環境
Windows7
.NET 4.6.1

C++側
void CONNECT(VARIANT * &RecvData)
{
if ((VT_BYREF | VT_BSTR) != RecvData->vt){
rc = 90;
return ;
}
rc = 0;

    後続処理

return ;
}

.NET側
[DllImport("HelloWorld.dll",CallingConvention = CallingConvention.Cdecl)]
public static extern void VBComGw([MarshalAs(UnmanagedType.BStr)]ref string RecvData);

public static void Main()
{
string Ls_RecvData = "";
CONNECT(ref Ls_RecvData);
}

Ls_RecvDataを渡して、DLL側で変数に値を入れて返すというものです。

VB6の時代ですと、Ls_RecvDataの型がVariantであったので、特別の処理はせずにDLL側に値を渡し返せていたのですが、
.NETになりますと、その型がないので、困っています。
Unsafeなどを使い、Char型のポインタなどを渡すことには成功したのですが、Stringのポインタを渡すやり方がいまいちわかりません。
WEBには[MarshalAs(UnmanagedType.BStr)]を使えば、Stringのまま渡すことできるとは書いてあったり、
Marshal.StringToBSTR()などを用いれば、使えるかと思ったのですが、(VT_BYREF | VT_BSTR)の型に合わず、苦慮しています。

また、ずっとVB.NETを行っていたため、ポインタの認識が浅いです。
C#でもポインタを使用したことがありませんでした。

どうかご助言のほど、宜しくお願い致します。



引用返信 編集キー/
■84637 / inTopicNo.2)  Re[1]: C++のVTBYRF|VTBSTRの受け取りに関して
□投稿者/ 774RR (542回)-(2017/07/24(Mon) 15:40:33)
その C++ DLL ってのを一切修正せずそのまま使わなければならないのか、
捨てちゃって .NET で書き直してよいのか、
あたりでアドバイス内容は異なってくるものと思われるっす。

その DLL で文字列を扱っているとしたら、内部のエンコーディングが MBCS(CP932) なのか UNICODE なのか、
作業を進める前にチェックしておいたほうがいいっすよ?
C++ DLL が CP932 だったら .NET 側で使える文字が C++ DLL には引き渡せないってことになるんで。

# オイラんとこでも MBCS な DLL は再利用せずに捨てて完全に書き直した経験あり

引用返信 編集キー/
■84639 / inTopicNo.3)  Re[2]: C++のVTBYRF|VTBSTRの受け取りに関して
□投稿者/ myzk (4回)-(2017/07/24(Mon) 15:58:42)
No84637 (774RR さん) に返信
> その C++ DLL ってのを一切修正せずそのまま使わなければならないのか、
> 捨てちゃって .NET で書き直してよいのか、
> あたりでアドバイス内容は異なってくるものと思われるっす。
>
> その DLL で文字列を扱っているとしたら、内部のエンコーディングが MBCS(CP932) なのか UNICODE なのか、
> 作業を進める前にチェックしておいたほうがいいっすよ?
> C++ DLL が CP932 だったら .NET 側で使える文字が C++ DLL には引き渡せないってことになるんで。
>
> # オイラんとこでも MBCS な DLL は再利用せずに捨てて完全に書き直した経験あり
>

774RR 様

ご返信ありがとうございます。

C++DLLは修正できない仕様となっています。
そのDLLには文字列を渡している他の関数があり、.NET側から呼び出しに成功していますので、文字コードはUNICODEだと思います。

引用返信 編集キー/
■84640 / inTopicNo.4)  Re[3]: C++のVTBYRF|VTBSTRの受け取りに関して
□投稿者/ Hongliang (557回)-(2017/07/24(Mon) 16:21:15)
多分、単純なMarshalAsの指定だけではどうにもならないと思います。

案1. 間にC/C++のDLLを挟む
 C#から扱いやすい引数型のラッパ関数を作成し、内部でVARIANTを作成して目的のDLL関数を呼び出す。

案2. 間にC++/CLIのDLLを挟む
 基本的には案1と同じ。C#からはDllImportではなく参照設定で呼び出せるように作れるので、C#の視点から見れば楽。その分C++/CLI部分の記述が増えるけど。

案3. 呼び出す際に自分でVARIANTを作成する
 Marshal.GetNativeVariantForObjectを有効利用できるかな?
 メモリの管理がどうなるかは私も詳しくないです。

案4. ICustomMarshalerを実装する
 案3と基本的な考え方は同じ。
引用返信 編集キー/
■84641 / inTopicNo.5)  Re[4]: C++のVTBYRF|VTBSTRの受け取りに関して
□投稿者/ 774RR (543回)-(2017/07/24(Mon) 21:23:27)
> .NET側から呼び出しに成功していますので、
marshaller がエンコーディングを変換している関係で「CP932 にある文字」に関してはうまくいっているが、
UNICODE にあって CP932 にない文字を渡すと化けたり欠落したり、の可能性が0ではない。
# だから「文字列」ではなく「文字」と書いたわけだけど。

その辺は確信が持てるまで確認したほうがよいと思うぞ。絵文字とか七3つの喜とか。

本題に関しては Hongliang 氏の案2に賛成。
C++/CLI の出番はこういうとき限定だと思う・・・

引用返信 編集キー/
■84642 / inTopicNo.6)  Re[2]: C++のVTBYRF|VTBSTRの受け取りに関して
□投稿者/ 魔界の仮面弁士 (1355回)-(2017/07/25(Tue) 11:12:45)
2017/07/25(Tue) 11:17:37 編集(投稿者)

No84635 (myzk さん) に返信
> [DllImport("HelloWorld.dll",CallingConvention = CallingConvention.Cdecl)]
> public static extern void VBComGw([MarshalAs(UnmanagedType.BStr)]ref string RecvData);
DllImportAttribute で VBComGw を指定していますね。
DLL 側は CONNECT 関数だったのでは?


> 現在、VB6の環境からC#.NETの環境にコンバートしています。
DLL 側は改修されていないのですよね。

C# からは CallingConvention を指定しているようですが、
VB6 の場合も Declare で呼び出していたのでしょうか?
それとも VB6 からは参照設定で呼び出していましたか?

Declare だとしたら、VB6 が要求する DLL は stdcall 規約を想定しているため、
C++ の既定である cdecl 規約のライブラリは直接呼び出せなかったはず。

仮に VB6 時代に参照設定で呼び出していたのなら、C# においても
DllImportAttibute ではなく参照設定するべきではないでしょうか。


> if ((VT_BYREF | VT_BSTR) != RecvData->vt){
VB6 時代は ByRef String の受け渡しになっていたのかな…?
http://program.station.ez-net.jp/special/vc/atl-com/variant.asp


> Stringのポインタを渡すやり方がいまいちわかりません。

以下、まだ目を通しきれていないので、参考になるかは分かりませんが。

[Using BSTR in Managed Code]
https://limbioliong.wordpress.com/2011/06/24/primer-using-bstr-in-managed-code-part-1/
https://limbioliong.wordpress.com/2011/06/24/using-bstr-in-managed-code-part-2/

[Using VARIANTs in Managed Code]
https://limbioliong.wordpress.com/2011/09/04/using-variants-in-managed-code-part-1/
https://limbioliong.wordpress.com/2011/09/05/using-variants-in-managed-code-part-2/
https://limbioliong.wordpress.com/2011/09/06/using-variants-in-managed-code-part-3/
引用返信 編集キー/
■84643 / inTopicNo.7)  Re[5]: C++のVTBYRF|VTBSTRの受け取りに関して
□投稿者/ myzk (5回)-(2017/07/25(Tue) 11:48:35)
No84641 (774RR さん) に返信
>>.NET側から呼び出しに成功していますので、
> marshaller がエンコーディングを変換している関係で「CP932 にある文字」に関してはうまくいっているが、
> UNICODE にあって CP932 にない文字を渡すと化けたり欠落したり、の可能性が0ではない。
> # だから「文字列」ではなく「文字」と書いたわけだけど。
>
> その辺は確信が持てるまで確認したほうがよいと思うぞ。絵文字とか七3つの喜とか。
>
> 本題に関しては Hongliang 氏の案2に賛成。
> C++/CLI の出番はこういうとき限定だと思う・・・
>

Hongliang様、774RR様

>>.NET側から呼び出しに成功していますので、
> marshaller がエンコーディングを変換している関係で「CP932 にある文字」に関してはうまくいっているが、
> UNICODE にあって CP932 にない文字を渡すと化けたり欠落したり、の可能性が0ではない。
> # だから「文字列」ではなく「文字」と書いたわけだけど。
>
> その辺は確信が持てるまで確認したほうがよいと思うぞ。絵文字とか七3つの喜とか。

私の認識不足でした。確認致します。

> 本題に関しては Hongliang 氏の案2に賛成。
> C++/CLI の出番はこういうとき限定だと思う・・・

C++は殆ど扱ったことがないので出来る自信がありませんが試してみます。

引用返信 編集キー/
■84644 / inTopicNo.8)  Re[3]: C++のVTBYRF|VTBSTRの受け取りに関して
□投稿者/ myzk (6回)-(2017/07/25(Tue) 12:16:18)
No84642 (魔界の仮面弁士 さん) に返信
> 2017/07/25(Tue) 11:17:37 編集(投稿者)
>
> ■No84635 (myzk さん) に返信
>>[DllImport("HelloWorld.dll",CallingConvention = CallingConvention.Cdecl)]
>>public static extern void VBComGw([MarshalAs(UnmanagedType.BStr)]ref string RecvData);
> DllImportAttribute で VBComGw を指定していますね。
> DLL 側は CONNECT 関数だったのでは?

申し訳ありません。誤表記です。同じ関数名です。

>
>
>>現在、VB6の環境からC#.NETの環境にコンバートしています。
> DLL 側は改修されていないのですよね。
>
> C# からは CallingConvention を指定しているようですが、
> VB6 の場合も Declare で呼び出していたのでしょうか?
> それとも VB6 からは参照設定で呼び出していましたか?
>
> Declare だとしたら、VB6 が要求する DLL は stdcall 規約を想定しているため、
> C++ の既定である cdecl 規約のライブラリは直接呼び出せなかったはず。
>
> 仮に VB6 時代に参照設定で呼び出していたのなら、C# においても
> DllImportAttibute ではなく参照設定するべきではないでしょうか。
>

Declareで呼び出しを行っています。
CallingConventionを元々は指定していませんでした。テストの為、C++のDLLの対象の関数のみをVC++の方でDLLを作成し為
付けないと呼び出せませんでした。C++に疎い為、コンパイル設定を間違った為にこのような設定をしたのかもしれません。
元々のDLL自体はCallingConventionなしで呼び出しています。

誤字、誤設定で申し訳ありません。

>
>>if ((VT_BYREF | VT_BSTR) != RecvData->vt){
> VB6 時代は ByRef String の受け渡しになっていたのかな…?
> http://program.station.ez-net.jp/special/vc/atl-com/variant.asp

VB6の時は、Declareの方はByref VARIANTであり、実際に呼び出す Ls_RecvDataはStringの変数で宣言されていました。


>
>>Stringのポインタを渡すやり方がいまいちわかりません。
>
> 以下、まだ目を通しきれていないので、参考になるかは分かりませんが。
>
> [Using BSTR in Managed Code]
> https://limbioliong.wordpress.com/2011/06/24/primer-using-bstr-in-managed-code-part-1/
> https://limbioliong.wordpress.com/2011/06/24/using-bstr-in-managed-code-part-2/
>
> [Using VARIANTs in Managed Code]
> https://limbioliong.wordpress.com/2011/09/04/using-variants-in-managed-code-part-1/
> https://limbioliong.wordpress.com/2011/09/05/using-variants-in-managed-code-part-2/
> https://limbioliong.wordpress.com/2011/09/06/using-variants-in-managed-code-part-3/


ありがとうございます。確認致します。
引用返信 編集キー/
■84648 / inTopicNo.9)  Re[4]: C++のVTBYRF|VTBSTRの受け取りに関して
□投稿者/ myzk (7回)-(2017/07/25(Tue) 13:42:59)
No84642 (魔界の仮面弁士 さん) に返信

いくつか試しましたので、ご報告致します。

https://limbioliong.wordpress.com/2011/09/05/using-variants-in-managed-code-part-2/

△関数側
[DllImport("HelloWorld.dll")]
public static extern void CONNECT([In]IntPtr RecvData);

○処理側
string Ls_RecvData = new string(' ', 322);
IntPtr pVariant = IntPtr.Zero;
pVariant = Marshal.AllocHGlobal(SizeOfNativeVariant);
Marshal.GetNativeVariantForObject(Ls_RecvData, pVariant);

CONNECT(pVariant);

□結果
C++の方を
if ((VT_BYREF | VT_BSTR) != RecvData->vt)ではなく
if ((VT_BSTR) != RecvData->vt)にすれば正常に通りましたが、VT_BYREF | VT_BSTRが存在するとエラーとして正常ではありませんでした。



Marshal.GetObjectForNativeVariantや他の値を使用してみたのですが、VT_BSTRでは通りますがVT_BYREF | VT_BSTRですと通りませんでした。

引用返信 編集キー/
■84649 / inTopicNo.10)  Re[5]: C++のVTBYRF|VTBSTRの受け取りに関して
□投稿者/ Hongliang (558回)-(2017/07/25(Tue) 13:51:18)
自分でMarshal.WriteInt16とか使って自分でVARIANTを調整しようって話のつもりでした。>案3
ドキュメントに記述がないんで呼び出したとき/返ってきたときのBSTRはどこが解放するのかとか、が「メモリの管理がどうなるかは私も詳しくない」です。
引用返信 編集キー/
■84651 / inTopicNo.11)  Re[5]: C++のVTBYRF|VTBSTRの受け取りに関して
□投稿者/ 魔界の仮面弁士 (1356回)-(2017/07/25(Tue) 15:20:52)
No84648 (myzk さん) に返信
> if ((VT_BSTR) != RecvData->vt)にすれば正常に通りましたが、VT_BYREF | VT_BSTRが存在するとエラーとして正常ではありませんでした。

送信前に、VARIANT 構造体の Offset 0 (vt メンバー)に VT_BYREF を加えてみては如何でしょう。

処理後の BSTR の解放は SysFreeString API あるいは Marshal.FreeBSTR メソッドですが、
今回は Variant なので、VariantClear API だと思います。
引用返信 編集キー/
■84653 / inTopicNo.12)  Re[6]: C++のVTBYRF|VTBSTRの受け取りに関して
□投稿者/ とっちゃん (444回)-(2017/07/25(Tue) 16:02:38)
No84649 (Hongliang さん) に返信
> 自分でMarshal.WriteInt16とか使って自分でVARIANTを調整しようって話のつもりでした。>案3
> ドキュメントに記述がないんで呼び出したとき/返ってきたときのBSTRはどこが解放するのかとか、が「メモリの管理がどうなるかは私も詳しくない」です。

BSTR は、呼び出す側が開放すると取り決めがあります。
かろうじて日本語な資料だと

https://msdn.microsoft.com/ja-jp/library/xda6xzx7.aspx

このあたりですかね。
VARIANT や SAFEARRAY の場合も同様です。

一応。。。.NET での、VT_BYREF|VT_BSTR は VBByRefStr になりますが、これを明示してVARIANTにコンバートする方法は用意されていない気がします。

引用返信 編集キー/
■84656 / inTopicNo.13)  Re[4]: C++のVTBYRF|VTBSTRの受け取りに関して
□投稿者/ 魔界の仮面弁士 (1357回)-(2017/07/25(Tue) 18:07:46)
No84644 (myzk さん) に返信
> VB6の時は、Declareの方はByref VARIANTであり、実際に呼び出す Ls_RecvDataはStringの変数で宣言されていました。

No84635 (myzk さん) に返信
> void CONNECT(VARIANT * &RecvData)
> {
>  if ((VT_BYREF | VT_BSTR) != RecvData->vt){

念のために VB6 でもテストしてみましたが、
提示頂いた内容と、動作が微妙に異なっているような…。

----
Option Explicit

' int WINAPI CONNECT2(VARIANT RecvData) { return RecvData.vt; }
Private Declare Function CONNECT2 Lib "C:\TEMP\Win32Project1.dll" (ByRef v As Variant) As Long

' int WINAPI CONNECT3(VARIANT * RecvData) { return RecvData->vt; }
Private Declare Function CONNECT3 Lib "C:\TEMP\Win32Project1.dll" (ByRef v As Variant) As Long

' int WINAPI CONNECT4(VARIANT * &RecvData) { return RecvData->vt; }
Private Declare Function CONNECT4 Lib "C:\TEMP\Win32Project1.dll" (ByRef v As Variant) As Long


Private Sub Form_Load()
  Dim s As String
  s = "Hello World"

  Dim ret As Long
  ret = CONNECT2(s) '実行時エラー 49 : DLL が正しく呼び出せません
  ret = CONNECT2(ByVal s) '戻り値は vbString (VT_BSTR 相当)

  ret = CONNECT3(s) '戻り値は &H4008& (VT_BYREF | VT_BSTR 相当)
  'ret = CONNECT3(ByVal s) 'クラッシュ

  'ret = CONNECT4(s) 'クラッシュ
  'ret = CONNECT4(ByVal s) 'クラッシュ
End Sub

引用返信 編集キー/
■84659 / inTopicNo.14)  Re[5]: C++のVTBYRF|VTBSTRの受け取りに関して
□投稿者/ myzk (8回)-(2017/07/26(Wed) 00:20:56)
No84656 (魔界の仮面弁士 さん) に返信
> ■No84644 (myzk さん) に返信
>>VB6の時は、Declareの方はByref VARIANTであり、実際に呼び出す Ls_RecvDataはStringの変数で宣言されていました。
>
> ■No84635 (myzk さん) に返信
>>void CONNECT(VARIANT * &RecvData)
>>{
>> if ((VT_BYREF | VT_BSTR) != RecvData->vt){
>
> 念のために VB6 でもテストしてみましたが、
> 提示頂いた内容と、動作が微妙に異なっているような…。
>
> ----
> Option Explicit
>
> ' int WINAPI CONNECT2(VARIANT RecvData) { return RecvData.vt; }
> Private Declare Function CONNECT2 Lib "C:\TEMP\Win32Project1.dll" (ByRef v As Variant) As Long
>
> ' int WINAPI CONNECT3(VARIANT * RecvData) { return RecvData->vt; }
> Private Declare Function CONNECT3 Lib "C:\TEMP\Win32Project1.dll" (ByRef v As Variant) As Long
>
> ' int WINAPI CONNECT4(VARIANT * &RecvData) { return RecvData->vt; }
> Private Declare Function CONNECT4 Lib "C:\TEMP\Win32Project1.dll" (ByRef v As Variant) As Long
>
>
> Private Sub Form_Load()
>   Dim s As String
>   s = "Hello World"
>
>   Dim ret As Long
>   ret = CONNECT2(s) '実行時エラー 49 : DLL が正しく呼び出せません
>   ret = CONNECT2(ByVal s) '戻り値は vbString (VT_BSTR 相当)
>
>   ret = CONNECT3(s) '戻り値は &H4008& (VT_BYREF | VT_BSTR 相当)
>   'ret = CONNECT3(ByVal s) 'クラッシュ
>
>   'ret = CONNECT4(s) 'クラッシュ
>   'ret = CONNECT4(ByVal s) 'クラッシュ
> End Sub
>

ご確認ありがとうございます。もとのC++Dllのほうを確認致しましたら、
CONNECT3(VARIANT * RecvData)が正しい形でした。byrefの&は付いていませんでした。

度々の誤表記でご迷惑をお掛けして申し訳ありません。
引用返信 編集キー/
■84661 / inTopicNo.15)  Re[6]: C++のVTBYRF|VTBSTRの受け取りに関して
□投稿者/ 774RR (544回)-(2017/07/26(Wed) 11:13:05)
https://social.msdn.microsoft.com/Forums/ja-JP/fed14bc3-a443-4a3d-ae18-785cff5a3973/ccdllstring?forum=csharpgeneralja
なんですって。もう知らん。

引用返信 編集キー/
■84662 / inTopicNo.16)  Re[7]: C++のVTBYRF|VTBSTRの受け取りに関して
□投稿者/ myzk (9回)-(2017/07/26(Wed) 11:26:52)
No84661 (774RR さん) に返信
> https://social.msdn.microsoft.com/Forums/ja-JP/fed14bc3-a443-4a3d-ae18-785cff5a3973/ccdllstring?forum=csharpgeneralja
> なんですって。もう知らん。
>

親身にご回答いただいている中大変申し訳ありません。多くの方のご意見もお伺いしたく載せてしましました。削除致しました。
色々と誤字、誤設定と不手際があり申し訳ありませんが、何卒宜しくお願い申し上げます。
引用返信 編集キー/
■84666 / inTopicNo.17)  Re[8]: C++のVTBYRF|VTBSTRの受け取りに関して
□投稿者/ Azulean (840回)-(2017/07/26(Wed) 12:44:06)
No84662 (myzk さん) に返信
> 親身にご回答いただいている中大変申し訳ありません。多くの方のご意見もお伺いしたく載せてしましました。削除致しました。

確実なのは C++/CLI 路線だとは思います。
いずれにせよ、簡単な方法はないので別の場所で質問しても答えは変わらないだけで時間が過ぎていくだけです。

ご自身の手に負えないなら、早めにギブアップして、組織内の力量ある人に頼るか、別の業者に投げるか、諦めるかした方がよいですよ。
解決しないまま、日数が経過する方が不味いので。
引用返信 編集キー/
■84670 / inTopicNo.18)  Re[6]: C++のVTBYRF|VTBSTRの受け取りに関して
□投稿者/ 魔界の仮面弁士 (1359回)-(2017/07/26(Wed) 17:32:26)
No84659 (myzk さん) に返信
> CONNECT3(VARIANT * RecvData)が正しい形でした。byrefの&は付いていませんでした。
> 度々の誤表記でご迷惑をお掛けして申し訳ありません。


DLL 側で V_VT(RecvData) が VT_BYREF | VT_BSTR となるよう、
VARIANT 構造体の内容を調整してみました。


// void WINAPI CONNECT(VARIANT * RecvData);
[DllImport("HelloWorld.dll")]
private static extern void CONNECT(IntPtr RecvData);


// WINOLEAUTAPI_(void) VariantInit(__out VARIANTARG * pvarg);
[DllImport("oleaut32")]
private static extern void VariantInit(IntPtr pVariant);

// WINOLEAUTAPI VariantClear(__inout VARIANTARG * pvarg);
[DllImport("oleaut32", PreserveSig = true)]
private static extern void VariantClear(IntPtr pVariant);

static void Main()
{
 string str = "Hello World";

 // Variant の作成
 IntPtr pVariant = Marshal.AllocCoTaskMem(8 + 2 * IntPtr.Size);
 VariantInit(pVariant);
 Marshal.GetNativeVariantForObject(str, pVariant);

 // VT_BSTR から VT_BYREF | VT_BSTR へと変更
 Marshal.WriteInt16(pVariant, 0, (short)(VarEnum.VT_BYREF | VarEnum.VT_BSTR));
 //IntPtr bstrVal = Marshal.StringToBSTR(str);
 IntPtr bstrVal = Marshal.ReadIntPtr(pVariant, 8); // BSTR の取得
 IntPtr pbstrVal = Marshal.AllocCoTaskMem(IntPtr.Size);
 Marshal.WriteIntPtr(pbstrVal, 0, bstrVal);
 Marshal.WriteIntPtr(pVariant, 8, pbstrVal); // BSTR* に書き換え

 // ターゲットの呼び出し
 CONNECT(pVariant);

 // 使うかどうかは分からないけれど、念のため
 // VARIANT の内容をマネージ側に戻しておく
 object resultObject = Marshal.GetObjectForNativeVariant(pVariant);
 string resultString = resultObject as string;

 // Variant の解放
 VariantClear(pVariant);
 Marshal.FreeBSTR(bstrVal);
 Marshal.FreeCoTaskMem(pVariant);
 Marshal.FreeCoTaskMem(pbstrVal);
}
引用返信 編集キー/
■84702 / inTopicNo.19)  Re[7]: C++のVTBYRF|VTBSTRの受け取りに関して
□投稿者/ myzk (10回)-(2017/07/28(Fri) 09:12:20)
No84670 (魔界の仮面弁士 さん) に返信
> ■No84659 (myzk さん) に返信
>>CONNECT3(VARIANT * RecvData)が正しい形でした。byrefの&は付いていませんでした。
>>度々の誤表記でご迷惑をお掛けして申し訳ありません。
>
>
> DLL 側で V_VT(RecvData) が VT_BYREF | VT_BSTR となるよう、
> VARIANT 構造体の内容を調整してみました。
>
>
> // void WINAPI CONNECT(VARIANT * RecvData);
> [DllImport("HelloWorld.dll")]
> private static extern void CONNECT(IntPtr RecvData);
>
>
> // WINOLEAUTAPI_(void) VariantInit(__out VARIANTARG * pvarg);
> [DllImport("oleaut32")]
> private static extern void VariantInit(IntPtr pVariant);
>
> // WINOLEAUTAPI VariantClear(__inout VARIANTARG * pvarg);
> [DllImport("oleaut32", PreserveSig = true)]
> private static extern void VariantClear(IntPtr pVariant);
>
> static void Main()
> {
>  string str = "Hello World";
>
>  // Variant の作成
>  IntPtr pVariant = Marshal.AllocCoTaskMem(8 + 2 * IntPtr.Size);
>  VariantInit(pVariant);
>  Marshal.GetNativeVariantForObject(str, pVariant);
>
>  // VT_BSTR から VT_BYREF | VT_BSTR へと変更
>  Marshal.WriteInt16(pVariant, 0, (short)(VarEnum.VT_BYREF | VarEnum.VT_BSTR));
>  //IntPtr bstrVal = Marshal.StringToBSTR(str);
>  IntPtr bstrVal = Marshal.ReadIntPtr(pVariant, 8); // BSTR の取得
>  IntPtr pbstrVal = Marshal.AllocCoTaskMem(IntPtr.Size);
>  Marshal.WriteIntPtr(pbstrVal, 0, bstrVal);
>  Marshal.WriteIntPtr(pVariant, 8, pbstrVal); // BSTR* に書き換え
>
>  // ターゲットの呼び出し
>  CONNECT(pVariant);
>
>  // 使うかどうかは分からないけれど、念のため
>  // VARIANT の内容をマネージ側に戻しておく
>  object resultObject = Marshal.GetObjectForNativeVariant(pVariant);
>  string resultString = resultObject as string;
>
>  // Variant の解放
>  VariantClear(pVariant);
>  Marshal.FreeBSTR(bstrVal);
>  Marshal.FreeCoTaskMem(pVariant);
>  Marshal.FreeCoTaskMem(pbstrVal);
> }


ありがとうございます。実行しましたら無事渡せることができました。
皆様には色々とご助言を頂きまして、ありがとうございました。

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -