unit general; interface uses Windows, Classes; //メッセージボックス function gfniMessageBox(const sMsg, sTitle: WideString; const iStyle: UINT): Integer; //ファイル名を返す function gfnsFileNameGet(sFile: WideString): WideString; function gfnsFilePathGet(sFile: WideString): WideString; //ファイル選択ダイアログボックス function gfnbOpenFileDialog(var sFile: WideString): Boolean; //保存ダイアログ function gfnbSaveFileDialog(var sFile: WideString): Boolean; function gfnsFileVersionGet: WideString; implementation uses CommDlg, Dialogs, Forms, Messages, MultiMon, SysUtils, main; // MessageBox ------------------------------------------------------------------ function gfniMessageBox(const sMsg, sTitle: WideString; const iStyle: UINT): Integer; //Unicode対応のMessageBox。 begin //iStyleに0を指定した場合はMB_OKを指定したのと同じ Result := MessageBoxW(Application.Handle, PWideChar(sMsg), PWideChar(sTitle), iStyle or MB_SETFOREGROUND); end; // File ------------------------------------------------------------------------ function gfnsFileNameGet(sFile: WideString): WideString; { パスを除いたファイル名を返す 拡張子はつく \ はつかない } var i, li_Len, li_Pos: Integer; begin Result := ''; if (sFile <> '') then begin li_Len := Length(sFile); li_Pos := li_Len + 1; //sFileの最後が'\'であった場合への対策 for i := li_Len downto 1 do begin if (sFile[i] = '\') or (sFile[i] = '/') or(sFile[i] = ':') then begin Break; end; li_Pos := i; end; Result := Copy(sFile, li_Pos, MaxInt); end; end; function gfnsFilePathGet(sFile: WideString): WideString; { Unicode対応ExtractFilePath。 ドライブ名も含む。 末尾の '\' はつく。 ドライブ名のみの場合も '\' はつく。 ただしパスが空文字の場合のみ '\' はつかない。 } var i: Integer; begin Result := ''; if (sFile <> '') then begin for i := Length(sFile) downto 1 do begin if (sFile[i] = '\') or (sFile[i] = '/') then begin Result := Copy(sFile, 1, i); Break; end else if (sFile[i] = ':') then begin Result := Copy(sFile, 1, i) + '\'; Break; end; end; end; end; function gfnbFolderExists(sFolder: WideString): Boolean; //DirectoryExitsのUnicode対応版 var lh_Handle: THandle; lr_Info: TWin32FindDataW; li_Len: Integer; begin Result := False; if (sFolder <> '') then begin li_Len := Length(sFolder); if (sFolder[li_Len] = '\') then begin SetLength(sFolder, li_Len -1); end; end; FillChar(lr_Info, SizeOf(TWin32FindDataW), 0); lh_Handle:= FindFirstFileW(PWideChar(sFolder), lr_Info); try if (lh_Handle<> INVALID_HANDLE_VALUE) then begin repeat if (WideString(lr_Info.cFileName) <> '.') and (WideString(lr_Info.cFileName) <> '..') and ((lr_Info.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) <> 0) then begin Result := True; Break; end; until not(FindNextFileW(lh_Handle, lr_Info)); end; finally Windows.FindClose(lh_Handle); end; end; function gfnsFileVersionGet: WideString; //バージョン情報を返す procedure Int32ToHiLo(iNum: Longint; var iHi, iLo: Integer); type TMy_HiLo = record case Integer of 1: (iInt: Longint); 2: (iLoInt, iHiInt: SmallInt); //リトルエンディアン end; var lr_Int: TMy_HiLo; begin lr_Int.iInt := iNum; iHi := lr_Int.iHiInt; iLo := lr_Int.iLoInt; end; var li_Size, li_Reserved, li_Len: DWORD; li_Hi, li_Lo: Integer; lp_Buff, lp_Locale, lp_Dat: Pointer; ls_FileInfo: WideString; begin Result := ''; // 必要なバッファのサイズを取得 li_Size := GetFileVersionInfoSizeW(PWideChar(G_sAppExeName), li_Reserved); if (li_Size > 0) then begin //メモリ確保 lp_Buff := AllocMem((li_Size +1) * 2); try if (GetFileVersionInfoW(PWideChar(G_sAppExeName), 0, li_Size, lp_Buff)) then begin //変数情報ブロック内の変換テーブルを指定 if (VerQueryValueW(lp_Buff, '\VarFileInfo\Translation', lp_Locale, li_Len) and (li_Len > 0)) then begin Int32ToHiLo(Integer(lp_Locale^), li_Hi, li_Lo); ls_FileInfo := WideFormat('\StringFileInfo\%.4x%.4x\', [li_Lo, li_Hi]); //ファイルバージョン if (VerQueryValueW(lp_Buff, PWideChar(ls_FileInfo + 'FileVersion'), lp_Dat, li_Len) and (li_Len > 0)) then begin Result := WideString(PWideChar(lp_Dat)); end; end; end; finally // 解放 FreeMem(lp_Buff); end; end; end; // Rect ------------------------------------------------------------------------ function gfniRectWidth(rtRect: TRect): Integer; //rtRectの幅を返す begin with rtRect do begin Result := Right - Left; end; end; function gfniRectHeight(rtRect: TRect): Integer; //rtRectの高さを返す begin with rtRect do begin Result := Bottom - Top; end; end; function gfnrcRectCenter(rcParent, rcChild: TRect): TRect; //rcChildがrcParentの真ん中にくるようなRectを返す var li_Left, li_Top, li_Width, li_Height: Integer; begin li_Width := gfniRectWidth (rcChild); li_Height := gfniRectHeight(rcChild); li_Left := rcParent.Left + (gfniRectWidth (rcParent) - li_Width) div 2; li_Top := rcParent.Top + (gfniRectHeight(rcParent) - li_Height) div 2; Result := Rect(li_Left, li_Top, li_Left + li_Width, li_Top + li_Height); end; function gfnrcMonitorWorkAreaRectGet(hHandle: HWND): TRect; overload; //ウィンドウのあるモニターのワークエリアを返す。 var lr_Info: TMonitorInfo; begin lr_Info.cbSize := SizeOf(lr_Info); GetMonitorInfo(MultiMon.MonitorFromWindow(hHandle, MONITOR_DEFAULTTONEAREST), @lr_Info); Result := lr_Info.rcWork; end; { Unicode対応のファイル選択ダイアログ TOpenFilename(OpenFilename構造体)について http://homepage2.nifty.com/Mr_XRAY/Halbow/Chap18.html コールバック関数について http://www.vbstation.net/spec/S3_1.htm } //コールバック関数 function lfniCallbackFileDialog(hHandle: HWND; iMsg: UINT; wParam: WPARAM; lParam: LPARAM): UINT stdcall; var lh_Handle: HWND; lrc_Rect: TRect; begin if (iMsg = WM_INITDIALOG) then begin lh_Handle := GetParent(hHandle); //ダイアログボックスのウィンドウハンドルを取得 GetWindowRect(lh_Handle, lrc_Rect); //表示位置をモニターの真ん中に lrc_Rect := gfnrcRectCenter(gfnrcMonitorWorkAreaRectGet(lh_Handle), lrc_Rect); SetWindowPos(lh_Handle, HWND_TOP, lrc_Rect.Left, lrc_Rect.Top, 0, 0, SWP_NOSIZE or SWP_NOZORDER); end; Result := 0; end; function gfnbOpenFileDialog(var sFile: WideString): Boolean; { Unicode対応のファイル選択ダイアログ。 http://delwiki.info/?%A5%B3%A1%BC%A5%C9%C1%D2%B8%CB%2FUnicode%C2%D0%B1%FE%B0%C6%A4%BD%A4%CE%A3%B2 上記サイトとDialogsのTOpenDialog.DoExecuteを参考。 一つだけ選択。 } var lr_Info: TOpenFilenameW; begin FillChar(lr_Info, SizeOf(lr_Info), 0); //0で初期化 with lr_Info do begin lStructSize := SizeOf(lr_Info); hWndOwner := Application.Handle; lpstrInitialDir := PWideChar(gfnsFilePathGet(sFile)); FlagsEx := 0; Flags := OFN_EXPLORER or OFN_ENABLEHOOK or OFN_ENABLESIZING; //エクスプローラ風は必須(古いタイプのとでは区切りが違うので) //Application.Handleだとダイアログが右下に表示されるのでフックを行って真ん中にする lpfnHook := lfniCallbackFileDialog; nMaxFile := 1024; //一つだけ選択なのでこれくらいでいいかなと lpstrFile := AllocMem((nMaxFile +1) * 2); try Result := GetOpenFileNameW(lr_Info); if (Result) then begin sFile := WideString(lpstrFile); end; finally FreeMem(lpstrFile); end; end; end; //SaveDialog function gfnbSaveFileDialog(var sFile: WideString): Boolean; //SaveFileDialogだけども実際はファイル名取得のためだけにも使える。 var lr_Info: TOpenFilenameW; begin FillChar(lr_Info, SizeOf(lr_Info), 0); //0で初期化 with lr_Info do begin lStructSize := SizeOf(lr_Info); hWndOwner := Application.Handle; lpstrInitialDir := PWideChar(gfnsFilePathGet(sFile)); Flags := OFN_EXPLORER or OFN_OVERWRITEPROMPT or OFN_ENABLEHOOK or OFN_ENABLESIZING; //Application.Handleだとダイアログが右下に表示されるのでフックを行って真ん中にする lpfnHook := lfniCallbackFileDialog; nMaxFile := 1024; //ファイルは一つだけなのでとりあえずこれくらいで充分かなと。 lpstrFile := AllocMem((nMaxFile +1) * 2); lstrcpyW(lpstrFile, PWideChar(gfnsFileNameGet(sFile))); try Result := GetSaveFileNameW(lr_Info); if (Result) then begin sFile := WideString(lr_Info.lpstrFile); end else begin sFile := ''; end; finally FreeMem(lpstrFile); end; end; end; end.