DcadCapture ver.2015.5.3 for DraftSight 2015 / ARES Commander 2015
※ARES は廉価版でも COM API (ActiveX) が使えます。そちらを使ったほうがスマートです。
Bricscad 用のキャプチャーソフトを DraftSight / ARES 用に改造してみました。
キャプチャーした図面イメージをダブルクリックすると、CADの図面が切り替わります。
フォームの大きさは、自由に変更できます。
・コマンドラインに文字列を流し込む方法なので、タイミングが合わない場合があります。
・クリップボードを使用してコマンド履歴を取得しているため、操作後は、クリップボードに文字列が残ります。
・図面の切り替えは、メニューを操作しています。
取得した時の図面数と、「メニュー」 - 「ウィンドウ」の図面数が合わない場合は、「閉じる」、「すべて閉じる」が選択される可能性があります。
※ARES では、「Classic Default」 表示にしておいて下さい。
・高解像度のPCでは、キャプチャー位置が合わないときがあります。DcadCapture.exe のプロパティーから、「高解像度DPI...」にチェックを付けて下さい。
・各所にタイミングをとるためのタイマーを入れているため、取得にかなり時間がかかります。
( 2015/5/3 :若干改善しました。23図面 130sec -> 45sec)
■履歴
2015/04/22
・初版作成
2015/04/28
・シート番号、またはページ番号を取得するを追加
・マウス右クリックのポップアップメニューに「再キャプチャ」を追加
2015/04/28(2回目)
・システム変数の取得を、属性と同様にDXFファイルから取得に変更。若干高速にした。
2015/05/03
・コマンド送信で、[Enter]、[ESC] の送信を追加。
・不要なタイミングタイマーを極力省いた。
■Draftsight 2015
■ARES Commander 2015
■ダウンロード
DcadCapture.zip (2015/05/03 EXE本体のみ)
■ソースコード
unit DcadCaptureUnit; interface uses Winapi . Windows, Winapi . Messages, System . SysUtils, System . Variants, System . Classes, Vcl . Graphics, Vcl . Controls, Vcl . Forms, Vcl . Dialogs, {BricscadApp_TLB, BricscadDb_TLB,} Vcl . StdCtrls, Vcl . ExtCtrls, Vcl . Grids, ComObj, IniFiles, Vcl . Buttons, Vcl . Menus, ClipBrd ; type TDwgDoc = record Index : integer ; Name : string ; Comment : string ; end ; type TForm2 = class (TForm) DrawGrid1: TDrawGrid; Panel1: TPanel; ComboBox1: TComboBox; SpeedButton1: TSpeedButton; PopupMenu1: TPopupMenu; N3: TMenuItem; N1: TMenuItem; N2: TMenuItem; SpeedButton2: TSpeedButton; SpeedButton3: TSpeedButton; N4: TMenuItem; N5: TMenuItem; Edit1: TEdit; SpeedButton4: TSpeedButton; procedure FormDestroy(Sender: TObject); procedure DrawGrid1DrawCell(Sender: TObject; ACol, ARow: Integer ; Rect: TRect; State: TGridDrawState); procedure FormResize(Sender: TObject); procedure DrawGrid1DblClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure ComboBox1Change(Sender: TObject); procedure SpeedButton1Click(Sender: TObject); procedure N3Click(Sender: TObject); procedure N2Click(Sender: TObject); procedure SpeedButton2Click(Sender: TObject); procedure SpeedButton3Click(Sender: TObject); procedure DrawGrid1Click(Sender: TObject); procedure DrawGrid1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer ); procedure N5Click(Sender: TObject); procedure SpeedButton4Click(Sender: TObject); private { Private 宣言 } public { Public 宣言 } // 取得するブロック名と属性名 BlkName, BlkName1, BlkName2, AttName, AttName1, AttName2 : string ; AttFlag1, AttFlag2 : boolean ; // 連続実行するLISP LspFileName : TFileName; LspCmdName : string ; LspCommand : string ; MoveX, MoveY : integer ; end ; var Form2: TForm2; // キャプチャしたビットマップを保持 BmpAry : array of TBitMap; // 図面名とその位置を保持 DwgDocAry : array of TDwgDoc; // ビットマップの大きさ BmpW, BmpH : integer ; // タイトル表示の高さ TitleH1, TitleH2 : integer ; // シート名、ページ番号を表示する CmtDispFlag : boolean ; // キャプチャ時、属性を取得 CmtGetFlag : boolean ; BcadActiveFlag : boolean ; // メインウィンドウ DcadMainWinHandle : HWND; DcadMDIClientWinHandle : HWND; DcadCommandWinHandle : HWND; DcadInputWinHandle : HWND; DcadOutputWinHandle : HWND; DcadMDIActiveWinHandle : HWND; DcadMDIChildWinHandle : HWND; DCadProcessID : DWORD; //プロセスID implementation {$R *.dfm} uses DcadCaptureCfgUnit; //**************************************** // 最後の指定文字列より後を得る //**************************************** function LastSubstringAfter( const ststr, s: string ): String ; var st, stlen : integer ; temp : string ; begin Result := '' ; if Pos(ststr, s) > 0 then begin temp := s; stlen := Length(ststr); while Pos(ststr, temp) > 0 do begin st := Pos(ststr, temp) + stlen; temp := Copy(temp, st, Length(temp) - st + 1 ); if temp = '' then break; end ; Result := Trim(temp); end ; end ; //**************************************** //最初に現れたststrからedstrまでを返す //**************************************** function StrAfterStrBefore( const ststr, edstr, s: string ): String ; var st, ed: integer ; temp : string ; begin Result:= '' ; st:=Pos(ststr,s); if st > 0 then begin temp := s; Delete(temp, 1 ,st + Length(ststr)- 1 ); ed := Pos(edstr, temp)- 1 ; if ed >= 0 then Result := Trim(Copy(temp, 1 , ed)); end ; end ; //**************************************** // 最後の指定文字列より後を得る //**************************************** function LastStrAfter( const ststr, s: string ): String ; var st, stlen : integer ; temp : string ; begin Result := '' ; if Pos(ststr, s) > 0 then begin temp := s; stlen := Length(ststr); while Pos(ststr, temp) > 0 do begin st := Pos(ststr, temp) + stlen; temp := Copy(temp, st, Length(temp) - st + 1 ); if temp = '' then break; end ; Result := Trim(temp); end ; end ; //****************************************** // ウィンドウのタイトル(キャプション)を得る //****************************************** function GetWindowCaption(h : HWND) : string ; var Title : array [ 0..255 ] of char ; begin result := '' ; if GetWindowText(h, Title, 255 ) <> 0 then result := Title; end ; //**************************************** // メインウィンドウ用コールバック関数 //**************************************** function EnumWindowProcMainWin(h: HWND; lp: LParam): BOOL; stdcall; var Title : array [ 0..255 ] of char ; ClassName : array [ 0..255 ] of char ; begin Result := true ; GetClassName(h, ClassName, 255 ); if 'Qt5QWindowIcon' = ClassName then begin // タイトルを得る if GetWindowText(h, Title, 255 ) <> 0 then begin if (Pos( 'DraftSight - [' , Title) = 1 ) or (Pos( 'ARES Commander 2015 - [' , Title) = 1 ) then begin DCadMainWinHandle := h; GetWindowThreadProcessId(h, @DCadProcessID); Result := false ; end ; end ; end ; end ; //**************************************** // メインウィンドウのハンドルを得る //**************************************** function GetDCadMainWinHandle : HWND; begin EnumWindows(@EnumWindowProcMainWin, 0 ); Result := DCadMainWinHandle; end ; // ************************************ // MDIClientウィンドウ取得用コールバック関数 // ************************************ function EnumCWinProc_MDIClient(h:HWND;lparam: Integer ):Bool;stdcall; var Title : array [ 0..255 ] of char ; begin Result:= True ; if GetWindowText(h, Title, 255 ) <> 0 then begin if 'CFxWorkspaceImplClassWindow' = Title then begin DcadMDIClientWinHandle := GetWindow(h, GW_CHILD); DcadMDIChildWinHandle := GetWindow(DcadMDIClientWinHandle, GW_CHILD); Result := False ; end ; end ; end ; // ************************************ // MDIClientウィンドウ取得 // 実際には、WindowsのMDIClientでは無い // ************************************ function GetDcadMDIClientHandle:HWND; begin EnumChildWindows(DcadMainWinHandle,@EnumCwinProc_MDIClient, 0 ); result:=DcadMDIClientWinHandle; end ; // ************************************ // コマンドウィンドウ取得用コールバック関数 // ************************************ function EnumCWinProc_CommandWinHandle(h: HWND; lparam: Integer ):Bool;stdcall; var Title : array [ 0..255 ] of char ; begin Result:= True ; if GetWindowText(h, Title, 255 ) <> 0 then begin if 'CFxCommandWindowWindow' = Title then begin DcadCommandWinHandle := h; Result:= False ; end ; end ; end ; // ************************************ // コマンドラインウィンドウを取得 // ************************************ function GetDcadCommandWinHandle:HWND; begin EnumChildWindows(DcadMainWinHandle, @EnumCwinProc_CommandWinHandle, 0 ); result := DcadCommandWinHandle; if result <> 0 then begin DcadOutputWinHandle := GetWindow(DcadCommandWinHandle, GW_CHILD); DcadInputWinHandle := GetWindow(DcadOutputWinHandle, GW_HWNDNEXT); end ; end ; // ************************************ // 対象ウィンドウに文字列を送信 // ************************************ function SendHwndCmdLine(hCmdLine: HWND; const cmd : string ): boolean ; var i : integer ; begin Result := False ; if hCmdLine <> 0 then begin // 文字列を送信 for i := 1 to Length(cmd) do begin if cmd[i] = # 13 then begin SendMessage(hCmdLine, WM_KEYDOWN,VK_RETURN, 0 ); SendMessage(hCmdLine, WM_KEYUP, VK_RETURN, 0 ); Sleep( 1 ); end else if (cmd[i] = # 27 ) or (cmd[i] = # 3 ) then begin SendMessage(hCmdLine, WM_KEYDOWN, VK_ESCAPE, 0 ); SendMessage(hCmdLine, WM_KEYUP, VK_ESCAPE, 0 ); Sleep( 1 ); end else begin SendMessage(hCmdLine, WM_CHAR, Word (cmd[i]), 0 ); if cmd[i] = # 20 then Sleep( 1 ); end ; end ; result := true ; end ; end ; // ************************************ // コマンドラインに文字列を送信 // ************************************ function SendDcadCommand( const cmd: string ): boolean ; begin GetDcadCommandWinHandle; Result := SendHwndCmdLine(DcadInputWinHandle, cmd); end ; function GetDcadVariable( const SysVar: string ): string ; var s : string ; begin Result := '' ; GetDCadMainWinHandle; SetForegroundWindow(DcadMainWinHandle); SendDcadCommand(SysVar + # 13 # 3 ); Sleep( 10 ); SendDcadCommand( 'COPYHISTORY' # 13 ); Sleep( 200 ); s := '' ; try s := ClipBoard . AsText; s := LastSubstringAfter( ': ' + SysVar, s); Result := '' ; if (Pos( '=' , s) > 0 ) and (Pos( '(' , s) > 1 ) then Result := Trim(StrAfterStrBefore( '=' , '(' , s)); if (Result = '' ) and (Pos( '(' , s) > 0 ) and (Pos( ')' , s) > 1 ) then Result := Trim(StrAfterStrBefore( '(' , ')' , s)); if (Result = '' ) and (Pos( 'デフォルト:' , s)> 0 ) then begin Result := Trim(StrAfterStrBefore( 'デフォルト:' , # 13 , s)); end ; except ; end ; end ; // ************************************ // CAD をアクティブに // ************************************ function SetDcadActive: boolean ; begin Result := False ; GetDCadMainWinHandle; if IsWindow(DcadMainWinHandle) then begin SetForegroundWindow(DcadMainWinHandle); Result := True ; end ; end ; //**************************************** // 画面の指定位置をBitmapに変換 //**************************************** procedure CaptureToBmp(Lf, Tp, W, H: Integer ; bmp: TBitmap); const CAPTUREBLT = $40000000 ; var hdcScreen : HDC; begin bmp . Width := W; bmp . Height := H; hdcScreen := CreateDC( 'DISPLAY' , nil , nil , nil ); try BitBlt( bmp . Canvas . Handle, 0 , 0 , W, H, hdcScreen, Lf, Tp, SRCCOPY or CAPTUREBLT); finally DeleteDC(hdcScreen); end ; end ; // ******************************* // DwgDocAryをソート // ******************************* procedure SortDwgDocAry; var len, n, m : integer ; i, j: integer ; DwgDocTmp : TDwgDoc; s, s1 : string ; begin n := Length(DwgDocAry); if n > 1 then begin // コメント文字列の最大文字数 len := 0 ; for i := 0 to n - 1 do begin m := DwgDocAry[i].Comment . Length; if len < m then len := m; end ; // 文字列比較のため同じ長さにする for i := 0 to n - 1 do begin with DwgDocAry[i] do begin m := Comment . Length; if m < len then begin for j := 1 to len - m do begin Comment:= ' ' + Comment; end ; end ; end ; end ; // ソート for i := 0 to n - 2 do begin s := DwgDocAry[i].Comment + ':' + DwgDocAry[i].Name; for j := i + 1 to n - 1 do begin s1 := DwgDocAry[j].Comment + ':' + DwgDocAry[j].Name; if s1 < s then begin DwgDocTmp := DwgDocAry[i]; DwgDocAry[i] := DwgDocAry[j]; DwgDocAry[j] := DwgDocTmp; s := s1; end ; end ; end ; end ; end ; // ************************************ // DrawGrid 同期 // ************************************ procedure TForm2 . ComboBox1Change(Sender: TObject); var idx : integer ; i : integer ; begin with ComboBox1 do begin idx := ItemIndex; if idx >= 0 then i := Integer (Items . Objects[idx]) else i := - 1 ; end ; if (i >= 0 ) and (i < Length(DwgDocAry)) then begin with DrawGrid1 do begin Col := i mod ColCount; Row := i div ColCount; end ; end ; end ; // ************************************ // コンボボックスを同期 // ************************************ procedure TForm2 . DrawGrid1Click(Sender: TObject); var i : integer ; begin with DrawGrid1 do i := Row * ColCount + col; ComboBox1 . ItemIndex := i; end ; // ************************************ // 図面切り替え // ************************************ procedure TForm2 . DrawGrid1DblClick(Sender: TObject); var i, id, j : integer ; begin with DrawGrid1 do begin i := Row * ColCount + col; if (i >= 0 ) and (i < Length(DwgDocAry)) then begin id := DwgDocAry[i].Index; if GetDCadMainWinHandle = 0 then Exit; SetForegroundWindow(DcadMainWinHandle); // メニュー操作 keybd_event(VK_MENU, 0 , 0 , 0 ); keybd_event(Ord( 'W' ), 0 , 0 , 0 ); keybd_event(Ord( 'W' ), 0 , KEYEVENTF_KEYUP, 0 ); keybd_event(VK_MENU, 0 , KEYEVENTF_KEYUP, 0 ); for j := 0 to id + 4 do begin keybd_event(VK_DOWN, 0 , 0 , 0 ); keybd_event(VK_DOWN, 0 , KEYEVENTF_KEYUP, 0 ); end ; keybd_event(VK_RETURN, 0 , 0 , 0 ); keybd_event(VK_RETURN, 0 , KEYEVENTF_KEYUP, 0 ); ComboBox1 . ItemIndex := i; //if BcadActiveFlag then // SetForegroundWindow(DcadMainWinHandle); end ; end ; //if not BcadActiveFlag then // SetForegroundWindow(Handle); end ; // ************************** // キャプチャ画像を描画 // ************************** procedure TForm2 . DrawGrid1DrawCell(Sender: TObject; ACol, ARow: Integer ; Rect: TRect; State: TGridDrawState); var i, w, h, dx, dy : integer ; idx : integer ; begin with DrawGrid1 do begin // 現在の表示位置 i := ARow * ColCount + Acol; idx := - 1 ; if (i >= 0 ) and (i < Length(DwgDocAry)) then idx := DwgDocAry[i].Index; if (idx >= 0 ) and (idx < Length(BmpAry)) then begin w := BmpAry[idx].Width; h := BmpAry[idx].Height; dx := (DefaultColWidth - w) div 2 ; if not CmtDispFlag then dy := (DefaultRowHeight - h - TitleH1) div 2 else dy := (DefaultRowHeight - h - TitleH2) div 2 ; with Canvas do begin if not CmtDispFlag then Draw(Rect . Left + dx, Rect . Top + dy + TitleH1, BmpAry[idx]) else Draw(Rect . Left+dx,Rect . Top+dy + TitleH2, BmpAry[idx]); // 背景を塗りつぶし if (ARow = Row) and (ACol = Col) then Brush . Color := clBlue else Brush . Color := clGray; if not CmtDispFlag then Rectangle(Rect . Left + 1 , Rect . Top + 1 , Rect . Right - 1 , Rect . Top + TitleH1 + 1 ) else Rectangle(Rect . Left + 1 , Rect . Top + 1 , Rect . Right - 1 , Rect . Top + TitleH2 + 1 ); Font . Color := clWHITE; // タイトルを描画 TextOut(Rect . Left + 3 , Rect . Top + 3 , ExtractFileName(DwgDocAry[i].Name)); // コメントを描画 if CmtDispFlag then TextOut(Rect . Left + 3 , Rect . Top + 3 + TitleH1 + 1 , DwgDocAry[i].Comment); // 標準の設定に戻す Pen . Style := psSolid; Brush . Style := bsClear; Pen . Color := clGray; Pen . Width := 1 ; Rectangle(Rect); end ; end else begin with Canvas do begin Brush . Color := clWhite; FillRect(Rect); end ; end ; end ; end ; // ************************************ // マウス座標を保持 // ************************************ procedure TForm2 . DrawGrid1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer ); begin MoveX := X; MoveY := Y; end ; // ************************************ // フォーム生成 // ************************************ procedure TForm2 . FormCreate(Sender: TObject); var ini : TIniFile; begin SetLength(BmpAry, 0 ); SetLength(DwgDocAry, 0 ); BmpH := 168 ; BmpW := 240 ; TitleH1 := 20 ; TitleH2 := 42 ; with DrawGrid1 do begin DefaultColWidth := BmpW; DefaultRowHeight := BmpH + 20 ; Options := Options + [goThumbTracking]; end ; BlkName := 'TITLE' ; AttName := 'ZSHEET' ; BlkName1 := BlkName; AttName1 := AttName; BlkName2 := BlkName; AttName2 := AttName; AttFlag1 := True ; AttFlag2 := False ; // ダブルクリックで Bricscad をアクティブに BcadActiveFlag := False ; // コメント表示 CmtDispFlag := False ; // キャプチャ時、コメントを取得 CmtGetFlag := True ; LspFileName := '' ; LspCmdName := '' ; LspCommand := '' ; ini := TIniFile . Create(ChangeFileExt(ParamStr( 0 ), '.ini' )); try with Ini do begin Top := ReadInteger( 'Form' , 'Top' , Top); Left := ReadInteger( 'Form' , 'Left' , Left); Width:= ReadInteger( 'Form' , 'Width' , Width); Height := ReadInteger( 'Form' , 'Height' , Height); if Left >= Screen . Width then Left := (Screen . Width + Width) div 2 ; if Top >= Screen . Height then Top := (Screen . Height + Height) div 2 ; BlkName1 := ReadString( 'Dcad' , 'BlkName1' , BlkName1); BlkName2 := ReadString( 'Dcad' , 'BlkName2' , BlkName2); AttName1 := ReadString( 'Dcad' , 'AttName1' , AttName1); AttName2 := ReadString( 'Dcad' , 'AttName2' , AttName2); AttFlag1 := ReadBool( 'Dcad' , 'AttFlag1' , AttFlag1); AttFlag2 := ReadBool( 'Dcad' , 'AttFlag2' , AttFlag2); BcadActiveFlag := ReadBool( 'Dcad' , 'ActiveFlag' , BcadActiveFlag); CmtDispFlag := ReadBool( 'DcadCapt' , 'CmtDispFlag' , CmtDispFlag); CmtGetFlag := ReadBool( 'DcadCapt' , 'CmtGetFlag' , CmtGetFlag); LspFileName := ReadString( 'Dcad' , 'LispFileName' , LspFileName); LspCmdName := ReadString( 'Dcad' , 'LispCmdName' , LspCmdName); LspCommand := ReadString( 'Dcad' , 'LispCommand' , LspCommand); // メニュー N2 . Caption := LspCmdName; SpeedButton2 . Caption := LspCmdName; end ; finally ini . Free; end ; end ; // ************************************ // フォーム破棄 // ************************************ procedure TForm2 . FormDestroy(Sender: TObject); var i : integer ; ini : TIniFile; begin if Length(BmpAry) > 0 then begin for i := 0 to Length(BmpAry) - 1 do BmpAry[i].Free; end ; ini := TIniFile . Create(ChangeFileExt(ParamStr( 0 ), '.ini' )); try with Ini do begin WriteInteger( 'Form' , 'Top' , Top); WriteInteger( 'Form' , 'Left' , Left); WriteInteger( 'Form' , 'Width' , Width); WriteInteger( 'Form' , 'Height' , Height); WriteString( 'Dcad' , 'BlkName1' , BlkName1); WriteString( 'Dcad' , 'BlkName2' , BlkName2); WriteString( 'Dcad' , 'AttName1' , AttName1); WriteString( 'Dcad' , 'AttName2' , AttName2); WriteBool( 'Dcad' , 'AttFlag1' , AttFlag1); WriteBool( 'Dcad' , 'AttFlag2' , AttFlag2); WriteBool( 'Dcad' , 'ActiveFlag' , BcadActiveFlag); WriteBool( 'DcadCapt' , 'CmtDispFlag' , CmtDispFlag); WriteBool( 'DcadCapt' , 'CmtGetFlag' , CmtGetFlag); WriteString( 'Dcad' , 'LispFileName' , LspFileName); WriteString( 'Dcad' , 'LispCmdName' , LspCmdName); WriteString( 'Dcad' , 'LispCommand' , LspCommand); end ; finally ini . Free; end ; end ; // *************************** // フォームリサイズ // *************************** procedure TForm2 . FormResize(Sender: TObject); var n, xcnt, ycnt: Integer ; begin n := Length(BmpAry); if n > 0 then begin with DrawGrid1 do begin xcnt := (Width - 23 ) div DefaultColWidth; if xcnt= 0 then xcnt:= 1 ; ycnt := n div xcnt; if n mod xcnt > 0 then Inc(ycnt); ColCount := xcnt; RowCount := ycnt; end ; end ; end ; procedure TForm2 . N2Click(Sender: TObject); begin end ; // ************************************ // 設定フォーム // ************************************ procedure TForm2 . N3Click(Sender: TObject); begin Form3 := TForm3 . Create(Form2); with Form3 do begin try Edit1 . Text := BlkName1; Edit2 . Text := AttName1; Edit3 . Text := BlkName2; Edit4 . Text := AttName2; Edit5 . Text := BmpW . ToString; Edit6 . Text := BmpH . ToString; Edit7 . Text := TitleH1 . ToString; Edit8 . Text := TitleH2 . ToString; CheckBox1 . Checked := AttFlag1; CheckBox2 . Checked := AttFlag2; CheckBox4 . Checked := BcadActiveFlag; CheckBox3 . Checked := CmtGetFlag; CheckBox5 . Checked := CmtDispFlag; Edit9 . Text := LspFileName; Edit10 . Text := LspCommand; Edit11 . Text := LspCmdName; if ShowModal = mrOk then begin BlkName1 := Edit1 . Text; AttName1 := Edit2 . Text; BlkName2 := Edit3 . Text; AttName2 := Edit4 . Text; BmpW := StrToIntDef(Edit5 . Text, BmpW); BmpH := StrToIntDef(Edit6 . Text, BmpH); TitleH1 := StrToIntDef(Edit7 . Text, TitleH1); TitleH2 := StrToIntDef(Edit8 . Text, TitleH2); AttFlag1 := CheckBox1 . Checked; if AttFlag1 and (BlkName1 <> '' ) and (AttName1 <> '' ) then begin BlkName := BlkName1; AttName := AttName1; end ; AttFlag2 := CheckBox2 . Checked; if AttFlag2 and (BlkName2 <> '' ) and (AttName2 <> '' ) then begin BlkName := BlkName2; AttName := AttName2; end ; BcadActiveFlag := CheckBox4 . Checked; CmtGetFlag := CheckBox3 . Checked; CmtDispFlag := CheckBox5 . Checked; LspFileName := Edit9 . Text; LspCommand := Edit10 . Text; LspCmdName := Edit11 . Text; // メニュー N2 . Caption := LspCmdName; SpeedButton2 . Caption := LspCmdName; end ; finally Free; end ; end ; end ; // ************************************ // DXFファイルからシステム変数(2D座標)を取得する // ************************************ function ReadDxfVariablePoint2D(dxfSl: TStrings; const sysName: string ): string ; var idx, i : integer ; code : integer ; s : string ; dxfSys : string ; begin Result := '' ; dxfSys := '$' + Uppercase(sysName); idx := dxfSL . IndexOf( 'ENTITIES' ); for i := 0 to idx div 2 do begin code := StrToInt(dxfSl[i * 2 ]); s := dxfSl[i * 2 + 1 ]; if (code = 9 ) and (s = dxfSys) then begin result := dxfSl[(i + 1 ) * 2 + 1 ] + ',' + dxfSl[(i + 2 ) * 2 + 1 ]; break; end ; end ; end ; // ************************************ // DXFファイルから属性を取得する // ************************************ function ReadDxfAttRib(dxfSl: TStrings; const InsertName: string ; const AttRibName: string ): string ; var i : integer ; insFlag, attFlag, hasAtt : boolean ; s : string ; AblkName , AattName, AattString : string ; code, idx : integer ; begin Result := '' ; insFlag := False ; hasAtt := False ; attFlag := False ; // ENTITIESセクションを探す idx := dxfsl . IndexOf( 'ENTITIES' ); for i := idx div 2 + 1 to dxfsl . Count div 2 - 1 do begin // DXFコード code := StrToInt(dxfsl[i * 2 ]); // その値 s := dxfsl[i * 2 + 1 ]; if insFlag then begin // 属性取得終了 if hasAtt and (code = 0 ) and (s = 'SEQEND' ) then begin insFlag := False ; hasAtt := False ; attFlag := false ; end ; if hasAtt and (AblkName = '' ) and (code = 2 ) then AblkName := s; if attFlag then begin // 属性の値を保持 if code = 1 then AattString := s; // 属性名 if code = 2 then begin AattName := s; // ブロック名、属性名が同じ if (InsertName = ABlkName) and (AttRibName = AattName) then begin Result := AattString; Break; end ; end ; end ; if hasAtt and (code = 0 ) and (s = 'ATTRIB' ) then attFlag := True ; end ; if (code = 0 ) and (s = 'INSERT' ) then begin insFlag := True ; hasAtt := False ; attFlag := False ; AblkName := '' ; end ; // 属性有 if (code = 66 ) and (Trim(s) = '1' ) then hasAtt := True ; // ENTITIES セクション終わり if (code = 0 ) and (s = 'ENDSEC' ) then Break; end ; end ; // ************************************ // DXFファイルを作成する // ************************************ function SaveDxfSl(dxfsl : TStringList): boolean ; var fname : TFileName; cnt : integer ; begin Result := False ; fname := ChangeFileExt(ParamStr( 0 ), '.dxf' ); DeleteFile(fname); cnt := 0 ; while True do begin Sleep( 10 ); if not FileExists(fname) then begin Break; end ; Inc(cnt); if cnt > 5 then Break; end ; if SetDcadActive then begin SendDcadCommand(# 3 'FILEDIA' # 13 '0' # 13 ); Sleep( 10 ); SendDcadCommand( 'DXFOUT' # 13 + fname + # 13 'Vesion' # 13 'R18' # 13 '16' # 13 ); SendDcadCommand( '' 'FILEDIA' # 13 '1' # 13 ); cnt := 0 ; while True do begin Sleep( 10 ); if FileExists(fname) then begin Sleep( 10 ); Break; end ; Inc(cnt); if cnt > 50 then Break; end ; if FileExists(fname) then begin dxfsl . LoadFromFile(fname); Result := dxfsl . Count > 0 ; end ; end ; end ; // ************************************ // 再キャプチャ // ************************************ procedure TForm2 . N5Click(Sender: TObject); var i, idx, j : integer ; ACol, ARow : integer ; s, s1 : string ; n : integer ; scrW, scrH : Integer ; ARect : TREct; ALeft, ATop : integer ; scale : Double ; APoint : TPoint; begin with DrawGrid1 do begin // マウス座標をCol,Rowに MouseToCell(MoveX, MoveY, ACol, ARow); Row := ARow; Col := ACol; i := Row * ColCount + Col; if (i >= 0 ) and (i < Length(DwgDocAry)) then begin idx := DwgDocAry[i].Index; if GetDCadMainWinHandle = 0 then Exit; // MDI のウィンドウを探す GetDcadMDIClientHandle; SetForegroundWindow(DcadMainWinHandle); // メニュー操作 keybd_event(VK_MENU, 0 , 0 , 0 ); keybd_event(Ord( 'W' ), 0 , 0 , 0 ); keybd_event(Ord( 'W' ), 0 , KEYEVENTF_KEYUP, 0 ); keybd_event(VK_MENU, 0 , KEYEVENTF_KEYUP, 0 ); for j := 0 to idx + 4 do begin keybd_event(VK_DOWN, 0 , 0 , 0 ); keybd_event(VK_DOWN, 0 , KEYEVENTF_KEYUP, 0 ); end ; keybd_event(VK_RETURN, 0 , 0 , 0 ); keybd_event(VK_RETURN, 0 , KEYEVENTF_KEYUP, 0 ); ComboBox1 . ItemIndex := i; Sleep( 500 ); // ウィンドウの位置と大きさを取得 GetWindowRect(DcadMDIClientWinHandle, ARect); // グラフィックウィンドウの左上座標 ALeft := ARect . Left; ATop := ARect . Top; // cad からグラフィック画面のサイズを取得 s := GetDcadVariable( 'SCREENSIZE' ); n := Pos( ',' , s); scrW := Trunc(StrToFloatDef(Copy(s, 1 , n - 1 ), 0 )); scrH := Trunc(StrToFloatDef(Copy(s, n + 1 ), 0 )); // システム変数取得失敗であれば、終了 if (scrW = 0 ) or (scrH = 0 ) then Exit; // 高解像度DPI対策 ALeft := Trunc(ALeft * scrW / (ARect . Right - ARect . Left)); ATop := Trunc(ATop * scrH / (ARect . Bottom - ARect . Top)); // キャプチャするビットマップの大きさに縮小する尺度 if BmpH / BmpW < scrH / scrW then scale := BmpW / scrW else scale := BmpH / scrH; // SetCursorPos(ALeft + 1 , ATop + 1 ); // 図面範囲でズーム s1 := GetDcadVariable( 'LIMMAX' ); s := GetDcadVariable( 'LIMMIN' ); if (s <> '' ) and (s1 <> '' ) then begin SendDcadCommand( 'ZOOM' # 13 + s + # 13 + s1 + # 13 ); end else begin SendDcadCommand( 'ZOOM' # 13 'Fit' # 13 ); end ; Sleep( 200 ); SendDcadCommand( 'ZOOM' # 13 + Format( '%.3f' , [scale]) + 'X' # 13 ); // 描画待ち Sleep( 500 ); if Length(BmpAry) > idx then begin // キャプチャ CaptureToBmp( ALeft + (scrW - BmpW) div 2 , ATop + (scrH - BmpH) div 2 , BmpAry[idx].Width, BmpAry[idx].Height, BmpAry[idx]); end ; // 直前の画面表示に戻す SendDcadCommand( 'ZOOM' # 13 'P' # 13 ); // マウスカーソルを戻す APoint . X := MoveX; APoint . Y := MoveY; APoint := ClientToScreen(APoint); SetCursorPos(APoint . X, APoint . Y); Repaint; end ; end ; end ; // *********************************** // 画面キャプチャ // *********************************** procedure TForm2 . SpeedButton1Click(Sender: TObject); var limmax, limmin : OleVariant; scrH, scrW : integer ; ARect : TRect; ALeft, ATop, AWidth, AHeight : integer ; i : integer ; scale : double ; h, hdwg : HWND; dwgTitle, ext : string ; cnt : integer ; s, s1 : string ; n, j : integer ; Tics : Cardinal ; sl : TStringList; Title : string ; count : integer ; begin Tics := GetTickCount; // メインウィンドウのハンドルを取得 if GetDCadMainWinHandle = 0 then Exit; // 最小化されていれば戻す if isIconic(DcadMainWinHandle) then begin OpenIcon(DcadMainWinHandle); Sleep( 100 ); end ; // MDI のウィンドウを探す GetDcadMDIClientHandle; h := DcadMDIChildWinHandle; cnt := 0 ; // ここでは、ドキュメントの数を数えるだけ while h <> 0 do begin hdwg := GetWindow(h, GW_CHILD); dwgTitle := GetWindowCaption(hdwg); // ファイル名を取得 ext := Uppercase(ExtRactFileExt(dwgTitle)); // 念のため、拡張子を比較 if (ext = '.DWG' ) or (ext = '.DWG*' ) then Inc(cnt); // 次のウィンドウを探す h := GetWindow(h, GW_HWNDNEXT); end ; if cnt = 0 then Exit; // ウィンドウの位置と大きさを取得 GetWindowRect(DcadMDIClientWinHandle, ARect); // グラフィックウィンドウの左上座標 ALeft := ARect . Left; ATop := ARect . Top; SetCursorPos(ALeft + 1 , ATop + 1 ); AWidth := ARect . Right - ARect . Left; AHeight := ARect . Bottom - ARect . Top; // Draftsight からグラフィック画面のサイズを取得 s := GetDcadVariable( 'SCREENSIZE' ); n := Pos( ',' , s); scrW := Trunc(StrToFloatDef(Copy(s, 1 , n - 1 ), 0 )); scrH := Trunc(StrToFloatDef(Copy(s, n + 1 ), 0 )); // 高解像度DPI対策 ALeft := Trunc(ALeft * scrW / AWidth); ATop := Trunc(ATop * scrH / AHeight); // キャプチャするビットマップの大きさに縮小 if BmpH / BmpW < scrH / scrW then scale := BmpW / scrW else scale := BmpH / scrH; // 自フォームを最小に //WindowState := wsMinimized; //Sleep(100); // すでにBitmap が作成されているときは、破棄 if Length(BmpAry) > 0 then begin for i := 0 to Length(BmpAry) - 1 do BmpAry[i].Free; end ; SetLength(BmpAry, cnt); SetLength(DwgDocAry, cnt); with DrawGrid1 do begin // 適当な大きさを確保 RowCount := cnt div ColCount; if cnt mod ColCount > 0 then RowCount := RowCount + 1 ; end ; SetForegroundWindow(DcadMainWinHandle); sl := TStringList . Create; try Title := '' ; // メニューを操作 for i := 0 to cnt - 1 do begin keybd_event(VK_MENU, 0 , 0 , 0 ); keybd_event(Ord( 'W' ), 0 , 0 , 0 ); keybd_event(Ord( 'W' ), 0 , KEYEVENTF_KEYUP, 0 ); keybd_event(VK_MENU, 0 , KEYEVENTF_KEYUP, 0 ); for j := 0 to i + 4 do begin keybd_event(VK_DOWN, 0 , 0 , 0 ); keybd_event(VK_DOWN, 0 , KEYEVENTF_KEYUP, 0 ); end ; keybd_event(VK_RETURN, 0 , 0 , 0 ); keybd_event(VK_RETURN, 0 , KEYEVENTF_KEYUP, 0 ); count := 0 ; while True do begin Sleep( 10 ); if Title <> GetWindowCaption(DcadMainWinHandle) then begin Break; end ; Inc(count); if Count > 60 then Break; end ; // 図面切り替わり待ち Sleep((count+ 2 ) * 50 ); // 編集の図面名を取得 s := GetWindowCaption(DcadMainWinHandle); Title := s; // 配列に格納 with DwgDocAry[i] do begin Index := i; Name := StrAfterStrBefore( '[' , ']' , s); end ; if SaveDxfSL(sl) then begin // シート番号、またはページ番号を取得 s := ReadDxfAttRib(sl, BlkName, AttName); DwgDocAry[i].Comment := s; s := ReadDxfVariablePoint2D(sl, 'LIMMAX' ); s1 := ReadDxfVariablePoint2D(sl, 'LIMMIN' ); SendDcadCommand( 'ZOOM' # 13 + s + # 13 + s1 + # 13 ); end else begin SendDcadCommand( 'ZOOM' # 13 'F' # 13 ); DwgDocAry[i].Comment := '' ; end ; SendDcadCommand( 'ZOOM' # 13 + Format( '%.3f' , [scale]) + 'X' # 13 ); Sleep( 200 ); // キャプチャ用ビットマップを作成 BmpAry[i] := TBitmap . Create; BmpAry[i].PixelFormat := pf32bit; // ビットマップの大きさ BmpAry[i].Width := BmpW; BmpAry[i].Height := BmpH; // キャプチャ CaptureToBmp( ALeft + (scrW - BmpW) div 2 , ATop + (scrH - BmpH) div 2 , BmpAry[i].Width, BmpAry[i].Height, BmpAry[i]); SendDcadCommand( 'ZOOM' # 13 'P' # 13 ); Sleep( 200 ); end ; finally sl . Free; end ; // シート番号、ページ番号順にソート SortDwgDocAry; with ComboBox1 do begin Items . Clear; Sorted := False ; for i := 0 to Length(DwgDocAry) - 1 do Items . AddObject(DwgDocAry[i].Comment + ':' + DwgDocAry[i].Name , TObject(i)); end ; FormResize(self); ComboBox1Change(self); // 自フォームを戻す //WindowState := wsNormal; // 自フォームをアクティブに SetForegroundWindow(Handle); ShowMessage( '終了しました。' +# 13 # 10 + Format( '%.1f' ,[(GetTickCount - Tics) / 1000 ]) + '秒' ); end ; procedure TForm2 . SpeedButton2Click(Sender: TObject); begin // コマンド実行 N2Click(self); end ; procedure TForm2 . SpeedButton3Click(Sender: TObject); begin // 設定 N3Click(self); end ; procedure TForm2 . SpeedButton4Click(Sender: TObject); var s: string ; begin s := GetDcadVariable(Edit1 . Text); ShowMessage(s); end ; end . |