Тема: Как отслеживать события Acad.Applications в Delphi

Здраствуйте!
1)Если кто сталкивался с подобной проблемой, то помогите реальным примером. Например, как я могу запустить процедуру Delphi, если в AutoCad-е произошло событие OnActivate.
2)И вообще в AutoCAD 2002 нет готового визуального компонента AcadApplication, есть только AcadDocument, поэтому подключатся нужно вручную, набирая текст ручками. Но у IAcadApplication нету процедур обработки событий Автокада. А мне нужно чтобы события любого активного документа отлавливало Delphi и запускало нужную процедуру.
За любой толковый совет, а ещё лучше пример Спасибо!

Re: Как отслеживать события Acad.Applications в Delphi

> Vadim
"визуального компонента AcadApplication" нет и не может быть. Невизуальный в некоторых билдах был. Осторожней с терминологией, тогда не будет вопросов.
Осторожнее с импортом библиотеки типов. Они совершенно разные для разных изданий одной базовой версии. Если будете использовать AutoCAD_TLB, то может оказаться что на другой машине программа вообще не будет работать, так как там окажутся другие GUID. Поэтому лучше вообще не укладывать никаких "компонентов", а работать через интерфейсы, то есть создавать в run-time
Приложение Acad можно получить и как IAcadApplication

 AcadApplication := GetActiveOleObject(AcadAppString) as IAcadApplication;

и как OleVariant

AcadApplication := GetActiveOleObject(AcadAppString);

Результаты будут разные.

мне нужно чтобы события любого активного документа отлавливало Delphi

Основным объектом теперь является AcadDocument. В нем и происходят события. И все они (которые объявлены в TLB) доступны. Приложение без документа - ничто. Но и до его свойств и методов можно добраться

AcadDocument.Applicatin

Далее, подставляя точки, можно добраться куда надо.
Здесь поможет CodeInsight

Re: Как отслеживать события Acad.Applications в Delphi

Основным объектом теперь является AcadDocument....

> ShaggyDoc
объясните пожалуйста подробнее что вы подразумеваете по объектом AcadDocument.
Если вы имеете ввиду интерфейс IAcadDocument, который
получается из IAcadApplication.ActiveDocument, то у него нету процедур обработки событий, которые я могу использовать(у него вообще не таких процедур). А такие процедуры, судя из
AutoCAD_TLB есть только у класса TAcadDocument. Но как сделать так, чтобы TAcadDocument связывался с IAcadApplication.ActiveDocument  я не знаю, потому как IAcadApplication.ActiveDocument возвращает интерфейс IAcadDocument, а мне-то нужен объект класса TAcadDocument.

Re: Как отслеживать события Acad.Applications в Delphi

AcadDocument  в данном случае лишь имя.
Может быть классом или интерфейсом.
Надо класс так объявляйте
AcadDocument : TAcadDocument;
Можно и положить "компонент", тогда он сам пропишется. И будут доступны события.
Можно ведь из IAcadApplication получить документ, а можно и наоборот.

Re: Как отслеживать события Acad.Applications в Delphi

тогда почему при выполнении этого кода происходит ошибка:

var
  AutoCADApplication:IAcadApplication;
  AcadDoc:TAcadDocument;
procedure ActivateAcad();
begin
AutoCADApplication := CreateOleObject('AutoCAD.Application')as IAcadApplication;
AutoCADApplication.Visible := true;
AcadDoc.ConnectTo(AutoCADApplication.ActiveDocument);
end;

Re: Как отслеживать события Acad.Applications в Delphi

