タイトルだけだとなんのコッチャですが。
P/Invokeでやりがちな誤り
C#などでP/Invokeの定義を記述すると下記のように書いてしまいたくなりますが、__x86プラットフォームでは32バイトになり誤り__です。(こちらから引用)
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SHFILEOPSTRUCT
{
public IntPtr hwnd;
[MarshalAs(UnmanagedType.U4)]
public int wFunc;
public string pFrom;
public string pTo;
public short fFlags;
[MarshalAs(UnmanagedType.Bool)]
public bool fAnyOperationsAborted;
public IntPtr hNameMappings;
public string lpszProgressTitle;
}
ネイティブの定義
SHFileOperation関数で使用するSHFILEOPSTRUCT構造体は、shellapi.hで下記のように定義されています。
typedef WORD FILEOP_FLAGS;
...
typedef struct _SHFILEOPSTRUCTA
{
HWND hwnd;
UINT wFunc;
PCZZSTR pFrom;
PCZZSTR pTo;
FILEOP_FLAGS fFlags;
BOOL fAnyOperationsAborted;
LPVOID hNameMappings;
PCSTR lpszProgressTitle; // only used if FOF_SIMPLEPROGRESS
} SHFILEOPSTRUCTA, *LPSHFILEOPSTRUCTA;
typedef struct _SHFILEOPSTRUCTW
{
HWND hwnd;
UINT wFunc;
PCZZWSTR pFrom;
PCZZWSTR pTo;
FILEOP_FLAGS fFlags;
BOOL fAnyOperationsAborted;
LPVOID hNameMappings;
PCWSTR lpszProgressTitle; // only used if FOF_SIMPLEPROGRESS
} SHFILEOPSTRUCTW, *LPSHFILEOPSTRUCTW;
fFlags以外は、ポインターかintになっているのがポイントです。
shellapi.hの先頭でpshpack1.hをincludeしているため、パッキングアラインメントが1バイトになりfFlagsより後は4バイト境界には配置されず、x86プラットフォームだと30バイトになります。
# if !defined(_WIN64)
# include <pshpack1.h>
# endif
...
前述のP/Invokeの定義では32バイトになるため、誤りということになります。
(fFlagsより後を使用しなければ、実害はないと思います。)
対応方法
pinvoke.netに記載がある通り、Pack=1を設定したx86用と、Packを設定しないx64用を2つ定義し、プラットフォームを判別して使い分ける必要があります。
実装としてはdotnet/runtimeあたりを見れば参考になるでしょう。