相互運用を通じて文字列を受信する
-
19-09-2019 - |
質問
自分が書いた C コードから文字列を取得するのに苦労しています。
まず、一般的に現実化されていない背景情報をいくつか示します。TAPI TSP のユーザーが読み取り可能な文字列を TAPI API から受信したいと考えています。ドライバ名と保存された文字列の一致に依存する、半実行可能な TAPI ソリューションを実装しましたが、顧客の 1 人が他の方法で動作することを拒否する (Alcatel) PBX を使用しているため、代わりに永続的な回線 ID で動作するようにこれを変更したいと考えています。 。
C では、ヘッダー ファイルに関数を次のように定義します。
__declspec(dllexport) void GetDeviceName(long DeviceId, wchar_t* DeviceName);
関数は次のように記述されます。
__declspec(dllexport) void GetDeviceName(long DeviceId, wchar_t* DeviceName)
{
//tapi code here...
//copy the string to DeviceName
wcscpy(DeviceName, (wchar_t*)((char *)devCaps + devCaps->dwLineNameOffset));
}
上で述べたように、これは最終的には何か役に立つことになるでしょうが、今のところは、abc が wchar_t*/StringBuilder に配置され、それが C# で確認できれば満足です。
C# では関数を次のように定義します。
[DllImport("SBW.Tapi.TapiInterop.dll", CharSet = CharSet.Auto)]
static extern void GetDeviceName(long DeviceId, StringBuilder DeviceName);
文字列は不変であり、DeviceName を C で設定したいため、DeviceName を StringBuilder として定義します (これはMSが推奨しています)。戻り値の型も次のように設定しました void
それも何かに影響を与えるだろうという淡い期待に基づいています(を参照) これ 部分的な疑似科学的説明としては、半役に立つモノ記事です)。
そしてそれを次のように呼びます:
StringBuilder name = new StringBuilder();
name.EnsureCapacity(100);
long n = 0;
GetDeviceName(n, name);
実行中のプロセスにデバッガーをアタッチし、ブレークポイントを設定すると、C コード内で StringBuilder が何らかの形で不正になり、アンマネージ コードに null ポインターとして提供されていることに気付きます。
その後、C# で AccessViolationException がスローされます。
何が問題だったのでしょうか?
長いパラメータを削除すると役に立ちます。C の DeviceName パラメーターに「abc」を追加できます。ただし、その長い変数が必要です。長いパラメーターを使用して強制的にクラッシュさせるなんて、私は何を間違っているのでしょうか?
解決
32 ビット プラットフォームの場合 long
.NET では 8 バイト (64 ビット) 幅で、ネイティブ コードでは 4 バイト (32 ビット) 幅です。P/Invoke メソッドを次のように変更する必要があります。
[DllImport("SBW.Tapi.TapiInterop.dll", CharSet = CharSet.Auto)]
static extern void GetDeviceName(int DeviceId, StringBuilder DeviceName);
このように、C# int
とC long
32 ビット プラットフォームでは同じ幅になります。
他のヒント
ただし、その長い変数が必要です
次に、C でパラメータを次のように定義する必要があります。 long long
. 。Lucero が指摘したように、C++ の Long は 32 ビットですが、C# の Long は 64 ビットです。したがって、C 関数が 32 ビット値を期待しているところに 64 ビット値を渡すと、関数は余分な 32 ビットを 2 番目のパラメータとして読み取り、明らかにバッファのアドレスが間違ってしまいます。
C++ long
32 ビットの場合、C# long
64ビットですよね?したがって、使用する必要があります int
最初のパラメータに。