探讨 Delphi 驱动 AutoCAD………………(100分)

D

darnis

Unregistered / Unconfirmed
GUEST, unregistred user!
我看到大家谈论到 Automation 时都是那么的积极,那么的踊跃,
我在这里把我平常工作中涉及到的 Delphi 驱动 AutoCAD 的问题
跟大家探讨一下。

由于 AutoCAD 是比较消耗系统资源的一个大的软件系统,所以有必要
在创建 AutoCAD 的 Automation 服务器之前检测系统中是是否已经
运行有 AutoCAD 的实例,GetActiveOleObject 就是用于实现这个功能
的API,而且它也可以返回当前运行的 AutoCAD 实例的引用。
如果AutoCAD没有运行的话,再创建一个 AutoCAD 的实例,使 AutoCAD
运行起来,这时用 CreateOleObject ,AutoCAD 的 ProgID 是
'AutoCAD.application'和'AutoCAD.Drawing' 这两个是不管AutoCAD
的版本是多少都存在的。查看注册表项的值就可以知道,
AutoCAD.application 对应的 LocalServer 的值比起 AutoCAD.Drawing
多了一个 /automation 的参数,当用 AutoCAD.applicaiton 作为
CreateOleObject 的参数,创建的 AutoCAD是以 Automation方式运行,
AutoCAD 的 Application.visible 是 false 的;以 AutoCAD.Drawing
方式运行 AutoCAD 时,感觉跟直接由用户启动 AutoCAD 差不多。

主要是因为在以前我做过的一次有关 AutoCAD 的项目中,驱动 AutoCAD
时遇到了一个问题:用Automation 方式驱动时,总是报错,不能成功驱动
AutoCAD,但是可以确保的 AutoCAD 是能够正常工作的(后来怀疑是因为
AutoCAD是盗版的故,而且用的又是98,同样的AutoCAD 用到2000上就啥问题都没有)
后来换成
CreateOleObject('AutoCAD.Drawing')
可以成功驱动,这时的工作方式好像跟我直接双击 Acad.exe 运行 AutoCAD
好像没有什么区别一样,,但这里还是想问一下富翁们:AutoCAD 的
AutoCAD.Drawing作为 CreateOleObject的参数驱动 AutoCAD 时,跟支持运行
AutoCAD 有没有区别啊?

下面我把最近我做的一个用线程来驱动 AutoCAD 的示例贴给大家看看,
请大伙帮小弟指正指正, :)

unit CADDrive;

interface

uses
Windows, Classes, AutoCAD_TLB, Dialogs, Messages, Forms,SysUtils,
AutoCADEvents;
// AutoCAdEvents 是用 EventSinkimp(http://www.techvanguards.com/products/eventsinkimp/)
// 来获取的 AutoCAD 事件处理的单元。
const

CAD_START = WM_USER+100;
CAD_NOTINSTALL = WM_USER +110;
CAD_ERROR = WM_USER+120;
CAD_VERSION = WM_USER+130;
CAD_QUIT = WM_USER+140; // AutoCAD 退出事件

type
{
TCadDrive 用于驱动AutoCAD
}
TCadDrive = class(TThread)
private
FHadle: HWND;
FController : IAcadApplication;
FConnect: boolean;
FOpened : boolean;
FError: integer;
FErrored: Boolean;
FEvent: TAutoCADDAcadApplicationEvents;

procedure SetController(const Value: IAcadApplication);
procedure SetConnect(const Value: boolean);

protected
procedure Execute; override;
public
constructor Create(Hadle: HWND;Suspended: boolean = true); overload;
// 驱动 AutoCAD 的过程…………
procedure Connect;
// 关闭 AutoCAD
procedure CloseCAD;
// AutoCAD 被用户手工关闭时的处理过程
procedure EVTCADClose(Sender: TObject; var Cancel: wordbool);

// 是否连接 AutoCAD 。
property Connected: boolean read FConnect write SetConnect;
// 处理过程中是否有错误。。
property Errored: Boolean read FErrored default false;
// 错误代码。。
property Error: integer read FError;
// 直接设置或者是取得 AutoCAD 的 Applicaiton 接口
property Controller: IAcadApplication read FController write
SetController;
end;

// 下面两个函数是提供给外部函数用的。
function GetAutoCAD(Handle: HWND):IAcadApplication;
procedure CloseAutoCAD;

var
CADDriver: TCADDrive;

implementation

uses
comobj, ActiveX;
{ Important: Methods and properties of objects in VCL or CLX can only be used
in a method called using Synchronize, for example,

Synchronize(UpdateCaption);

and UpdateCaption could look like,

procedure TCadDrive.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }

{ TCadDrive }

procedure TCadDrive.CloseCAD;
begin
if Assigned(FController) then
FController.Quit;
end;

