C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト


■85096 / )  Re[7]: 複数ファイルをコピーする時に進捗ダイアログを表示する
□投稿者/ 魔界の仮面弁士 (1410回)-(2017/09/11(Mon) 13:02:08)
No85094 (カンガルー さん) に返信
>>SHFILEOPSTRUCT 構造体のアライメントは、本来は 1 バイトパッキングです。
>>提示 URL の VBA コードだと fFlags の後続メンバーの配置がずれますのでご注意ください。
> これってどういう意味ですか?

紹介した URL で解説していますが、ファイルコピーがユーザによってキャンセルされた場合、
SHFILEOPSTRUCT の fAnyOperationsAborted メンバーに 1 がセットされる仕様なのです。
(先のサンプルでは、キャンセルを判定するようなコードにはなっていないですけれどね)

32bit環境においては、SHFILEOPSTRUCT 構造体のメモリ配置は、
 0x00-0x03 → HWND 型 hWnd
 0x04-0x07 → UINT 型 wFunc
 0x08-0x0B → PCZZTSTR 型 pFrom
 0x0C-0x0F → PCZZTSTR 型 pTo
 0x10-0x11 → FILEOP_FLAGS 型 fFlags
 0x12-0x15 → BOOL 型 fAnyOperationsAborted
 0x16-0x19 → LPVOID 型 hNameMappings
 0x1A-0x1D → PCTSTR 型 lpszProgressTitle
と並んでいます。


ところが VBA は、4バイト単位に再配置して呼び出す仕様です。

0x00、0x04、0x08、0x0C というのは 4 バイト単位の位置に並んでいるので問題ないのですが、
fAnyOperationsAborted が配置されているのは、「0x10-0x13 の後半」と「0x14-0x17 の前半」に
またがるメモリ位置になっています。

そこで VBA は、API の呼び出し時に自動的に 2 バイト分調整し、 No85091 の構造体を
 0x00-0x03 → Long 型 hWnd
 0x04-0x07 → Long 型 wFunc
 0x08-0x0B → String 型 pFrom
 0x0C-0x0F → String 型 pTo
 0x10-0x11 → Integer 型 fFlags
 0x12-0x13 → 【2 バイトのパディング】
 0x14-0x17 → Long 型 fAnyOperationsAborted
 0x18-0x1B → Long 型 hNameMappings
 0x1C-0x1F → String 型 lpszProgressTitle
のメモリ配置に変換して渡すようになっています。


ところが、API がキャンセル結果を書き込むのは
0x12-0x15 のメモリ位置なので、結果を正しく受け取れなくなるわけです。

受け取れないだけならまだ良いですが、ポインタである
lpszProgressTitle に文字列を渡してから呼び出せば、
クラッシュしてしまう可能性すらあるわけです。


一方 VB.NET の場合は、StructLayoutAttibute 属性を付与することで、
このアライメント調整を明示的に指定することができるようになっています。


'SHFileOperationA を呼び出す場合は、CharSet.Ansi をセットします。
'SHFileOperationW を呼び出す場合は、CharSet.Unicode をセットします。
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode, Pack:=1)> _
Public Structure SHFILEOPSTRUCT
  Public hwnd As IntPtr
  <MarshalAs(UnmanagedType.U4)> Public wFunc As Integer '(Enum FILEOP As Int32)
  <MarshalAs(UnmanagedType.LPWStr)> Public pFrom As String
  <MarshalAs(UnmanagedType.LPWStr)> Public pTo As String
  <MarshalAs(UnmanagedType.U2)> Public fFlags As Short '(Enum FILEOP_FLAGS As Int16)
  <MarshalAs(UnmanagedType.Bool)> Public fAnyOperationsAborted As Boolean
  Public hNameMappings As IntPtr
  <MarshalAs(UnmanagedType.LPWStr)> Public lpszProgressTitle As String
End Structure
返信 編集キー/


管理者用

- Child Tree -