COMオブジェクトを生成する、ファクトリー関数をP/Invokeメソッドとして宣言する場合、(COMオブジェクトを含まなくてもそうだけど)いろいろな宣言が可能なので、そのメモ。
ネイティブ関数
SHCreateDefaultContextMenu を例にする。
SHSTDAPI SHCreateDefaultContextMenu(_In_ const DEFCONTEXTMENU *pdcm, _In_ REFIID riid, _Outptr_ void **ppv);
メソッドいろいろ
素直なP/Invokeメソッド
C# 7.2から使用できるin引数を使用している。
[DllImport("shell32.dll", PreserveSig = false)]
void SHCreateDefaultContextMenu(in DEFCONTEXTMENU pdcm, in Guid riid, out IContextMenu ppv);
C# 7.2より前
Guid
構造体には、UnmanagedType.LPStruct
が使えるらしいので、ref
を付けずにポインタを渡せる。
[DllImport("shell32.dll", PreserveSig = false)]
void SHCreateDefaultContextMenu(ref DEFCONTEXTMENU pdcm, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IContextMenu ppv);
COMオブジェクトをinterfaceではなく、objectで受け取る
[DllImport("shell32.dll", PreserveSig = false)]
void SHCreateDefaultContextMenu(ref DEFCONTEXTMENU pdcm, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, [MarshalAs(UnmanagedType.IUnknown)]out object ppv);
戻り値をHRESULTのまま受け取る
DllImport
属性のPreserveSig
をtrue
(デフォルト)にしておけば、ネイティブ関数のHRESULT
の値をそのまま受け取れる。
その代わり、エラーチェックは自分でやる必要がある。
[DllImport("shell32.dll", PreserveSig = true)]
int SHCreateDefaultContextMenu(in DEFCONTEXTMENU pdcm, in Guid riid, out IContextMenu ppv);
最後の引数を戻り値として受け取る
COMのIDLには retval
属性があり、メソッドの戻り値があるかどうかは最後の引数の属性で決まる。
単なる属性なので、P/Invokeでもシグニチャ次第となる。
PreserveSig = false
が付与されている前提で、
- 戻り値を
void
にすれば戻り値なしになる - 最後の引数を戻り値に移動させればそれが戻り値になる
[DllImport("shell32.dll", PreserveSig = false)]
IContextMenu SHCreateDefaultContextMenu(in DEFCONTEXTMENU pdcm, in Guid riid);
付録:上記で使用している型の宣言
struct DEFCONTEXTMENU
{
public IntPtr hwnd;
public IContextMenuCB pcmcb;
public PCIDLIST_ABSOLUTE pidlFolder;
public IShellFolder psf;
public uint cidl;
public PCUITEMID_CHILD_ARRAY apidl;
[MarshalAs(UnmanagedType.IUnknown)]
public object punkAssociationInfo;
public uint cKeys;
// const HKEY *aKeys;
public IntPtr[] aKeys;
}
[ComImport]
[SuppressUnmanagedCodeSecurity]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214e4-0000-0000-c000-000000000046")]
internal interface IContextMenu
{
void QueryContextMenu(
/* [annotation][in] */
IntPtr hmenu,
/* [annotation][in] */
uint indexMenu,
/* [annotation][in] */
uint idCmdFirst,
/* [annotation][in] */
uint idCmdLast,
/* [annotation][in] */
uint uFlags);
void InvokeCommand(
/* [annotation][in] */
in CMINVOKECOMMANDINFO pici);
void GetCommandString(
/* [annotation][in] */
UIntPtr idCmd,
/* [annotation][in] */
uint uType,
/* [annotation][in] */
UIntPtr pReserved,
/* [annotation][out] */
StringBuilder pszName,
/* [annotation][in] */
uint cchMax);
}