procedure TCadDrive.Connect;
var
str: string;
begin
if FController = nil then
begin
try // 直接尝试获取 AutoCAD 的运行实例。
FController := GetActiveOleObject('AutoCAD.Application') as IAcadApplication;
FOpened := true;
except // 发生异常表明AutoCAD 没有运行,下面就是
try // OleAutomation 方式启动 AutoCAD。
FController := CreateOleObject('AutoCAD.Application') as IAcadApplication;
except
try // 如果 AutoMation 方式启动失败,由以一般的方式启动。
FController := CreateOleObject('AutoCAD.Drawing') as IAcadApplication;
except // 如果还是不能启动,则系统报错,抛出异常。
raise Exception.Create(inttostr(CAD_NOTINSTALL));
end;
end;
end;

// 版本判断
str := copy( FController.Version , 0, 2);
if strtoint(str)<15 then
begin
FController :=nil;
sendmessage(FHadle,CAD_VERSION,0,0);
raise Exception.Create(inttostr(CAD_VERSION));
end;

//// 把 AutoCAD 的事件处理跟 FController 联系起来,
FEvent.Connect(FController);
FEvent.BeginQuit := EVTCADClose;
end;
end;

//
constructor TCadDrive.Create(Hadle: HWND;Suspended: boolean);
begin
inherited Create(Suspended);
FHadle := Hadle;
FOpened := false;
FErrored := false;
FConnect := false;
// TAutoCADDAcadApplicationEvents 是 AutoCADEvents 单元中的一个
// 类,用于处理 AutoCAD 的Application 级事件。
FEvent := TAutoCADDAcadApplicationEvents.Create(nil);
end;

procedure TCadDrive.EVTCADClose(Sender: TObject; var Cancel: wordbool);
begin
// 当 AutoCAD 被用户关闭时,向创建线程的实例发送message。
sendmessage(FHadle,CAD_QUIT,0,0);
end;

procedure TCadDrive.Execute;
begin
{ Place thread code here }
CoInitialize(nil); // 环境初始化。
if (FController = nil) and(not FConnect) then
try
Synchronize(Connect);
FConnect := true;
except
on e: Exception do
begin
FConnect := false;
FErrored := true;
FError := strtoint(e.Message);
sendmessage(FHadle,FError,0,0);
end;
end;
if FConnect then
begin
sendmessage(FHadle,CAD_START,0,0);
end;
CoUninitialize; // 跟CoInitialize成对使用。
end;


procedure TCadDrive.SetConnect(const Value: boolean);
begin
if FConnect<>Value then
begin
FConnect := Value;
if FConnect then
Synchronize(Connect)
else
begin
if Assigned(FController) and FOpened then
Synchronize(CloseCAD);
end;
end;
end;

procedure TCadDrive.SetController(const Value: IAcadApplication);
begin
FController := Value;
end;

function GetAutoCAD(Handle: HWND):IAcadApplication;
begin
try
if (not Assigned(CADDriver))or(not Assigned(CADDriver.Controller)) then
begin
CADDriver := TCadDrive.Create(Handle);
CADDriver.Resume;
CADDriver.WaitFor;
end;
// CADDriver.Controller.Visible:=true;
Result := CADDriver.Controller;
except
raise Exception.Create(inttostr(CADDriver.Error));
end;
end;

procedure CloseAutoCAD;
begin
if Assigned(CADDriver) then
begin
try
CADDriver.Controller.Quit;
CADDriver.Controller := nil;
except
showmessage('不能正常关闭 AutoCAD!');
end;
end;
end;

end.

在这里用 GetActiveOleObject 和 CreateOleObject 获得的是跟
Automation 类型兼容的,返回值是 OleVariant 类型,为了编程过程中
方便,我把这个返回值转换成了 IAcadApplication 这样子编程过程
中就可以避免盲目地调用了。 IAcadApplication 的申明,需要引入
AutoCAD 的类型库文件 Acad.tlb,,可以从 Import Libary 中直接
Create Unit.. 来获取。 至于 AutoCADEvents 这个单元可以借助于
EventSinkImp(http://www.techvanguards.com/products/eventsinkimp/
可以下载到)来自动生成,可以生成 AutoCAD 所有对象的事件处理
单元,,比较爽的。

有兴趣的富翁们多多指教。。 :)
 
我送你一个更好的东西

前几天也在研究CAD的二次开发,

把做的东西放进CAD里面进行开发,不用写那么麻烦的程序了

http://www.delphibbs.com/delphibbs/dispq.asp?lid=1362630

可以去看DEMO
http://www.softediter.com/demo.gif
 
谢谢,,谢谢。。:)
你所说的东西,我是会仔细去看的。

我所讲到的东西,不是为了在AutoCAD 的环境下去做什么,,而是为了在应用中
如何地去控制AutoCAD,如何让AutoCAD作为自己应用程序的一个工具。
:)
 
不好意思,搞错了
 
:)
你是常在做 AutoCAD 上的应用啊?
以后有问题还多请教你!

先问你一个:
AutoCAD 的 AcadSelectionSet 的方法
SelectByPolygon 方法为啥在Delphi 里调用时老是报错呢?说那个 FilterType
参数不正确。。……
你帮忙看一下呢?
是别人的问题
http://www.delphibbs.com/delphibbs/dispq.asp?LID=1354415
,,,,
 
请给我邮一份已经编好的实例好么,我要.dpr那种,因为我不会调,谢谢谢谢!帮帮忙
jt79@163.com
 
多人接受答案了。
 
顶部