3

void*void ポインター (別名またはハンドル) を COMタイプに配置するにはどうすればよいですかVARIANT。ラッパー クラス_variant_tはこれを誤ってブール値に変換します。しかし、COM-Marshaller for .NET がそれをIntPtr.

私が読んだスレッドの 1つは、MSDN Social のこのスレッドでした。彼らは次のような解決策を提案しました。

VARIANTARG Arg; 
VariantInit(&Arg);
V_VT(&Arg) = VT_INT;
V_INT(&Arg) = (int)m_hWnd; 

この解決策の問題は、V_INT(member intVal) が32 ビット整数であり、ポインターを強制的に 32 ビット ポインターにすることです。つまり、64 ビット ポインターを転送できません。その問題の解決策はありますか?64ビット整数として転送する他の方法はありますか?

私はいくつかのコードでこれをテストしました。したがって、any を受け取り、System.Objectその値と型を出力する .NET メソッドを使用します。

public static void TakePtr(object ptr)
{
    Console.WriteLine("Received a " + ptr.GetType() + " with value " + ptr);
}

MyVARIANTは互換性のために満たされてv.llVal = 0; v.byref = myPointer;いるため、32/64 ビット ポインターに関して常に正しくコンパイルされるはずです。さらに、バリアント型を設定して、.NET がSystem.IntPtr キャストせずにマップするようにする必要があります。(実際のアセンブリの場合、コードを変更することはできず、コードをラップしたくないためです。これにより、大幅な複雑さが追加されます。)

  • .NET はSystem.IntPtrを として後方に転送し、前方VT_INTに をマップしSystem.Int32ます。
  • VT_I8にマップしますSystem.Int64が、ではありませんSystem.IntPtr

では、どのVARENUMフラグが ? を指定しSystem.IntPtrますか?

4

5 に答える 5

5

それは不可能です。VARIANT は自動化タイプです。オートメーションは、未知の型へのポインターを処理することを好みません。それらを逆参照する安全な方法はありません。サポートされている唯一のポインター型は、IUnknown* と IDispatch*、インターフェイス ポインターです。

せいぜい、long にマーシャリングする VT_I8 として格納できます。その後、IntPtr にキャストできます。

于 2012-05-27T17:48:48.460 に答える
2

現時点では、完全な問題を解決するための一時的な解決策を見つけました。メソッドを呼び出すときに引数の型を明示的に定義するには、別の呼び出しメカニズムを使用します。したがって、次のメソッドを使用します。これは、型呼び出しメソッドの引数をほぼラップしますが、さらに型をチェックしてそれに応じてキャストするため、 aはorSystem.IntPtrとしてではなく、そのように認識されます。System.Int32System.Int64

public static object InvokeMember(this Type type, object obj, String name, System.Reflection.BindingFlags invokeAttr, Type[] argTypes, object[] argValues)
{
    if (argTypes.Length != argValues.Length) throw new InvalidOperationException("Mismatching count of types an parameters.");
    for (int i = 0; i < argTypes.Length; i++) if (argTypes[i] == typeof(IntPtr)) argValues[i] = new IntPtr(Convert.ToInt64(argValues[i]));
    return type.InvokeMember(name, invokeAttr, null, obj, argValues);
}

このメソッドの呼び出しは次のようになります。

typeof(ExampleLib.HelloNET).InvokeMember(
    null,
    "TakePtr",
    BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod,
    new Type[] { typeof(IntPtr) },
    new object[] { 42 });

最後に、COM からこれを使用してポインター VARIANT を渡す必要があります。v.llVal = 0; v.byref = myPointer; v.vt = VT_INT;

/解決済み:-)

于 2012-05-29T14:07:55.920 に答える
1

PVOID byref;バリアントのメンバーは役に立ちそうです。しかし、それに付随するタイプを設定する必要があるかどうかはわかりません。

LONGLONG llVal32 ビット プラットフォームにもIntPtr(Int64)コンストラクターがあるため、Hans の提案どおりに使用できます。誰かが 128 ビット ポインターを発明するまでは機能するはずです。

于 2012-05-27T18:51:03.520 に答える
0

VT_VOIDとbyrefparamをほとんど問題なく使用しました。ほとんどの場合、.NETは、ネイティブから管理対象オブジェクトへの不正な変換に関するMDAエラー(InvalidVariantエラー)を発生させるためです。

常に表示されるとは限らないため、byrefが0の場合に問題があるかどうかはまだ確認できませんでした。:)

于 2013-02-22T20:39:58.253 に答える
0

同様の問題がありました。64 ビット ポインターが PVOID バリアント型に配置されると、32 ビット ポインターとして切り捨て/マーシャリングされます。そこで、VT_I8 バリアント型を使用し、ポインターをその llVal メンバーに配置すると、すべてうまくいきました。

于 2012-06-21T19:06:28.217 に答える