unit general; //{$DEFINE _DEBUG} interface uses Classes, Controls, Forms, Grids, Windows, Graphics; type TMyBounds = record Left, Top, Width, Height: Longint; end; //myApp.pas function gfnbFormExists(AForm: TForm): Boolean; //myType.pas function gfnsBoolToStr(const bBool: Boolean): String; //myFile.pas function gfnhExecute(sFile: String; sCmdLine: String = ''): THandle; function gfniFileSizeGet(hHandle: THandle): Int64; function gfnhFileOpenRead (sFileName: String): THandle; function gfnhFileOpenWrite(sFileName: String): THandle; //ファイルバージョン type TMyFileVersionInfo = record Comments, // コメント CompanyName, // 会社名 FileDescription, // 説明 FileVersion, // ファイルバージョン InternalName, // 内部名 LegalCopyright, // 著作権 LegalTrademarks, // 商標 OriginalFilename, // 正式ファイル名 PrivateBuild, // プライベートビルド情報 ProductName, // 製品名 ProductVersion, // 製品バージョン SpecialBuild: String; // スペシャルビルド情報 end; function gfnrFileVersionInfoGet(sFile: String): TMyFileVersionInfo; function gfnsProductNameGet: String; function gfnsCommentGet: String; function gfnsFileVersionGet: String; //myGrid.pas procedure gpcGridDataClear(Grid: TStringGrid); function gfniGridWidthGet(Grid: TDrawGrid): Integer; //myList.pas procedure gpcListDelete(List: TList; iIndex: Integer); overload; procedure gpcListClear(List: TList); procedure gpcListFree(List: TList); procedure gpcDifferenceListGet(AGetList: TStrings; ASrcList, ADiffList: TStrings); //myNum.pas function gfniStrToInt(sNum: String; bHexadecimal: Boolean = False): Int64; function gfniNumLimit(iNum: Int64; iMin, iMax: Int64): Int64; function gfniMax(iNum: array of Integer): Integer; function gfnbIsInsideRange(iNum, iMin, iMax: Integer): Boolean; //mySize.pas function gfnrcMinRect(rcRect: array of TRect): TRect; function gfnbEqual(ptPos1, ptPos2: TPoint): Boolean; overload; function gfnsCompasGet(ptStart, ptPos: TPoint): String; function gfniRectWidth (rtRect: TRect): Integer; function gfniRectHeight(rtRect: TRect): Integer; //myMonitor.pas procedure gpcMonitorInfoUpdate; function gfniMonitorIndexGet(APoint: TPoint): Integer; procedure gpcMonitorCenterPosSet(AWinControl: TWinControl); procedure gpcSetMonitorBounds(AForm: TCustomForm; ARect: TRect); //myString.pas function gfnsStrHeadFit(sSrc, sHead: String): String; function gfnsStrHeadCut(sSrc, sHead: String): String; function gfnsStrEndFit(sSrc, sEnd: String): String; //myWindow.pas function gfnbKeyState(iKey: Integer): Boolean; function gfnbKeyStateAnd(iKeys: array of Integer): Boolean; function gfnptMousePosGet: TPoint; function gfnsExeNameGet(hHandle: HWND): String; overload; function gfnhWindowGet(APoint: TPoint): HWND; overload; function gfnszWindowSizeGet(hHandle: HWND): TMyBounds; function gfnsClassNameGet(hHandle: HWND): String; function gfnsWindowTextGet(hHandle: HWND; bFast: Boolean = False): String; function gfnrcClientRectGet(hHandle: HWND): TRect; function gfnptClientToScreen(hHandle: HWND): TPoint; overload; function gfnptScreenToClient(hHandle: HWND; ptPos: TPoint): TPoint; function gfnrcWindowRectGet(hHandle: HWND): TRect; function gfnhToplevelWindowGet(hHandle: HWND): HWND; overload; function gfnhToplevelWindowGet(ptPos: TPoint): HWND; overload; function gfnhOwnerWindowGet(hHandle: HWND): HWND; function gfnhParentWindowGet(hHandle: HWND): HWND; function gfnhProcessToWindow(hWindow: HWND; hProcess: THandle): HWND; overload; function gfnhProcessToWindow(hProcess: THandle): HWND; overload; function gfniProcessIDGet(hHandle: HWND): DWORD; function gfnhPIDToWindow(iProcessID: DWORD): HWND; function gfnsSystem32DirGet: String; //function gfnbIsUnicode(sSrc: String): Boolean; function gfniCanvasTextWidthGet (AFont: TFont; sText: String; iCharExtra: Integer = 0): Integer; function gfniCanvasTextHeightGet(AFont: TFont; sText: String; iCharExtra: Integer = 0): Integer; //スタイル function gfnbFlagCheck(iStyle: Longint; iCheck: Longint): Boolean; const G_ciMARGIN = 2; implementation uses {$IFDEF _DEBUG} _myDebug, {$ENDIF} Messages, MultiMon, PsApi, ShellApi, SysUtils, TlHelp32, // _myWStrings; Types; var F_hUser32_dllModule : HMODULE; F_GetPhysicalCursorPos : function(var lpPoint: TPoint): BOOL; stdcall; // F_LogicalToPhysicalPoint : function(hWindow: HWND; var lpPoint: TPoint): BOOL; stdcall; // F_PhysicalToLogicalPoint : function(hWindow: HWND; var lpPoint: TPoint): BOOL; stdcall; //myApp.pas -------------------------------------------------------------------- function gfnbFormExists(AForm: TForm): Boolean; {2010-07-11: } var i: Integer; begin Result := False; if (AForm <> nil) then begin for i := 0 to Screen.FormCount-1 do begin if (Screen.Forms[i] = AForm) then begin Result := True; Exit; end; end; end; end; //myType.pas ------------------------------------------------------------------- function gfnsBoolToStr(const bBool: Boolean): String; //bBoolがTrueなら'True'を、Falseなら'False'という文字列を返す。 begin if (bBool) then begin Result := 'True'; end else begin Result := 'False'; end; end; //myFile.pas ------------------------------------------------------------------- function gfnhExecute(sFile: String; sCmdLine: String = ''): THandle; { sFileを引数(sCmdLine)で実行してプロセスのハンドルを返す。 呼び出し側で戻り値をCloseHandleする必要あり。 } var l_Info : TShellExecuteInfo; begin FillChar(l_Info, SizeOf(l_Info), 0); l_Info.cbSize := SizeOf(l_Info); l_Info.fMask := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_UNICODE or SEE_MASK_CONNECTNETDRV //ネットワーク上のファイルの UNC(Universal Naming Convention)パス名であることを表します。 // or SEE_MASK_FLAG_DDEWAIT //DDE 対話が開始される場合には、それが終了するまで再開されません。 ; if (sFile <> '') then begin l_Info.lpFile := PChar(sFile); end; if (sCmdLine <> '') then begin l_Info.lpParameters := PChar(sCmdLine); end; l_Info.nShow := SW_SHOWNORMAL; if (ShellExecuteEx(@l_Info)) then begin Result := l_Info.hProcess; end else begin Result := 0; end; // CloseHandle(l_Info.hProcess); end; function gfniFileSizeGet(hHandle: THandle): Int64; {2008-03-11: hHandleのファイルハンドルを持つファイルのサイズをByte単位で返す } var li_High, li_Low: DWORD; begin if (hHandle <> INVALID_HANDLE_VALUE) then begin li_Low := GetFileSize(hHandle, @li_High); Result := li_High * (Int64(MAXDWORD) +1) + li_Low; end else begin Result := 0; end; end; function gfnhFileOpenRead(sFileName: String): THandle; begin Result := CreateFile( PChar(sFileName), //ファイル名 GENERIC_READ, //アクセスモード FILE_SHARE_READ or FILE_SHARE_WRITE , //共有モード nil, //セキュリティ OPEN_EXISTING, //作成方法 FILE_ATTRIBUTE_NORMAL, //ファイル属性 0 //テンプレート ); end; function gfnhFileOpenWrite(sFileName: String): THandle; begin Result := CreateFile( PChar(sFileName), //ファイル名 GENERIC_WRITE, //アクセスモード 0, //共有モード nil, //セキュリティ CREATE_ALWAYS, //作成方法 FILE_ATTRIBUTE_NORMAL, //ファイル属性 0 //テンプレート ); end; function gfnsFileMainGet(sFile: String): String; { ファイル名のうちパスと拡張子を除いた部分を返す。 メインファイル名の拡張子のないもの。 \ と . はつかない。 } begin Result := ChangeFileExt(ExtractFileName(sFile), ''); end; { var i : Integer; lb_Ext : Boolean; //2007-10-26 begin Result := ''; lb_Ext := True; for i := Length(sFile) downto 1 do begin if (sFile[i] = '\') or (sFile[i] = '/') or (sFile[i] = ':') then begin //\と/と:が出てきた時点でファイル名の終了なのでループを抜ける。 Break; end else if (sFile[i] = '.') and (lb_Ext) then begin; //2007-10-26 //拡張子であったので今までのをチャラにする。 Result := ''; lb_Ext := False; end else begin Result := sFile[i] + Result; end; end; end; } function gfnrFileVersionInfoGet(sFile: String): TMyFileVersionInfo; {2007-06-09: ファイルのバージョン情報を返す http://www2.big.or.jp/~osamu/Delphi/Tips/key.cgi?key=13#0226.txt } type TLangAndCodePage = record iLanguage: WORD; iCodePage: WORD; end; PLangAndCodePage = ^TLangAndCodePage; var li_Size, li_Reserved, li_Len : DWORD; lp_Buff, lp_Dat : Pointer; lp_LangPage : PLangAndCodePage; ls_FileInfo : String; begin FillChar(Result, SizeOf(Result), 0); // 必要なバッファのサイズを取得 li_Size := GetFileVersionInfoSize(PChar(sFile), li_Reserved); if (li_Size > 0) then begin //メモリ確保 lp_Buff := AllocMem((li_Size) * SizeOf(Char)); try if (GetFileVersionInfo(PChar(sFile), 0, li_Size, lp_Buff)) then begin //変数情報ブロック内の変換テーブルを指定 // if (VerQueryValueW(lp_Buff, '\VarFileInfo\Translation', lp_Locale, li_Len) and (li_Len > 0)) then begin // gpcInt32ToHiLo(Integer(lp_Locale^), li_Hi, li_Lo); // ls_FileInfo := Format('\StringFileInfo\%.4x%.4x\', [li_Lo, li_Hi]); if (VerQueryValue(lp_Buff, '\VarFileInfo\Translation', Pointer(lp_LangPage), li_Len) and (li_Len > 0)) then begin ls_FileInfo := String(Format('\StringFileInfo\%.4x%.4x\', [lp_LangPage^.iLanguage, lp_LangPage^.iCodePage])); //コメント if (VerQueryValue(lp_Buff, PChar(ls_FileInfo + 'Comments'), lp_Dat, li_Len) and (li_Len > 0)) then begin Result.Comments := String(PChar(lp_Dat)); end; //会社名 if (VerQueryValue(lp_Buff, PChar(ls_FileInfo + 'CompanyName'), lp_Dat, li_Len) and (li_Len > 0)) then begin Result.CompanyName := String(PChar(lp_Dat)); end; //説明 if (VerQueryValue(lp_Buff, PChar(ls_FileInfo + 'FileDescription'), lp_Dat, li_Len) and (li_Len > 0)) then begin Result.FileDescription := String(PChar(lp_Dat)); end; //ファイルバージョン if (VerQueryValue(lp_Buff, PChar(ls_FileInfo + 'FileVersion'), lp_Dat, li_Len) and (li_Len > 0)) then begin Result.FileVersion := String(PChar(lp_Dat)); end; //内部名 if (VerQueryValue(lp_Buff, PChar(ls_FileInfo + 'InternalName'), lp_Dat, li_Len) and (li_Len > 0)) then begin Result.InternalName := String(PChar(lp_Dat)); end; //著作権 if (VerQueryValue(lp_Buff, PChar(ls_FileInfo + 'LegalCopyright'), lp_Dat, li_Len) and (li_Len > 0)) then begin Result.LegalCopyright := String(PChar(lp_Dat)); end; //商標 if (VerQueryValue(lp_Buff, PChar(ls_FileInfo + 'LegalTrademarks'), lp_Dat, li_Len) and (li_Len > 0)) then begin Result.LegalTrademarks := String(PChar(lp_Dat)); end; //正式ファイル名 if (VerQueryValue(lp_Buff, PChar(ls_FileInfo + 'OriginalFilename'), lp_Dat, li_Len) and (li_Len > 0)) then begin Result.OriginalFilename := String(PChar(lp_Dat)); end; //プライベートビルド情報 if (VerQueryValue(lp_Buff, PChar(ls_FileInfo + 'PrivateBuild'), lp_Dat, li_Len) and (li_Len > 0)) then begin Result.PrivateBuild := String(PChar(lp_Dat)); end; //製品名 if (VerQueryValue(lp_Buff, PChar(ls_FileInfo + 'ProductName'), lp_Dat, li_Len) and (li_Len > 0)) then begin Result.ProductName := String(PChar(lp_Dat)); end; //製品バージョン if (VerQueryValue(lp_Buff, PChar(ls_FileInfo + 'ProductVersion'), lp_Dat, li_Len) and (li_Len > 0)) then begin Result.ProductVersion := String(PChar(lp_Dat)); end; //スペシャルビルド情報 if (VerQueryValue(lp_Buff, PChar(ls_FileInfo + 'SpecialBuild'), lp_Dat, li_Len) and (li_Len > 0)) then begin Result.SpecialBuild := String(PChar(lp_Dat)); end; end; end; finally // 解放 FreeMem(lp_Buff); end; end; end; function gfnsProductNameGet: String; //自アプリの製品名。 var lr_Info: TMyFileVersionInfo; begin lr_Info := gfnrFileVersionInfoGet(Application.ExeName); Result := lr_Info.ProductName; if (Result = '') then begin //製品名が指定されていなければ主ファイル名を返す。 Result := gfnsFileMainGet(Application.ExeName); end; end; function gfnsCommentGet: String; //自アプリの説明。 //タスクマネージャやエクスプローラのプロパティには出ない var lr_Info: TMyFileVersionInfo; begin lr_Info := gfnrFileVersionInfoGet(Application.ExeName); Result := lr_Info.Comments; end; function gfnsFileVersionGet: String; //自アプリのファイルバージョン。 var lr_Info: TMyFileVersionInfo; begin lr_Info := gfnrFileVersionInfoGet(Application.ExeName); Result := lr_Info.FileVersion; end; //myGrid.pas ------------------------------------------------------------------- procedure gpcGridDataClear(Grid: TStringGrid); //固定セル以外をクリア。 var i, k: Integer; begin with Grid do begin for i := FixedRows to RowCount-1 do begin for k := FixedCols to ColCount-1 do begin Cells[k, i] := ''; end; end; end; end; function gfniGridWidthGet(Grid: TDrawGrid): Integer; { グリッドの幅を返す。 ボーダースタイルとグリッド線、固定行も含む。 } var i: Integer; begin Result := 0; with Grid do begin //枠 if (BorderStyle = bsSingle) then begin if (Ctl3D) then begin Result := 4; end else begin Result := 2; end; end; //固定列 for i := 0 to FixedCols-1 do begin Inc(Result, ColWidths[i]); if (goFixedVertLine in Options) then begin Inc(Result, GridLineWidth); end; end; for i := FixedCols to ColCount-1 do begin Inc(Result, ColWidths[i]); if (goVertLine in Options) then begin Inc(Result, GridLineWidth); end; end; end; end; //myList.pas ------------------------------------------------------------------- procedure gpcListDelete(List: TList; iIndex: Integer); begin Dispose(List.Items[iIndex]); List.Delete(iIndex); end; procedure gpcListClear(List: TList); var i: Integer; begin for i := List.Count -1 downto 0 do begin gpcListDelete(List, i); end; List.Clear; end; procedure gpcListFree(List: TList); begin gpcListClear(List); List.Free; end; procedure gpcDifferenceListGet(AGetList: TStrings; ASrcList, ADiffList: TStrings); {2015-10-05: リストASrcListからリストADiffListの要素を取り除いたものをAGetListにセットする。 AGetListはASrcListおよびADiffListと同じであってはならない。 } function _IsElementExist(sElement: String; AList: TStrings): Boolean; var i: Integer; begin Result := False; for i := 0 to AList.Count -1 do begin if (sElement = AList[i]) then begin Result := True; Exit; end; end; end; var i: Integer; l_List: TStrings; begin //AGetListの前のvarがないと呼び出し側でエラーになる。 if (AGetList = nil) then begin AGetList := TStringList.Create; end; if (ASrcList = nil) or (ASrcList.Count = 0) then begin if (ADiffList <> nil) and (ADiffList.Count > 0) then begin AGetList.Assign(ADiffList); end else begin AGetList.Clear; end; Exit; end; if (ADiffList = nil) then begin AGetList.Assign(ASrcList); Exit; end; l_List := nil; try l_List := TStringList.Create; for i := 0 to ASrcList.Count -1 do begin if not(_IsElementExist(ASrcList[i], ADiffList)) then begin l_List.AddObject(ASrcList[i], ASrcList.Objects[i]); end; end; AGetList.Assign(l_List); finally l_List.Free; end; //myDebug.gpcDebug(AGetList); end; //myNum.pas -------------------------------------------------------------------- function gfniStrToInt(sNum: String; bHexadecimal: Boolean = False): Int64; //sNumを整数にして返す。 function _GetStrToHalf(sSrc: String): String; var lp_Buff : PChar; li_Len : Integer; begin Result := sSrc; li_Len := LCMapString(GetUserDefaultLCID(), LCMAP_HALFWIDTH, PChar(Result), -1, nil, 0); lp_Buff := AllocMem((li_Len +1) * SizeOf(Char)); try //半角にする LCMapString(GetUserDefaultLCID(), LCMAP_HALFWIDTH, PChar(Result), -1, lp_Buff, li_Len); Result := String(lp_Buff); finally FreeMem(lp_Buff); end; end; procedure _Val(S: String; var V: Int64; var Code: Integer); var ls_Num : String; li_Pos : Integer; begin Val(S, V, Code); if (Code > 0) then begin ls_Num := Copy(S, 1, Code -1); Val(ls_Num, V, li_Pos); end; end; var li_Pos, i: Integer; ls_Tmp: String; li_Err: Integer; begin sNum := UpperCase(_GetStrToHalf(Trim(sNum))); //全角の算用数字もOkなように半角にする。 _Val(sNum, Result, li_Err); if (li_Err = 0) then begin Exit; end; // try // Result := StrToInt64(sNum); // except ls_Tmp := ''; for i := 1 to Length(sNum) do begin li_Pos := Pos(sNum[i], '$X-+, 0123456789ABCDEF'); if (li_Pos >= 17) then begin //'A..F' if (ls_Tmp <> '') and (ls_Tmp[1] = '$') then begin ls_Tmp := ls_Tmp + sNum[i]; end else begin //頭に'$'を付け加えて変換できるようにする。 //頭に$がないと16進表記はエラーになるのでそれへの対処。 ls_Tmp := '$' + ls_Tmp + sNum[i]; end; end else if (li_Pos >= 7) then begin //'0..9' ls_Tmp := ls_Tmp + sNum[i]; end else if ((li_Pos = 1) or (li_Pos = 2)) and (ls_Tmp = '') then begin //'$', 'X' //16進表記。 ls_Tmp := '$'; //'x'や'X'ではだめ。 end else if ((li_Pos = 3) or (li_Pos = 4)) and (ls_Tmp = '') then begin //and (i = 1) でもよい。 //'-', '+' //sNum[i]は'-+'のどちらか。 ls_Tmp := sNum[i]; end else if (li_Pos = 5) then begin //','は無視。 end else if (li_Pos = 6) then begin //' 'は行頭なら無視、途中ならそこまで。 if (ls_Tmp <> '') then begin Break; end; end else begin Break; end; end; if (ls_Tmp = '') then begin Result := 0; end else begin if (bHexadecimal) and (ls_Tmp[1] <> '$') then begin ls_Tmp := '$' + ls_Tmp; end; Result := StrToInt64Def(ls_Tmp, 0); end; // end; end; function gfniRound(fNum: Extended): Int64; {2007-06-09: fNumを四捨五入して返す Delphiのヘルプからコピー } begin if (fNum >= 0) then begin Result := Trunc(fNum + 0.5); end else begin Result := Trunc(fNum - 0.5); end; end; function gfniNumLimit(iNum: Int64; iMin, iMax: Int64): Int64; begin if (iMin = iMax) then begin Result := iMin; end else begin //間違いの元なので気を利かせるのをやめた //l_pcNumSwap_MinMax(iMin, iMax); if (iNum < iMin) then begin Result := iMin; end else if (iNum > iMax) then begin Result := iMax; end else begin Result := iNum; end; end; end; function gfniMax(iNum: array of Integer): Integer; {2007-08-27: 引数の中の最大値を返す。 } var i: Integer; begin Result := iNum[0]; for i := 1 to High(iNum) do begin if (iNum[i] > Result) then begin Result := iNum[i]; end; end; end; function gfniMin(iNum: array of Integer): Integer; //引数の中の最小値を返す。 var i: Integer; begin Result := iNum[0]; for i := 1 to High(iNum) do begin if (iNum[i] < Result) then begin Result := iNum[i]; end; end; end; function gfnbIsInsideRange(iNum, iMin, iMax: Integer): Boolean; {2010-07-13: } begin Result := (iNum >= iMin) and (iNum <= iMax); end; //mySize.pas ------------------------------------------------------------------- function gfnrcMinRect(rcRect: array of TRect): TRect; //rcRectの重なる部分の一番狭い領域を返す。 var i: Integer; begin Result := rcRect[0]; for i := 1 to High(rcRect) do begin Result.Left := gfniMax([Result.Left, rcRect[i].Left]); Result.Top := gfniMax([Result.Top, rcRect[i].Top]); Result.Right := gfniMin([Result.Right, rcRect[i].Right]); Result.Bottom := gfniMin([Result.Bottom, rcRect[i].Bottom]); end; if (Result.Right < Result.Left) then begin Result.Right := Result.Left; end; if (Result.Bottom < Result.Top) then begin Result.Bottom := Result.Top; end; end; function gfnbEqual(ptPos1, ptPos2: TPoint): Boolean; //ptPos1とptPos2の内容が同じならTrueを返す。 begin Result := (ptPos1.X = ptPos2.X) and (ptPos1.Y = ptPos2.Y); end; //角度を返す function gfniAngleGet(ptStart, ptPos: TPoint): Integer; {2007-12-22: ptStartを原点してptPosがどの方向(角度)にあるかを返す。 ptPosがptStartからダブルクリックで許容される範囲(の三倍)内にあれば-1を返す。 それ以外は0〜359の角度を返す。 2007-12-30:どうもおかしいと思ったら Y/X ではなくX/Y としていたので修正。 http://nkiso.u-tokai.ac.jp/phys/matsuura/lecture/dyna/contents/triangle/triangle.asp } const lci_NOMOVE = 3; //マウスジェスチャーとして認識しない範囲の倍数。 var li_X, li_Y: Integer; begin li_X := ptPos.X - ptStart.X; li_Y := ptStart.Y - ptPos.Y; //数学の座標とはY軸が逆なので反対にしている。 //ドラッグ操作の開始とはみなされない範囲のlci_NOMOVE倍内であれば動いていないとみなす。 //GetSystemMetricsで得た値だとちょっとシビアな気がするので余裕を持たせるため。 if (Abs(li_X) <= (GetSystemMetrics(SM_CXDRAG) * lci_NOMOVE)) then li_X := 0; if (Abs(li_Y) <= (GetSystemMetrics(SM_CYDRAG) * lci_NOMOVE)) then li_Y := 0; if (li_X = 0) then begin if (li_Y = 0) then begin Result := -1; end else if (li_Y > 0) then begin Result := 90; end else begin Result := 270; end; end else if (li_Y = 0) then begin if (li_X > 0) then begin Result := 0; end else begin Result := 180; end; end else begin Result := gfniRound(Arctan(li_Y / li_X) * (360 / (2 * Pi))); //Arctanはラジアン単位なので度に直す if (li_X > 0) and (li_Y > 0) then begin //第一象限。 //そのまま。 end else if (li_X < 0) and (li_Y > 0) then begin //第二象限。 Inc(Result, 180); //第四象限と同じ値が出るのでプラス180度。 end else if (li_X < 0) and (li_Y < 0) then begin //第三象限。 Inc(Result, 180); //第一象限と同じ値が出るのでプラス180度。 end else //if (li_X < 0) //and (li_Y > 0) {then} begin //第四象限。 Inc(Result, 360); //マイナスの角度が出るのでぐるっと360度足しこむ。 end; end; end; function gfnsCompasGet(ptStart, ptPos: TPoint): String; {2007-12-22,2009-01-18: 上下左右を返す マウスジェスチャー用に作った。 2009-01-18:返す値を東西南北から上下左右に変更。 } var li_Angle: Integer; begin li_Angle := gfniAngleGet(ptStart, ptPos); case li_Angle of -1: Result := ''; 0.. 45: Result := '右'; 46..135: Result := '上'; 136..225: Result := '左'; 226..315: Result := '下'; 316..359: Result := '右'; else Result := ''; //保険 end; end; function gfniRectWidth (rtRect: TRect): Integer; {2007-06-09: rtRectの幅を返す } begin with rtRect do begin Result := Right - Left; end; end; function gfniRectHeight(rtRect: TRect): Integer; {2007-06-09: rtRectの高さを返す } begin with rtRect do begin Result := Bottom - Top; end; end; // myMonitor.pas --------------------------------------------------------------- procedure gpcMonitorInfoUpdate; { モニター情報が変わってもTScreenは感知しないのでTCustomForm.Monitorを呼ぶことでモ ニター情報を再作成させる。 } begin if (Application.MainForm <> nil) then begin Application.MainForm.Monitor; end; end; function gfniMonitorIndexGet(APoint: TPoint): Integer; { モニターのインデックスを取得。 APointはスクリーン座標であること。 } var i : Integer; begin //念のためモニター情報が変わっていたらモニター情報を再作成しておく gpcMonitorInfoUpdate; Result := -1; for i := 0 to Screen.MonitorCount -1 do begin if (PtInRect(Screen.Monitors[i].BoundsRect, APoint)) then begin Result := i; Exit; end; end; end; procedure gpcMonitorCenterPosSet(AWinControl: TWinControl); //ウィンドウをモニターの中心に配置 var l_Monitor : TMonitor; begin //念のためモニター情報が変わっていたらモニター情報を再作成しておく gpcMonitorInfoUpdate; l_Monitor := Screen.Monitors[gfniMonitorIndexGet(gfnptMousePosGet)]; // AWinControl.SetBounds((gfniRectWidth(l_Monitor.WorkareaRect) - AWinControl.Width) div 2, (gfniRectHeight(l_Monitor.WorkareaRect) - AWinControl.Height) div 2, AWinControl.Width, AWinControl.Height); SetWindowPos(AWinControl.Handle, HWND_TOP, (gfniRectWidth(l_Monitor.WorkareaRect) - AWinControl.Width) div 2, (gfniRectHeight(l_Monitor.WorkareaRect) - AWinControl.Height) div 2, AWinControl.Width, AWinControl.Height, 0); end; function gfnhMonitorFromRect(rcRect: TRect): HMONITOR; //rcRectの領域があるモニターのモニターハンドルを返す。 begin Result := MultiMon.MonitorFromRect(@rcRect, MONITOR_DEFAULTTONEAREST); end; function gfnrcMonitorWorkAreaRectGet(hHandle: HMONITOR): TRect; overload; //モニターのワークエリアを返す。 var lr_Info: TMonitorInfo; begin lr_Info.cbSize := SizeOf(lr_Info); GetMonitorInfo(hHandle, @lr_Info); Result := lr_Info.rcWork; end; function gfnrcMonitorWorkAreaRectGet(rcRect: TRect): TRect; overload; //rcRectの領域のあるモニターのワークエリアを返す。 begin Result := gfnrcMonitorWorkAreaRectGet(gfnhMonitorFromRect(rcRect)); end; procedure gpcSetMonitorBounds(AForm: TCustomForm; ARect: TRect); var lrc_WorkAreaRect : TRect; li_Left : Integer; li_Top : Integer; li_FormWidth : Integer; li_FormHeight : Integer; li_WorkAreaWidth : Integer; li_WorkAreaHeight : Integer; begin li_FormWidth := gfniRectWidth(ARect); li_FormHeight := gfniRectHeight(ARect); lrc_WorkAreaRect := gfnrcMonitorWorkAreaRectGet(ARect); li_WorkAreaWidth := gfniRectWidth(lrc_WorkAreaRect); li_WorkAreaHeight := gfniRectHeight(lrc_WorkAreaRect); if (li_FormWidth >= li_WorkAreaWidth) then begin li_Left := lrc_WorkAreaRect.Left; end else begin li_Left := gfniNumLimit(ARect.Left, lrc_WorkAreaRect.Left, lrc_WorkAreaRect.Left + li_WorkAreaWidth - li_FormWidth); end; if (li_FormHeight >= li_WorkAreaHeight) then begin li_Top := lrc_WorkAreaRect.Top; end else begin li_Top := gfniNumLimit(ARect.Top, lrc_WorkAreaRect.Top, lrc_WorkAreaRect.Top + li_WorkAreaHeight - li_FormHeight); end; AForm.BoundsRect := Rect(li_Left, li_Top, li_Left + li_FormWidth, li_Top + li_FormHeight); end; //myString.pas ----------------------------------------------------------------- function gfnsStrHeadFit(sSrc, sHead: String): String; {2008-03-16: sSrcの頭がsHeadでなければsHeadを足して返す。 } begin if (Copy(sSrc, 1, Length(sHead)) <> sHead) then begin Result := sHead + sSrc; end else begin Result := sSrc; end; end; function gfnsStrHeadCut(sSrc, sHead: String): String; {2009-01-19: sSrcの頭がsHeadであればsHeadを削除して返す。 } var li_Len : Integer; ls_Head : String; begin li_Len := Length(sHead); ls_Head := Copy(sSrc, 1, li_Len); if (ls_Head = sHead) then begin Result := Copy(sSrc, li_Len +1, MAXINT); end else begin Result := sSrc; end; end; function gfnsStrEndFit(sSrc, sEnd: String): String; //sSrcの末尾がsEndでなければsEndを足して返す。 begin if (Copy(sSrc, Length(sSrc) - Length(sEnd) +1, Length(sEnd)) <> sEnd) then begin Result := sSrc + sEnd; end else begin Result := sSrc; end; end; //myWindow.pas ----------------------------------------------------------------- function gfnbKeyState(iKey: Integer): Boolean; var li_Check: SHORT; begin //左右ボタンを入れ替えている場合に対処。 if (GetSystemMetrics(SM_SWAPBUTTON) <> 0) then begin if (iKey = VK_LBUTTON) then begin iKey := VK_RBUTTON; end else if (iKey = VK_RBUTTON) then begin //2009-02-04:VK_RUBTTONとしたままだったのを修正。 iKey := VK_LBUTTON; end; end; li_Check := GetAsyncKeyState(iKey); //Result := BOOL(Hi(li_Check)) and (BOOL(Lo(li_Check))); Result := BOOL(Hi(li_Check)); end; function gfnptMousePosGet: TPoint; //マウスカーソルの位置をスクリーン座標で返す。 begin // Result := Point(0, 0); // GetCursorPos(Result); if (@F_GetPhysicalCursorPos = nil) then begin GetCursorPos(Result); end else begin F_GetPhysicalCursorPos(Result); end; end; function gfnbKeyStateAnd(iKeys: array of Integer): Boolean; var i :integer; begin Result := False; for i := 0 to High(iKeys) do begin if not(gfnbKeyState(iKeys[i])) then begin Exit; end; end; Result := True; end; function gfnszWindowSizeGet(hHandle: HWND): TMyBounds; //ウィンドウのLeft, Top, Width, Heightを返す。 var lrc_Rect: TRect; lpt_Point: TPoint; lh_Parent: HWND; begin if (GetWindowRect(hHandle, lrc_Rect)) then begin //2010-10-15:GetAncestor API使用に切り替え。 // lh_Parent := GetParent(hHandle); lh_Parent := gfnhParentWindowGet(hHandle); lpt_Point := lrc_Rect.TopLeft; if (lh_Parent <> 0) and (ScreenToClient(lh_Parent, lpt_Point)) then begin Result.Left := lpt_Point.X; Result.Top := lpt_Point.Y; end else begin Result.Left := lrc_Rect.Left; Result.Top := lrc_Rect.Top; end; Result.Width := lrc_Rect.Right - lrc_Rect.Left; Result.Height := lrc_Rect.Bottom - lrc_Rect.Top; end else begin Result.Left := 0; Result.Top := 0; Result.Width := 0; Result.Height := 0; end; end; function gfnhParentWindowGet(hHandle: HWND): HWND; //親Windowを返す。 begin Result := GetAncestor(hHandle, GA_PARENT); //親ウィンドウ。hHandleがトップレベルウィンドウの場合GetDesktopWindowの値が返る。 // Result := GetParent(hHandle); end; function gfnsClassNameGet(hHandle: HWND): String; //ウィンドウハンドルhHandleのクラス名を返す。 const lci_LEN = 255; var lp_Buff: PChar; begin Result := ''; lp_Buff := AllocMem((lci_LEN +1) * SizeOf(Char)); try GetClassName(hHandle, lp_Buff, lci_LEN); Result := String(lp_Buff); finally FreeMem(lp_Buff); end; end; function gfnsWindowTextGet(hHandle: HWND; bFast: Boolean = False): String; {,2015-05-31: 2015-05-31:ListBoxとComboBoxのテキスト取得に対応。 ウィンドウハンドルhHandleのテキスト(キャプション)を返す。 } var li_Len : DWORD; lp_Buff : PChar; li_Index : DWORD; begin Result := ''; li_Len := GetWindowTextLength(hHandle); if (li_Len > 0) then begin Inc(li_Len); lp_Buff := AllocMem(li_Len * SizeOf(Char)); try GetWindowText(hHandle, lp_Buff, li_Len); Result := String(lp_Buff); finally FreeMem(lp_Buff); end; Exit; end; if (bFast) then begin Exit; end; //他のアプリケーションのエディットボックス用。 if (SendMessageTimeout(hHandle, WM_GETTEXTLENGTH, 0, 0, SMTO_ABORTIFHUNG, 500, li_Len) <> 0) then begin if (li_Len > 0) then begin Inc(li_Len); lp_Buff := AllocMem(li_Len * SizeOf(Char)); try SendMessageTimeout(hHandle, WM_GETTEXT, WPARAM(li_Len), LPARAM(lp_Buff), SMTO_ABORTIFHUNG, 500, li_Len); Result := String(lp_Buff); finally FreeMem(lp_Buff); end; Exit; end; end; //リストボックス用。 //現在の選択行を取得。 if (SendMessageTimeout(hHandle, LB_GETCURSEL, 0, 0, SMTO_ABORTIFHUNG, 500, li_Index) <> 0) then begin if (li_Index = DWORD(LB_ERR)) then begin li_Index := 0; end; end; //現在の選択行の文字数を取得。 if (SendMessageTimeout(hHandle, LB_GETTEXTLEN, li_Index, 0, SMTO_ABORTIFHUNG, 500, li_Len) <> 0) then begin //エラーなら抜ける。 if (li_Len = DWORD(LB_ERR)) then begin Exit; end; if (li_Len > 0) then begin Inc(li_Len); lp_Buff := AllocMem(li_Len * SizeOf(Char)); try if (SendMessageTimeout(hHandle, LB_GETTEXT, WPARAM(li_Index), LPARAM(lp_Buff), SMTO_ABORTIFHUNG, 500, li_Len) <> 0) then begin Result := String(lp_Buff); end; finally FreeMem(lp_Buff); end; Exit; end; end; //コンボボックス用 //現在の選択行を取得。 if (SendMessageTimeout(hHandle, CB_GETCURSEL, 0, 0, SMTO_ABORTIFHUNG, 500, li_Index) <> 0) then begin if (li_Index = DWORD(LB_ERR)) then begin li_Index := 0; end; end; if (SendMessageTimeout(hHandle, CB_GETLBTEXTLEN, li_Index, 0, SMTO_ABORTIFHUNG, 500, li_Len) <> 0) then begin if (li_Len = DWORD(LB_ERR)) then begin Exit; end; if (li_Len > 0) then begin Inc(li_Len); lp_Buff := AllocMem(li_Len * SizeOf(Char)); try if (SendMessageTimeout(hHandle, CB_GETLBTEXT, WPARAM(li_Index), LPARAM(lp_Buff), SMTO_ABORTIFHUNG, 500, li_Len) <> 0) then begin Result := String(lp_Buff); end; finally FreeMem(lp_Buff); end; end; end; end; function gfnrcClientRectGet(hHandle: HWND): TRect; begin Result := Rect(0, 0, 0, 0); GetClientRect(hHandle, Result); end; function gfnptClientToScreen(hHandle: HWND): TPoint; {2007-08-21: ウィンドウのクライアント領域の原点をスクリーン座標に変換して返す } begin Result := Point(0, 0); Windows.ClientToScreen(hHandle, Result); end; function gfnptScreenToClient(hHandle: HWND; ptPos: TPoint): TPoint; {2009-03-08: ptPosをhHandleのウィンドウのクライアント座標で返す。 } begin Result := ptPos; if (IsWindow(hHandle)) then begin ScreenToClient(hHandle, Result); end; end; function gfnhProcessToWindow(hWindow: HWND; hProcess: THandle): HWND; { プロセスのハンドルからプロセスのトップレベルウィンドウのハンドルを取得して返す。 トップレベルウィンドウが複数ある場合は一番手前にあるウィンドウのハンドルが返る。 実行ファイルのウィンドウハンドルを取得する場合は実行後WaitForInputIdleで初期化処 理を終了するまで待ってからでないと取得に失敗する。 } var lh_Handle : THandle; lh_SelfPID : DWORD; l_Info : TProcessEntry32; begin Result := 0; FillChar(l_Info, SizeOf(l_Info), 0); l_Info.dwSize := Sizeof(l_Info); lh_Handle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, hProcess); try if (Process32First(lh_Handle, l_Info)) then begin lh_SelfPID := gfniProcessIDGet(hWindow); repeat //myDebug.gpcDebug([String(l_Info.szExeFile), l_Info.th32ParentProcessID, gfniProcessIDGet(Self.Handle)]); if (l_Info.th32ParentProcessID = lh_SelfPID) then begin Result := gfnhPIDToWindow(l_Info.th32ProcessID); end; until not(Process32NextW(lh_Handle, l_Info)); end; finally CloseHandle(lh_Handle); end; end; function gfnhProcessToWindow(hProcess: THandle): HWND; begin Result := gfnhProcessToWindow(Application.Handle, hProcess); end; function gfnsSystem32DirGet: String; var li_Size: UINT; lp_Buff: PChar; begin Result := ''; li_Size := GetSystemDirectory(nil, 0); if (li_Size > 0) then begin lp_Buff := AllocMem(li_Size * SizeOf(Char)); try li_Size := GetSystemDirectory(lp_Buff, li_Size); if (li_Size > 0) then begin Result := gfnsStrEndFit(String(lp_Buff), '\'); end; finally FreeMem(lp_Buff); end; end; end; type TDwmIsCompositionEnabled = function(var bBool: BOOL): HResult stdcall; //function DwmIsCompositionEnabled(var bBool: BOOL) : HResult; stdcall external 'Dwmapi.dll'; function DwmIsCompositionEnabled(var bBool : BOOL) : HResult; var ls_Path : String; lh_Module : HMODULE; l_DwmIsCompositionEnabled : TDwmIsCompositionEnabled; begin Result := E_NOTIMPL; bBool := False; ls_Path := gfnsSystem32DirGet; lh_Module := LoadLibrary(PChar(ls_Path + 'Dwmapi.dll')); if (lh_Module <> 0) then begin try // DwmIsCompositionEnabled の関数ポインタを取得。 @l_DwmIsCompositionEnabled := GetProcAddress(lh_Module, 'DwmIsCompositionEnabled'); if (@l_DwmIsCompositionEnabled <> nil) then begin Result := l_DwmIsCompositionEnabled(bBool); end; finally FreeLibrary(lh_Module); end; end; end; function gfnbIsAeroActive : Boolean; var lb_IsAero : BOOL; begin DwmIsCompositionEnabled(lb_IsAero); Result := lb_IsAero; end; function gfnrcBasicWindowRectGet(hHandle: HWND): TRect; {2013-11-17: ウィンドウのRectを返す。 } begin Result := Rect(0, 0, 0, 0); GetWindowRect(hHandle, Result); end; //http://www.delphipraxis.net/159936-form-mit-bssingle-unter-aero-zu-gross.html const DWMWA_EXTENDED_FRAME_BOUNDS = 9; //function DwmGetWindowAttribute(hwnd: HWND; dwAttribute: DWORD; pvAttribute: Pointer; cbAttribute: DWORD): HResult; stdcall; external 'Dwmapi.dll'; type TDwmGetWindowAttribute = function(hwnd: HWND; dwAttribute: DWORD; pvAttribute: Pointer; cbAttribute: DWORD): HResult; stdcall; function gfnrcAeroWindowRectGet(hHandle: HWND): TRect; {2013-11-17: } var ls_Path : String; lh_Module : HMODULE; l_DwmGetWindowAttribute : TDwmGetWindowAttribute; li_Ret : HRESULT; begin Result := Rect(0, 0, 0, 0); // Result := gfnrcBasicWindowRectGet(hHandle); ls_Path := gfnsSystem32DirGet; lh_Module := LoadLibrary(PChar(ls_Path + 'Dwmapi.dll')); if (lh_Module <> 0) then begin try // DwmGetWindowAttribute の関数ポインタを取得 @l_DwmGetWindowAttribute := GetProcAddress(lh_Module, 'DwmGetWindowAttribute'); if (@l_DwmGetWindowAttribute <> nil) then begin li_Ret := l_DwmGetWindowAttribute( hHandle, DWMWA_EXTENDED_FRAME_BOUNDS, @Result, SizeOf(TRect) ); if not(Succeeded(li_Ret)) then begin Result := gfnrcBasicWindowRectGet(hHandle); end; end; finally FreeLibrary(lh_Module); end; end; end; //http://www.delphipraxis.net/142052-getlayeredwindowattributes-funktioniert-nicht-noch-resize.html //function GetLayeredWindowAttributes(hwnd: HWND; var crKey: COLORREF; var bAlpha: BYTE; var dwFlags: DWORD): BOOL; stdcall; external user32 name 'GetLayeredWindowAttributes'; type TGetLayeredWindowAttributes = function(hwnd: HWND; var crKey: COLORREF; var bAlpha: BYTE; var dwFlags: DWORD): BOOL; stdcall; function gfnbGetLayeredWindowAttributes(hHandle: HWND; var crKey: COLORREF; var bAlpha: BYTE; var dwFlags: DWORD): Boolean; {2015-03-10: } var ls_Path : String; lh_Module : HMODULE; l_GetLayeredWindowAttributes : TGetLayeredWindowAttributes; begin Result := False; ls_Path := gfnsSystem32DirGet; lh_Module := LoadLibrary(PChar(ls_Path + 'user32.dll')); if (lh_Module <> 0) then begin try // GetLayeredWindowAttributes の関数ポインタを取得 @l_GetLayeredWindowAttributes := GetProcAddress(lh_Module, 'GetLayeredWindowAttributes'); if (@l_GetLayeredWindowAttributes <> nil) then begin Result := l_GetLayeredWindowAttributes( hHandle, crKey, bAlpha, dwFlags ); end; finally FreeLibrary(lh_Module); end; end; end; function gfnrcWindowRectGet(hHandle: HWND): TRect; {2008-12-31,2013-11-17: 2013-11-17:Aero テーマに対応。以前のものはgfnrcBasicWindowRectGetとした。 ウィンドウのRectを返す。 } begin if (gfnbIsAeroActive) then begin Result := gfnrcAeroWindowRectGet(hHandle); end else begin Result := gfnrcBasicWindowRectGet(hHandle); end; end; function gfniProcessIDGet(hHandle: HWND): DWORD; begin GetWindowThreadProcessId(hHandle, @Result); end; type TGetProcessImageFileName = function(hProcess: THandle; lpImageFileName: LPWSTR; nSize: DWORD): DWORD; stdcall; //function GetProcessImageFileNameW(hProcess: THandle; lpImageFileName: LPWSTR; nSize: DWORD): DWORD; stdcall; external 'Psapi.dll'; function gfnsExeNameGet(hHandle: HWND): String; { ウィンドウハンドルからexeファイル名を返す http://m--takahashi.com/bbs/pastlog/02500/02414.html http://www.geocities.jp/fjtkt/problems/2003_0004.html http://www2.big.or.jp/~osamu/Delphi/tips.cgi?index=0182.txt http://homepage1.nifty.com/MADIA/delphi/Win32API/Process.htm http://rarara.cafe.coocan.jp/cgi-bin/lng/vc/vclng.cgi?print+201010/10100011.txt http://www14.big.or.jp/~ken1/tech/tech11.html } function _ProcessIDGet(hHandle: HWND): DWORD; begin GetWindowThreadProcessId(hHandle, @Result); end; var lh_Process : THandle; lp_Buff : PChar; i : Integer; li_Drives : DWORD; li_Flag : Integer; ls_Device : String; lp_Device : PChar; ls_Drv : String; ls_Path : String; lh_Module : HMODULE; l_GetProcessImageFileName : TGetProcessImageFileName; begin Result := ''; lh_Process := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, _ProcessIDGet(hHandle)); try lp_Buff := AllocMem((MAX_PATH +1) * SizeOf(Char)); try //プロセスハンドルを渡すだけで実行ファイル名を得られた。インスタンスハンドルはいらないようだ。 if (GetModuleFileNameEx(lh_Process, 0, lp_Buff, MAX_PATH) <> 0) then begin Result := String(lp_Buff); end else begin { //EnumProcessModulesは32bitプロセスから64bitプロセスのモジュールハンドルを取得できない。 if (EnumProcessModules(lh_Process, @lh_Module, SizeOf(HMODULE), li_Num)) then begin FillChar(l_Info, SizeOf(l_Info), 0); if (GetModuleInformation(lh_Process, lh_Module, @l_Info, SizeOf(l_Info))) then begin if (GetMappedFileName(lh_Process, l_Info.EntryPoint, lp_Buff, MAX_PATH) <> 0) then begin Result := String(lp_Buff); end; end; end; } //GetModuleFileNameExは32bitプロセスから64bitプロセスの実行ファイル名を取得できない。 //システムディレクトリを取得 ls_Path := gfnsSystem32DirGet; //完全修飾パスを指定してPsapi.dllをロード lh_Module := LoadLibrary(PChar(ls_Path + 'Psapi.dll')); if (lh_Module <> 0) then begin try //GetProcessImageFileNameの関数ポインタを取得 @l_GetProcessImageFileName := GetProcAddress(lh_Module, 'GetProcessImageFileNameW'); if (@l_GetProcessImageFileName <> nil) then begin l_GetProcessImageFileName(lh_Process, lp_Buff, MAX_PATH); Result := String(lp_Buff); end; finally FreeLibrary(lh_Module); end; if (Result <> '') then begin li_Drives := GetLogicalDrives; li_Flag := 1; for i := Ord('A') to Ord('Z') do begin if ((li_Drives and li_Flag) <> 0) then begin //_myDebug.gpcDebug(Chr(i)); lp_Device := nil; try lp_Device := AllocMem((MAX_PATH +1) * SizeOf(Char)); ls_Drv := String(Char(i)) + ':'; QueryDosDevice(PChar(ls_Drv), lp_Device, MAX_PATH); ls_Device := String(lp_Device); //_myDebug.gpcDebug(ls_Device); if (Pos(ls_Device + '\', Result) = 1) then begin Result := ls_Drv + Copy(Result, Length(ls_Device) +1, MaxInt); Break; end; finally FreeMem(lp_Device); end; end; li_Flag := li_Flag shl 1; end; end; end; end; finally FreeMem(lp_Buff); end; finally CloseHandle(lh_Process); end; end; function gfnhToplevelWindowGet(hHandle: HWND): HWND; {2007-06-12: トップレベルウィンドウを返す。 } begin Result := GetAncestor(hHandle, GA_ROOT); end; function gfnhToplevelWindowGet(ptPos: TPoint): HWND; //gfnhToplevelWindowGetのTPoint版。 begin //WindowFromPointは見えている一番手前のウィンドウハンドルを返す。 //一番手前のウィンドウが無効な場合は無効なウィンドウの親ウィンドウのハンドルを返す。 //トップレベルウィンドウが無効な場合はトップレベルウィンドウのハンドルを返す。 // Result := GetAncestor(WindowFromPoint(ptPos), GA_ROOT); Result := GetAncestor(gfnhWindowGet(ptPos), GA_ROOT); end; (* //APoint上にある可視ウィンドウを返す。 type T_TopWindow = record hWindow : HWND; //調べる点の上にあるウィンドウ ptPos : TPoint; //この位置にある一番手前の見えているウィンドウを取得する end; P_TopWindow = ^T_TopWindow; function EnumChildProc(hHandle: HWND; pTopWindow: Pointer): BOOL; stdcall; var lh_Parent : HWND; lrc_Rect : TRect; begin Result := True; GetWindowRect(hHandle, lrc_Rect); if (IsWindowVisible(hHandle)) and (PtInRect(lrc_Rect, T_TopWindow(pTopWindow^).ptPos)) then begin lh_Parent := GetAncestor(hHandle, GA_PARENT); if (lh_Parent = T_TopWindow(pTopWindow^).hWindow) then begin //直前に列挙された対象ウィンドウの子ウィンドウだった //hWindowを書き換える //子ウィンドウがあるかもしれないので処理を続ける T_TopWindow(pTopWindow^).hWindow := hHandle; end else begin //親ウィンドウが同じなら兄弟ウィンドウ。 //しかし列挙されるのは手前のウィンドウからなのでその場合はhTopは書き換ず処理を抜ける。 //親ウィンドウが直前のウィンドウでもない //おじさんおばさんウィンドウ、あるいはさらに遡ってのウィンドウであるのでこれまたhTopを書き換えず処理を抜ける Result := False; end; end; end; function gfnhWindowGet(APoint : TPoint) : HWND; //APoint上にあり一番手前にある見えているウィンドウのハンドルを返す。 var lr_TopWindow : T_TopWindow; lh_Window, lh_CWindow : HWND; lpt_Client : TPoint; begin //WindowFromPointはAPointが無効ウィンドウ上にある場合はトップレベルウィンドウのハンドルを返す。 lh_Window := WindowFromPoint(APoint); lpt_Client := APoint; Windows.ScreenToClient(lh_Window, lpt_Client); lh_CWindow := ChildWindowFromPointEx(lh_Window, lpt_Client, CWP_SKIPINVISIBLE or CWP_SKIPTRANSPARENT); if (lh_Window = lh_CWindow) then begin //WindowFromPointとChildWindowFromPointExの戻り値が同じならそれで良い。 Result := lh_Window; end else begin FillChar(lr_TopWindow, SizeOf(lr_TopWindow), 0); lr_TopWindow.hWindow := lh_Window; lr_TopWindow.ptPos := APoint; EnumChildWindows(lh_Window, @EnumChildProc, LPARAM(@lr_TopWindow)); Result := lr_TopWindow.hWindow; end; end; *) //ptPosの点上にある可視ウィンドウを返す。 type T_TopWindow = record hTop : HWND; pPoint : TPoint; end; P_TopWindow = ^T_TopWindow; function _EnumChildProc(hHandle: HWND; pTopWindow: Pointer): BOOL; stdcall; var lh_Parent: HWND; begin Result := True; if (IsWindowVisible(hHandle)) and (PtInRect(gfnrcWindowRectGet(hHandle), T_TopWindow(pTopWindow^).pPoint)) then begin lh_Parent := gfnhParentWindowGet(hHandle); if (lh_Parent = T_TopWindow(pTopWindow^).hTop) then begin //直前に列挙された対象ウィンドウの子ウィンドウだった //hTopとhParentを書き換える //子ウィンドウがあるかもしれないので処理を続ける T_TopWindow(pTopWindow^).hTop := hHandle; end else begin //親ウィンドウが同じなら兄弟ウィンドウ。 //しかし列挙されるのは手前のウィンドウからなのでその場合はhTopは書き換ず処理を抜ける。 //親ウィンドウが直前のウィンドウでもない //おじさんおばさんウィンドウ、あるいはさらに遡ってのウィンドウであるのでこれまたhTopを書き換えず処理を抜ける Result := False; end; end; end; function _EnumWindowsProc(hHandle: HWND; pTopWindow: Pointer):BOOL; stdcall; //トップレベルウィンドウを列挙する var lrg_Region: HRGN; lpt_Pos: TPoint; lrc_Rect, lrc_Client: TRect; begin lrc_Rect := gfnrcWindowRectGet(hHandle); if (IsWindowVisible(hHandle)) //可視ウィンドウのみ // and (PtInRect(lrc_Rect, FrDispInfo.ptMousePos)) //ウィンドウのRect内にマウスカーソルがある and (PtInRect(lrc_Rect, T_TopWindow(pTopWindow^).pPoint)) //ウィンドウのRect内にマウスカーソルがある then begin Result := False; lrg_Region := CreateRectRgn(0, 0, 0, 0); try if (GetWindowRgn(hHandle, lrg_Region) <> ERROR) then begin lpt_Pos.X := T_TopWindow(pTopWindow^).pPoint.X - lrc_Rect.Left; lpt_Pos.Y := T_TopWindow(pTopWindow^).pPoint.Y - lrc_Rect.Top; if (PtInRegion(lrg_Region, lpt_Pos.X, lpt_Pos.Y)) then begin //リージョン内だったので処理を抜ける end else begin //リージョン外だったので処理を続ける Result := True; end; end; finally DeleteObject(lrg_Region); end; if (Result = False) then begin T_TopWindow(pTopWindow^).hTop := hHandle; lrc_Client := gfnrcClientRectGet(hHandle); if (lrc_Client.Right > 0) or (lrc_Client.Bottom > 0) then begin EnumChildWindows(hHandle, @_EnumChildProc, LPARAM(pTopWindow)); end; end; end else begin Result := True; end; end; function gfnhWindowGet(APoint: TPoint): HWND; overload; var lr_TopWindow : T_TopWindow; lh_Toplevel : HWND; li_ExStyle : DWORD; li_ColorKey : COLORREF; li_Alpha : Byte; li_Flag : DWORD; begin Result := WindowFromPoint(APoint); { if (Result = ChildWindowFromPoint(Result, gfnptScreenToClient(Result, ptPos))) then begin Exit; end; } FillChar(lr_TopWindow, SizeOf(lr_TopWindow), 0); lr_TopWindow.pPoint := APoint; EnumWindows(@_EnumWindowsProc, LPARAM(@lr_TopWindow)); //WindowFromPoint APIで取得したハンドルとEnumWindows APIで取得したハンドルを比較する。 if (Result <> lr_TopWindow.hTop) then begin //違っていたらEnumWindows APIで取得したウィンドウのスタイルを調べる。 //WS_EX_TRANSPARENTとWS_EX_LAYEREDが同時にセットされていたら見えていても //WindowFromPoint APIでは取得できないウィンドウなのでこちらを返す。 lh_Toplevel := GetAncestor(lr_TopWindow.hTop, GA_ROOT); li_ExStyle := GetWindowLong(lh_Toplevel, GWL_EXSTYLE); if ((li_ExStyle and WS_EX_LAYERED) = WS_EX_LAYERED) and ((li_ExStyle and WS_EX_TRANSPARENT) = WS_EX_TRANSPARENT) then begin if (gfnbGetLayeredWindowAttributes(lh_Toplevel, li_ColorKey, li_Alpha, li_Flag)) then begin if ((li_Flag and LWA_ALPHA) = LWA_ALPHA) and (li_Alpha = 0) then begin Exit; end; end; Result := lr_TopWindow.hTop; end; end; end; function gfnhOwnerWindowGet(hHandle: HWND): HWND; //オーナーWindowを返す。 begin Result := GetWindow(GetAncestor(hHandle, GA_ROOT), GW_OWNER); end; var lhPIDToWindowHandle: HWND; function gfnhPIDToWindow(iProcessID: DWORD): HWND; {2010-07-29: PIDからトップレベルウィンドウのウィンドウハンドルを返す。 } function l_fnbEnumWindowProc(hHandle: HWND; iParam: LPARAM): BOOL; stdcall; //戻り値はBooleanではなくBOOLである必要あり begin if (gfniProcessIDGet(hHandle) = DWORD(iParam)) then begin lhPIDToWindowHandle := hHandle; Result := False; end else begin Result := True; end; end; begin lhPIDToWindowHandle := 0; EnumWindows(@l_fnbEnumWindowProc, iProcessID); Result := lhPIDToWindowHandle; end; // sub_api.pas --------------------------------------------------------------------- function gfniCanvasTextWidthGet(AFont: TFont; sText: String; iCharExtra: Integer = 0): Integer; {2009-10-28, 2011-03-01: 2011-03-01:行間指定に対応。 } var l_Bitmap : TBitmap; begin l_Bitmap:= TBitmap.Create; try l_Bitmap.Canvas.Font.Assign(AFont); SetTextCharacterExtra(l_Bitmap.Canvas.Handle, iCharExtra); Result := l_Bitmap.Canvas.TextWidth(sText); finally l_Bitmap.Free; end; end; function gfniCanvasTextHeightGet(AFont: TFont; sText: String; iCharExtra: Integer = 0): Integer; {2009-10-28, 2011-03-01: 2011-03-01:行間指定に対応。 } var l_Bitmap : TBitmap; begin l_Bitmap:= TBitmap.Create; try l_Bitmap.Canvas.Font.Assign(AFont); SetTextCharacterExtra(l_Bitmap.Canvas.Handle, iCharExtra); Result := l_Bitmap.Canvas.TextHeight(sText); finally l_Bitmap.Free; end; end; //------------------------------------------------------------------------------ //スタイル function gfnbFlagCheck(iStyle: Longint; iCheck: Longint): Boolean; begin Result := ((iStyle and iCheck) = iCheck); end; //------------------------------------------------------------------------------ initialization //GetPhysicalCursorPos F_hUser32_dllModule := LoadLibraryW(PWideChar(gfnsSystem32DirGet + 'User32.dll')); if (F_hUser32_dllModule <> 0) then begin // GetPhysicalCursorPos の関数ポインタを取得 @F_GetPhysicalCursorPos := GetProcAddress(F_hUser32_dllModule, 'GetPhysicalCursorPos'); end else begin F_GetPhysicalCursorPos := nil; end; (* //LogicalToPhysicalPoint if (F_hUser32_dllModule <> 0) then begin // LogicalToPhysicalPoint の関数ポインタを取得 @F_LogicalToPhysicalPoint := GetProcAddress(F_hLogicalToPhysicalPointModule, 'LogicalToPhysicalPoint'); end else begin F_LogicalToPhysicalPoint := nil; end; //PhysicalToLogicalPoint if (F_hUser32_dllModule <> 0) then begin // PhysicalToLogicalPoint の関数ポインタを取得 @F_PhysicalToLogicalPoint := GetProcAddress(F_hPhysicalToLogicalPointModule, 'PhysicalToLogicalPoint'); end else begin F_LogicalToPhysicalPoint := nil; end; *) finalization //LogicalToPhysicalPoint FreeLibrary(F_hUser32_dllModule); end.