PInvoke-COMインターフェイスからフィールドを表現する方法
質問
次のように始まるCOM構造を参照しています:
[scriptable, uuid(ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e)]
interface nsICacheSession : nsISupports
{
/**
* Expired entries will be doomed or evicted if this attribute is set to
* true. If false, expired entries will be returned (useful for offline-
* mode and clients, such as HTTP, that can update the valid lifetime of
* cached content). This attribute defaults to true.
*/
attribute PRBool doomEntriesIfExpired;
...
出典:http ://dxr.proximity.on.ca/dxr/mozilla-central/netwerk/cache/public/nsICacheSession.idl.html#58
そのインターフェイスをC#アプリにインポートするコードを見つけました。ただし、 set
メソッドは役に立たないようであり、何が起こるかを確認するためだけに呼び出すとエラーがスローされるため、コードは間違っている必要があります。
[Guid("ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e"), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface nsICacheSession
{
[return: MarshalAs(UnmanagedType.Bool)]
void set_doomEntriesIfExpired();
[return: MarshalAs(UnmanagedType.Bool)]
bool get_doomEntriesIfExpired();
...
doomEntriesIfExpired
の値を設定する正しい方法と、コードからこれを参照するにはどうすればよいですか
編集
コードを次のように変更し、" System.AccessViolationException:保護されたメモリの読み取りまたは書き込みを試行しましたyada yada ...":
[Guid("ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e"), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface nsICacheSession
{
void set_doomEntriesIfExpired(bool enabled);
bool get_doomEntriesIfExpired();
...
解決
挿入した答えは良いです。 COMでは、InteropブールはデフォルトでVARIANT_BOOLとしてマーシャリングされるため、MarshalAs属性を追加してマーシャラーに標準の4バイトBOOL型を使用するように指示することは正しいですが、式のゲッター部分にも属性を追加する必要があります。
一般に、インターフェイスで定義されているプロパティをゲッターとセッターに分割するのではなく、プロパティのままにしておきます。インターフェース定義のセマンティクスとよりよく一致し、通常は読みやすくなります。 doomEntriesIfExpiredの属性の性質を保持するために、次のようにCOMインポート定義を書き直すことができるはずです。
[Guid("ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e"), ComImport,
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface nsICacheSession
{
bool doomEntriesIfExpired
{
[param:MarshalAs(UnmanagedType.Bool)]set;
[return:MarshalAs(UnmanagedType.Bool)]get;
}
...
他のヒント
void set
メソッドに対して [return:MarshalAs(UnmanagedType.Bool)]
を記述しているという事実は、明らかにエラーの原因です。
とはいえ、.idlに[return ...]タグを付けずにC ++ mozillaプラグインをコーディングできました。例:
[scriptable, uuid(ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e)]
interface nsICacheSession : nsISupports
{
void set_doomEntriesIfExpired(in bool value);
bool get_doomEntriesIfExpired();
}
ところで、C#でnsiプラグインをコーディングしてもいいですか?
答えは次のとおりでした:
[Guid("ae9e84b5-3e2d-457e-8fcd-5bbd2a8b832e"), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface nsICacheSession
{
void set_doomEntriesIfExpired([In, MarshalAs(UnmanagedType.Bool)] ref bool enabled);
bool get_doomEntriesIfExpired();