> Vadim
Конечно будет ошибка.
AutoCADApplication объявлен как интерфейс, а AcadDoc - как класс. Явно подключена библиотека типов, иначе откуда Delphi узнала бы про TAcadDocument.
И где же создание AcadDoc? Он еще не создан, а пытается коннектиться, да еще к интерфейсу. Кто ж ему даст?
К документу надо обращаться так:
AutoCADApplication.ActiveDocument.  и далее метод.
И не забывать все заключать в
try
except
end;
Чтобы выловить ошибку. Обработку ошибки - в except. Причин может быть множество. Например, нет 'AutoCAD.Application', а есть 'AutoCAD.Application.15' или наоборот, или нет у него вообще активного документа. Или вообще нет никаких таких Автокадов. Может и такая ситуация быть. Или есть, но не зарегистрирован в реестре как COM-сервер. Вчера был, а сегодня куда-то делся. Баловство с библиотекой типов в Delphi может к этому привести.

Re: Как отслеживать события Acad.Applications в Delphi

> ShaggyDoc
Спасибо за ответ, с созданием и подключением разобрался.
Удиветельно, но всё работает. Теперь бы ещё понять как
к указателю метода обработки события привязать конкретную
процедуру. Например:
var
AcadDoc:TAcadDocument;
begin
TAcadDocument.Create(AcadDoc);
AcadDoc.OnActivate:='Какая-нибудь процедура обработки
                                 события 'OnActivate''
end;

Re: Как отслеживать события Acad.Applications в Delphi

> Vadim
Я здесь тоже нахожусь с подобным вопросом. Но у меня они (события) вообще не отслеживаются. Нашел кое-какой "корявенький" выход. См. https://www.caduser.ru/forum/topic7509.html

Re: Как отслеживать события Acad.Applications в Delphi

OnActivate - обработчик события TNotifyEvent.
TNotifyEvent = procedure(Sender: TObject) of object;
Так что, нужно объявить и написать процедуру
procedure Kadabra(Sender: TObject);
begin
  //...
end;
и использовать её в качестве обработчика
AcadDoc.OnActivate:= Kadabra;

Re: Как отслеживать события Acad.Applications в Delphi

народ, че вы голову морочите?? Этоже COM!! Про подписку на события не слышали? А про IConnectionPoint? Шас.. выложу..

Re: Как отслеживать события Acad.Applications в Delphi

