Модераторы: MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Word при закрытие выдает access violation, Add-ins в Word 
:(
    Опции темы
cemick
Дата 17.5.2007, 19:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 416
Регистрация: 6.7.2006
Где: Санкт-Петербург

Репутация: 1
Всего: 6



Добрый день. Диплом горит!
У меня Add-ins к ворду. Делал все по Тенцеру, ни чего лишнего, все как у Тенцера. Когда закрываю Word дебугер ловит access  vilation at 0x000000000. Дело именно в проекте, ошибка повторяеться в раных системах. Может у кого то, что то подобное было?
В чем может быть проблема?
И почему у Тенцера на ondisconnect удаляется только кнопка, а панель остаеться?
 
Вот код:
Код

unit ComServerUnit;

{$WARN SYMBOL_PLATFORM OFF}

interface

uses
  ComObj, ActiveX, ErQR_TLB,Variants,Word_TLB,
  Office_TLB,ComAddinUtils, MacrosUnit;

type
  TDEwinReport = class(TAutoObject, IDTExtensibility2)
  private
    Host: WordApplication;
    FButtonEventsSink: TCommandButtonEventSink;
    Bar: CommandBar;
    Button: CommandBarButton;
    MacrosObj:TInterpreter;
    procedure ButtonClick(Button: CommandBarButton;
      var CancelDefault: WordBool);
  protected
    procedure BeginShutdown(var custom: PSafeArray); safecall;
    procedure OnAddInsUpdate(var custom: PSafeArray); safecall;
    procedure OnConnection(const HostApp: IDispatch; ext_ConnectMode: Integer;
      const AddInInst: IDispatch; var custom: PSafeArray); safecall;
    procedure OnDisconnection(ext_DisconnectMode: Integer; var custom: PSafeArray);
      safecall;
    procedure OnStartupComplete(var custom: PSafeArray); safecall;

  end;
const
  BUTTON_TAG = '{F3C838C9-D661-468B-9045-E96DE887D32E}';
implementation

uses ComServ,ShlObj,Windows,SysUtils;

procedure TDEwinReport.BeginShutdown(var custom: PSafeArray);
begin

end;

procedure TDEwinReport.OnAddInsUpdate(var custom: PSafeArray);
begin

end;

procedure TDEwinReport.OnConnection(const HostApp: IDispatch;
  ext_ConnectMode: Integer; const AddInInst: IDispatch; var custom: PSafeArray);
const msoBarFloating = 4;
//const msoControlComboBox = 4;

begin
//  MacrosObj := TInterpreter.Create;
//  MacrosObj.Destroy;
  // Сохраняем ссылку на WordApplication
  Host := HostApp as WordApplication;
  // Создаем обработчик событий для кнопки
  FButtonEventsSink := TCommandButtonEventSink.Create;
  FButtonEventsSink.OnClick := ButtonClick;
  // Создаем панельку
  Bar := Host.CommandBars.Add('ErWin AddIns panel',msoBarFloating,False,True);
  Bar.Enabled:=true;
  Bar.Visible:=true;
  //Bar.Controls.Add( msoControlComboBox, 1,EmptyParam,EmptyParam,EmptyParam);
  // Проверяем наличие на ней нашей кнопки
  Button := Bar.FindControl(msoControlButton, EmptyParam, BUTTON_TAG,
    EmptyParam, msoFalse) as CommandBarButton;
  if not Assigned(Button) then
    // Если её нет - создаем
    Button := Bar.Controls.Add(msoControlButton, EmptyParam,
      BUTTON_TAG, 1, EmptyParam) as CommandBarButton;
  // Подключаем обработчик и устанавливаем свойства кнопки
  FButtonEventsSink.Connect(Button);
  Button.Set_Style(msoButtonIconAndCaption);
  Button.Set_Tag(BUTTON_TAG);
  Button.Set_FaceId(43);
  Button.Set_Caption('Connect to ErWin');

//  MacrosObj.GlobalModelName:='_';

end;

procedure TDEwinReport.OnDisconnection(ext_DisconnectMode: Integer;
  var custom: PSafeArray);
var
   Bar: CommandBar;
   B: CommandBarControl;
begin

     // Уничтожаем обработчик событий кнопки
   FreeAndNil(FButtonEventsSink);
   // Ищем свою кнопку
   Bar := Host.CommandBars.Get_Item('ErWin AddIns panel');
   B := Bar.FindControl(msoControlButton, EmptyParam, BUTTON_TAG,
     EmptyParam, msoFalse) as CommandBarButton;
   // И удаляем ее
   if Assigned(B) then
     B.Delete(msoFalse);
   //Bar.Delete;}   
end;

procedure TDEwinReport.OnStartupComplete(var custom: PSafeArray);
begin

end;

procedure TDEwinReport.ButtonClick(Button: CommandBarButton;
  var CancelDefault: WordBool);
var
  D: WordDocument;
  Patch: OleVariant;
  FErWinDocName, FWordDocName: string;
  WordBool:OleVariant;
 // timer:Itimer
begin
//Patch:=Host.NormalTemplate.Path + '\ErWinTemplate1.dot';
  MessageBox(0,'hi!','mm',mb_Ok);
{if MacrosObj.GetFileNameFromBrowse(0, FWordDocName, 'c:\', '*.doc',
      'Файлы MSWord '#0'*.doc'#0'Все файлы'#0'*.*'#0#0      , 'Выбор файла MsWord') then
  Patch:=FWordDocName else
  begin
    MessageBox(0,'Не выбран файл','Внимание!',MB_ICONWARNING);
    exit;
  end;
  WordBool := true;
  d:= Host.Documents.Add(Patch, EmptyParam, EmptyParam, WordBool);
  //Host.Documents.AddOld(Patch, EmptyParam);
  if MacrosObj.GetFileNameFromBrowse(0, FErWinDocName, 'c:\', '*.er1',
  'Файлы ERwin '#0'*.er1'#0'Все файлы'#0'*.*'#0#0      , 'Выбор файла ErWin') then
  begin
    MacrosObj.GlobalModelName := '_';
   d.Application.Visible := false;
   //MacrosObj.MSWordMacros(D,PAnsiChar(FErWinDocName),host);
   MacrosObj.MSWordMacrosVer2(D,PAnsiChar(FErWinDocName),host);
    //MacrosObj.MSWordMacrosTest(D,PAnsiChar(FErWinDocName),host);
   d.Application.Visible := true;
   d.Activate;
  end;
}
end;

initialization
  TAutoObjectFactory.Create(ComServer, TDEwinReport, Class_TDTExtensibility2,
    ciMultiInstance, tmApartment);
end.


Код

{
 Вспомогательные функции для реализации интерфейса IDispatch
 Реализация интерфейса с Ms.Word
}
unit ComAddInUtils;

interface

uses ActiveX, Office_TLB, ComObj, SysUtils, Windows;

type
  TBaseSink = class(TObject, IUnknown, IDispatch)
  protected
    { методы IUnknown }
    function QueryInterface(const IID: TGUID; out Obj): HResult;
      stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
    { методы IDispatch }
    function GetIDsOfNames(const IID: TGUID; Names: Pointer;
      NameCount, LocaleID: Integer; DispIDs: Pointer): HResult;
      virtual; stdcall;
    function GetTypeInfo(Index, LocaleID: Integer;
      out TypeInfo): HResult; virtual; stdcall;
    function GetTypeInfoCount(out Count: Integer): HResult;
      virtual; stdcall;
    function Invoke(DispID: Integer; const IID: TGUID;
      LocaleID: Integer; Flags: Word; var Params;
      VarResult, ExcepInfo, ArgErr: Pointer): HResult;
      virtual; stdcall;
  private
    FCookie: Integer;
    FCP: IConnectionPoint;
    FSinkIID: TGuid;
    FSource: IUnknown;

    function DoInvoke(DispID: Integer; const IID: TGUID;
      LocaleID: Integer;  Flags: Word; var dps: TDispParams;
      pDispIds: PDispIdList;  VarResult, ExcepInfo,
      ArgErr: Pointer): HResult; virtual; abstract;

  public
    destructor Destroy; override;
    procedure Connect(pSource : IUnknown);
    procedure Disconnect;
    property SinkIID: TGuid read FSinkIID;
    property Source: IUnknown read FSource;
  end;
//------------------------------------------------------------------------------
type
  _CommandBarButtonEvents = dispinterface
    ['{000C0351-0000-0000-C000-000000000046}']
    procedure Click(const Ctrl: CommandBarButton; 
      var CancelDefault: WordBool); dispid 1;
  end;

type
  // Обработчик события нажатия на кнопку
  TOnCommandButtonClick = procedure (Button: CommandBarButton;
     var CancelDefault: WordBool) of object;

  TCommandButtonEventSink = class(TBaseSink)
  private
    FOnClick: TOnCommandButtonClick;
  protected
    procedure DoClick(Button: CommandBarButton;
      var CancelDefault: WordBool); virtual;
    function DoInvoke (DispID: Integer; const IID: TGUID;
      LocaleID: Integer; Flags: Word; var dps : TDispParams; 
      pDispIds : PDispIdList; VarResult, ExcepInfo, 
      ArgErr: Pointer): HResult; override;

  public
    constructor Create; virtual;
    property OnClick: TOnCommandButtonClick 
      read FOnClick write FOnClick;
  end;


implementation

{===============================================================================
START of BaseSink realization}

function TBaseSink.QueryInterface(const IID: TGUID;
  out Obj): HResult;
begin
  Result := E_NOINTERFACE;
  Pointer(Obj) := NIL;
  if GetInterface(IID, Obj) then
    Result := S_OK;
  // если запрашивается интерфейс SinkIID - 
  // возвращаем свой IDispatch
  if not Succeeded(Result) then
    if IsEqualIID(IID, FSinkIID) then
      if GetInterface(IDispatch, Obj) then
        Result := S_OK;
end;

procedure TBaseSink.Connect(pSource: IUnknown);
var
  pcpc: IConnectionPointContainer;
begin
  Disconnect;
  try
    // Запрашиваем интерфейс IConnectionPointContainer у объекта-
    // источника событий
    OleCheck(pSource.QueryInterface(IConnectionPointContainer,
      pcpc));
    // Запрашиваем интерфейс IConnectionPoint.
    OleCheck(pcpc.FindConnectionPoint(FSinkIID, FCP));
    // Подключаемся к обработчику событий
    OleCheck(FCP.Advise(Self, FCookie));
    // Все прошло успешно - устанавливаем свойство Source
    FSource := pSource;
  except
    raise Exception.Create(Format('Unable to connect %s.'#13'%s',
      [ClassName, Exception(ExceptObject).Message]));
  end;
end;

procedure TBaseSink.Disconnect;
begin
  if FSource = NIL then
    Exit;
  try
    OleCheck(FCP.Unadvise(FCookie));
    FCP := NIL;
    FSource := NIL;
  except
    Pointer(FCP) := NIL;
    Pointer(FSource) := NIL;
  end;
end;

function TBaseSink._AddRef: Integer;
begin
  Result := 2;
end;

function TBaseSink._Release: Integer;
begin
   Result := 1;
end;

function TBaseSink.GetIDsOfNames(const IID: TGUID; Names: Pointer;
      NameCount, LocaleID: Integer; DispIDs: Pointer): HResult;
begin
   Result := E_NOTIMPL;
end;

function TBaseSink.GetTypeInfo(Index, LocaleID: Integer;
      out TypeInfo): HResult;
begin
   Result := E_NOTIMPL;
  pointer (TypeInfo) := NIL;
end;

function TBaseSink.GetTypeInfoCount(out Count: Integer): HResult;
begin
    Result := E_NOTIMPL;
    Count := 0;
end;

procedure BuildPositionalDispIds (pDispIds : PDispIdList; const dps : TDispParams);
var
  i : integer;
begin
  Assert (pDispIds <> NIL);

  { меняем местами аргументы }
  for i := 0 to dps.cArgs - 1 do
    pDispIds^ [i] := dps.cArgs - 1 - i;

  { проверка на непустые аргументы }
  if (dps.cNamedArgs <= 0) then Exit;

  { обработка аргументов }
  for i := 0 to dps.cNamedArgs - 1 do
    pDispIds^ [dps.rgdispidNamedArgs^ [i]] := i;
end;
//

function TBaseSink.Invoke(DispID: Integer; const IID: TGUID;
      LocaleID: Integer; Flags: Word; var Params;
      VarResult, ExcepInfo, ArgErr: Pointer): HResult;

var
  dps : TDispParams absolute Params;
  bHasParams : boolean;
  pDispIds : PDispIdList;
  iDispIdsSize : integer;
begin
//do you still believe?

if (Flags AND DISPATCH_METHOD = 0) then
    raise Exception.Create (
      Format ('%s only supports sinking of method calls!', [ClassName]
    ));

pDispIds := NIL;
iDispIdsSize := 0;
bHasParams := (dps.cArgs > 0);
if (bHasParams) then
  begin
    iDispIdsSize := dps.cArgs * SizeOf (TDispId);
    GetMem (pDispIds, iDispIdsSize);
  end;

try
    { rearrange dispids properly }
    if (bHasParams) then BuildPositionalDispIds (pDispIds, dps);
    Result := DoInvoke (DispId, IID, LocaleID, Flags, dps, pDispIds, VarResult, ExcepInfo, ArgErr);
  finally
    { free pDispIds array }
    if (bHasParams) then FreeMem (pDispIds, iDispIdsSize);
  end;  { finally }
end;

destructor TBaseSink.Destroy;
begin
  Disconnect;
  inherited;
end;

{END of BaseSink realization
===============================================================================}
{===============================================================================
START of CommandBarButton realization}

constructor TCommandButtonEventSink.Create;
begin
  inherited;
  FSinkIID := _CommandBarButtonEvents;
end;

procedure TCommandButtonEventSink.DoClick(Button: CommandBarButton;
  var CancelDefault: WordBool);
begin
  if Assigned(FOnClick) then
    FOnClick(Button, CancelDefault);
end;

function TCommandButtonEventSink.DoInvoke(DispID: Integer;
  const IID: TGUID; LocaleID: Integer; Flags: Word;
  var dps: TDispParams; pDispIds: PDispIdList;
  VarResult, ExcepInfo, ArgErr: Pointer): HResult;
begin
  Result := S_OK;
  case DispID of
    // Для этого DispId передаются 2 параметра - CommandBarButton
    // и WordBool
    1 : DoClick(IUnknown(dps.rgvarg^[pDispIds^[0]].unkVal)
          as CommandBarButton, dps.rgvarg^[pDispIds^[1]].pbool^);
  else
    Result := DISP_E_MEMBERNOTFOUND;
  end;
end;

{END of CommandBarButton realization
===============================================================================}
end.


Точнее, ошибку выдает при выгрузке модуля. Причем фатальную для ворда.

Это сообщение отредактировал(а) cemick - 18.5.2007, 01:04
PM MAIL WWW   Вверх
Albinos_x
Дата 18.5.2007, 02:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Evil Skynet
****


Профиль
Группа: Комодератор
Сообщений: 3288
Регистрация: 28.5.2004
Где: X-6120400 Y-1 4624650

Репутация: 15
Всего: 108



возможно ворд сам пытается освободить твою кнопку, освобождение происходит два раза,в результате ошибка...


--------------------
"Кто владеет информацией, тот владеет миром"    
Уинстон Черчилль
PM MAIL ICQ   Вверх
cemick
Дата 18.5.2007, 12:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 416
Регистрация: 6.7.2006
Где: Санкт-Петербург

Репутация: 1
Всего: 6



Пробовал комментить все, что находиться в ondisconnect, разницы ни какой.

Кто нибудь может объяснить, зачем в папке import валяются библиотеки типов. Чем отличается, допустим WORD_TLB.pas который валяется там, от того, который можно получить используя Import Library? Просто, давно как то уже делал add-ins используя модули из папки import и все работало, теперь же, то же самое(вроде), только воспользовался  Import Library и вот такая ерунда. smile 

Попробовал еще кнопку не создавать. Дак вот, все равно ошибка. От без исходности переставил ось - толку ни какого.
PM MAIL WWW   Вверх
cemick
Дата 23.5.2007, 15:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 416
Регистрация: 6.7.2006
Где: Санкт-Петербург

Репутация: 1
Всего: 6



Решилась проблема как всегда неожиданно. Всему виной оказался подключенный модуль ShareMem. Подключил потому, что в одной из книжек прочитал, если в dll работаем с динамической памятью, то для корректной работы с ней необходимо подключать сей модуль. Для чего он  тогда нужен?
PM MAIL WWW   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: ActiveX/СОМ/CORBA"

Rrader
Girder

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами


  • Литературу по Delphi обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Delphi
  • Вопросы по SQL и вопросы по базам данных, не связанные с Delphi, задавать здесь

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Rrader, Girder.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: ActiveX/СОМ/CORBA | Следующая тема »


 




[ Время генерации скрипта: 0.0675 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.