класс

 unit SinkAcadEvents;
 interface
 Uses
 ComObj, AutoCAD_TLB, Classes;
 Type
  TAcadApplicationEvents = class(TInterfacedObject, IUnknown, IDispatch)
  private
    FOwner : TObject;
    FOnBeginSave : TNotifyEvent;
    FOnEndSave : TNotifyEvent;
    FOnBeginCommand : TNotifyEvent;
    FOnEndCommand : TNotifyEvent;
    FOnBeginLisp : TNotifyEvent;
    FOnEndLisp : TNotifyEvent;
    FOnLispCancelled : TNotifyEvent;
    FOnSelectionChanged : TNotifyEvent;
    FOnActivate : TNotifyEvent;
    FOnDeactivate : TNotifyEvent;
    FOnBeginRightClick : TNotifyEvent;
    FOnBeginShortcutMenuDefault : TNotifyEvent;
    FOnBeginShortcutMenuEdit : TNotifyEvent;
    FOnBeginShortcutMenuCommand : TNotifyEvent;
    FOnBeginShortcutMenuGrip : TNotifyEvent;
    FOnBeginShortcutMenuOsnap : TNotifyEvent;
    FOnEndShortcutMenu : TNotifyEvent;
    FOnBeginDoubleClick : TNotifyEvent;
    FOnObjectAdded : TNotifyEvent;
    FOnObjectErased : TNotifyEvent;
    FOnObjectModified : TNotifyEvent;
    FOnBeginPlot : TNotifyEvent;
    FOnEndPlot : TNotifyEvent;
    FOnWindowMovedOrResized : TNotifyEvent;
    FOnLayoutSwitched : TNotifyEvent;
    FOnWindowChanged : TNotifyEvent;
    FOnBeginClose : TNotifyEvent;
    FOnBeginDocClose : TNotifyEvent;
    FOnUnknownEvent : TNotifyEvent;
  protected
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
    function GetTypeInfoCount(out Count: Integer): HResult; virtual; stdcall;
    function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; virtual; stdcall;
    function GetIDsOfNames(const IID: TGUID; Names: Pointer;
      NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; virtual; stdcall;
    function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
      Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; virtual; stdcall;
  public
    constructor Create(Owner : TObject);
    property OnBeginSave : TNotifyEvent read FOnBeginSave write FOnBeginSave;
    property OnEndSave : TNotifyEvent read FOnEndSave write FOnEndSave ;
    property OnBeginCommand : TNotifyEvent read FOnBeginCommand write FOnBeginCommand;
    property OnEndCommand : TNotifyEvent read FOnEndCommand write FOnEndCommand ;
    property OnBeginLisp : TNotifyEvent read FOnBeginLisp write FOnBeginLisp ;
    property OnEndLisp : TNotifyEvent read FOnEndLisp write FOnEndLisp;
    property OnLispCancelled : TNotifyEvent read FOnLispCancelled write FOnLispCancelled;
    property OnSelectionChanged : TNotifyEvent read FOnSelectionChanged write FOnSelectionChanged;
    property OnActivate : TNotifyEvent read FOnActivate write FOnActivate;
    property OnDeactivate : TNotifyEvent read FOnDeactivate write FOnDeactivate;
    property OnBeginRightClick : TNotifyEvent read FOnBeginRightClick write FOnBeginRightClick;
    property OnBeginShortcutMenuDefault : TNotifyEvent read FOnBeginShortcutMenuDefault write FOnBeginShortcutMenuDefault;
    property OnBeginShortcutMenuEdit : TNotifyEvent read FOnBeginShortcutMenuEdit write FOnBeginShortcutMenuEdit;
    property OnBeginShortcutMenuCommand : TNotifyEvent read FOnBeginShortcutMenuCommand write FOnBeginShortcutMenuCommand;
    property OnBeginShortcutMenuGrip : TNotifyEvent read FOnBeginShortcutMenuGrip write FOnBeginShortcutMenuGrip;
    property OnBeginShortcutMenuOsnap : TNotifyEvent read FOnBeginShortcutMenuOsnap write FOnBeginShortcutMenuOsnap;
    property OnEndShortcutMenu : TNotifyEvent read FOnEndShortcutMenu write FOnEndShortcutMenu;
    property OnBeginDoubleClick : TNotifyEvent read FOnBeginDoubleClick write FOnBeginDoubleClick;
    property OnObjectAdded : TNotifyEvent read FOnObjectAdded write FOnObjectAdded;
    property OnObjectErased : TNotifyEvent read FOnObjectErased write FOnObjectErased;
    property OnObjectModified : TNotifyEvent read FOnObjectModified write FOnObjectModified;
    property OnBeginPlot : TNotifyEvent read FOnBeginPlot write FOnBeginPlot;
    property OnEndPlot : TNotifyEvent read FOnEndPlot write FOnEndPlot;
    property OnWindowMovedOrResized : TNotifyEvent read FOnWindowMovedOrResized write FOnWindowMovedOrResized;
    property OnLayoutSwitched : TNotifyEvent read FOnLayoutSwitched write FOnLayoutSwitched;
    property OnWindowChanged : TNotifyEvent read FOnWindowChanged write FOnWindowChanged;
    property OnBeginClose : TNotifyEvent read FOnBeginClose write FOnBeginClose;
    property OnBeginDocClose : TNotifyEvent read FOnBeginDocClose write FOnBeginDocClose;
    property OnUnknownEvent : TNotifyEvent read FOnUnknownEvent write FOnUnknownEvent;
  end;
implementation
uses Windows, ActiveX;
{ TAcadApplicationEvents }
function TAcadApplicationEvents.GetTypeInfo(Index, LocaleID: Integer;
  out TypeInfo): HResult;
begin
  Result := E_NOTIMPL;
end;
function TAcadApplicationEvents.QueryInterface(const IID: TGUID;
  out Obj): HResult;
begin
  Result := E_NOINTERFACE;
  Pointer(Obj) := nil;
  if GetInterface(IID,Obj) then Result := S_OK;
  if IsEqualGUID(IID,_DAcadApplicationEvents) and GetInterface(IDispatch,Obj)
   then Result := S_OK;
end;
function TAcadApplicationEvents.GetIDsOfNames(const IID: TGUID; Names: Pointer;
  NameCount, LocaleID: Integer; DispIDs: Pointer): HResult;
begin
  Result := E_NOTIMPL;
end;
function TAcadApplicationEvents._AddRef: Integer;
begin
  Result := 2;
end;
function TAcadApplicationEvents.GetTypeInfoCount(out Count: Integer): HResult;
begin
  Count :=0;
  Result := S_OK;
end;
function TAcadApplicationEvents.Invoke(DispID: Integer; const IID: TGUID;
  LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
  ArgErr: Pointer): HResult;
begin
  Case DispID of
    1  : if Assigned(FOnBeginSave) then FOnBeginSave(FOwner);
    2  : if Assigned(FOnEndSave) then FOnEndSave(FOwner);
    6  : if Assigned(FOnBeginCommand) then FOnBeginCommand(FOwner);
    7  : if Assigned(FOnEndCommand) then FOnEndCommand(FOwner);
    8  : if Assigned(FOnBeginLisp) then FOnBeginLisp(FOwner);
    9  : if Assigned(FOnEndLisp) then FOnEndLisp(FOwner);
    10 : if Assigned(FOnLispCancelled) then FOnLispCancelled(FOwner);
    11 : if Assigned(FOnSelectionChanged) then FOnSelectionChanged(FOwner);
    12 : if Assigned(FOnActivate) then FOnActivate(FOwner);
    13 : if Assigned(FOnDeactivate) then FOnDeactivate(FOwner);
    14 : if Assigned(FOnBeginRightClick) then FOnBeginRightClick(FOwner);
    15 : if Assigned(FOnBeginShortcutMenuDefault) then FOnBeginShortcutMenuDefault(FOwner);
    16 : if Assigned(FOnBeginShortcutMenuEdit) then FOnBeginShortcutMenuEdit(FOwner);
    17 : if Assigned(FOnBeginShortcutMenuCommand) then FOnBeginShortcutMenuCommand(FOwner);
    18 : if Assigned(FOnBeginShortcutMenuGrip) then FOnBeginShortcutMenuGrip(FOwner);
    19 : if Assigned(FOnBeginShortcutMenuOsnap) then FOnBeginShortcutMenuOsnap(FOwner);
    30 : if Assigned(FOnEndShortcutMenu) then FOnEndShortcutMenu(FOwner);
    20 : if Assigned(FOnBeginDoubleClick) then FOnBeginDoubleClick(FOwner);
    21 : if Assigned(FOnObjectAdded) then FOnObjectAdded(FOwner);
    22 : if Assigned(FOnObjectErased) then FOnObjectErased(FOwner);
    23 : if Assigned(FOnObjectModified) then FOnObjectModified(FOwner);
    24 : if Assigned(FOnBeginPlot) then FOnBeginPlot(FOwner);
    25 : if Assigned(FOnEndPlot) then FOnEndPlot(FOwner);
    29 : if Assigned(FOnWindowMovedOrResized) then FOnWindowMovedOrResized(FOwner);
    31 : if Assigned(FOnLayoutSwitched) then FOnLayoutSwitched(FOwner);
    32 : if Assigned(FOnWindowChanged) then FOnWindowChanged(FOwner);
    33 : if Assigned(FOnBeginClose) then FOnBeginClose(FOwner);
    34 : if Assigned(FOnBeginDocClose) then FOnBeginDocClose(FOwner);
    else if Assigned(FOnUnknownEvent) then FOnUnknownEvent(FOwner);
  end;
  Result := S_OK;
end;
function TAcadApplicationEvents._Release: Integer;
begin
  Result := 1;
end;
constructor TAcadApplicationEvents.Create(Owner: TObject);
begin
  inherited Create;
  FOwner := Owner;
end;
end.

Re: Как отслеживать события Acad.Applications в Delphi

пример использования, с ходу может и не пойдет, но общий смысл помоему понятен.. надергано с рабочего приложения.. try,except,finally блоки отсутсвуют, чтобы не загромождать код..

Uses
   Autocad_TLB, ComObj, ... , ... ;
var
 FAcadApplication : IAcadApplication;
 obj : Variant;
 EventChanel : TAcadApplicationEvents;
 CPC: IConnectionPointContainer;
 CP : IConnectionPoint;
 cook : Integer;
begin
// пытаемся присоединиться к уже запущенной копии AutoCad
 FACADAppliction := GetActiveOleObject('AutoCAD.Application.16') as IACadApplication;
 if Assigned(FAcadApplication) then
 begin
// создаем канал
   EventChanel := TAcadApplicationEvents.Create(self);
// присоединяем к автокаду
// тот-же код в InterfaceConnect модуль ComObj
   FAcadApplication.QueryInterface(IConnectionPointContainer, CPC);
   CPC.FindConnectionPoint(_DAcadDocumentEvents,CP);
   CP.Advise(EventChanel,cook);
// подвешиваем обработчик
   EventChanel.OnSelectionChanged := OnActivate;
 end;
// не забудте описать процедуру
//procedure onActivate(Sender: TObject);
// и в последствии отсоединить канал событий
// InterfaceDisconnect(FAcadApplication, _DAcadDocumentEvents, cookie);
end.

Всем удачи, если че не понятно, пишите..

(изменено: Максим Кошман, 13 января 2010г. 14:11:01)

Re: Как отслеживать события Acad.Applications в Delphi

Подскажите пожайлуста кто разобрался в данном коде
У меня на OnSelectionChanged ошибка

И, если есть рабочий пример (этот или подобный), скиньте мне пожалуйста.

Я хочу сделать программу на делфи которая будет записывать в лог все команды из командной строки
Я так понял для этого надо использовать endcommand

Заранее благодарен

Re: Как отслеживать события Acad.Applications в Delphi

В эту же тему:
У меня получилось перехватывать события автокада (как уровня приложения, так и уровня документа) при импортировании библиотеки типов
однако, такое приложение может не работать на другой машине (более старая/новая версия или ГУИДы другие).
Подскажите, пожалуйста, как я могу перехватывать события автокада, ограничиваясь лишь OleVariant'ами?
Я так понял, мне нужно создать подключиться к ConnectionPoint автокада. Как это сделать?
Заранее благодарю.
Выложу свой код, который не работает :) ЧТобы можно было понять, в ту ли я вообще сторону двигаюсь или нет:

  acApp := CreateOleObject('AutoCAD.Application.17');
  Registry := TRegistry.Create;
  Registry.RootKey := HKEY_CLASSES_ROOT;
  Registry.Access := KEY_QUERY_VALUE;
  if Registry.OpenKey('AutoCAD.Application\CLSID', false) then
      begin
        GUID := StringToGUID(Registry.ReadString(''));
      end;
  if (GetActiveObject(GUID, nil , Unknown) = S_OK) then
//фэйл ниже. "ConnectionPointContainer не поддерживается"
connectionPointContainer := IDispatch(acApp.ConnectionPointContainer) as IConnectionPointContainer;

Re: Как отслеживать события Acad.Applications в Delphi

В этом коде ты уже ограничил себя набором из AutoCAD 2007,2008,2009. У них у всех одна tlb-библиотека, так что если ты импортируешь библиотеку типов, то ничего не потеряешь.