Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: ActiveX/СОМ/CORBA > определить закрыт Word или нет


Автор: Albinos_x 24.4.2005, 12:28
Работаю с компонентами закладки Servis

WordApplication1 и WordDocument1

пытаюсь определить открыт или закрыт Word, так
Код
...
if not VarIsEmpty(WordApplication1.Application) then
...


но эта строка всегда возвращяет - True

Может, кто знает, как правильно определять запущен Word или нет?

Заранее спасибо за помощь! smile

Автор: z-END 24.4.2005, 13:05
попробуй так:
Код

function WordRunning:Boolean;
var 
 temp: Variant;
begin
  try
    temp := GetActiveOleObject('Word.Application');
    Result := true;
  except 
   Result := false;
 end;
end;

Автор: Albinos_x 24.4.2005, 13:12
в каком модуле лежит GetActiveOleObject();

Автор: z-END 24.4.2005, 13:21
помоему в ComObj если нет то нажми хэлп по данной ф-ции и посмотри в описании из какого она модуля.

Автор: Albinos_x 24.4.2005, 13:49
Аналогичная проблема...

Автор: z-END 24.4.2005, 15:09
Цитата(Albinos_x @ 24.4.2005, 14:49)
Аналогичная проблема...

всмысле? опять получается что Ворд запущен?! может он у тя в процессах висит?!

Автор: Albinos_x 24.4.2005, 15:46
Я был не прав определяет... Но не совсем так как мне нужно...

обнаружил следующие косяки
1. Word открыт. Запускаем программу. Документ в ней не создаём. закрываем программу. Закрывается до этого открытый документ + ещё и сохраняется
2. Word закрыт. Запускаем программу. создаём в ней документ. Закрываем документ (Word). Программа выдаёт ошибку.

код
Код

procedure TForm1.SpeedButton1Click(Sender: TObject);
var SaveChanges, templ:olevariant;
    s: string;
begin
// если Word не закрыт
  if WordRunning  then
     begin
     // определяем название и место сохранения документа
     s:=ExtractFilePath(Application.ExeName)+'Temp\отчёт '+ DateToStr(DateTimePicker1.Date);
   // если такой файл уже существует
     while (FileExists(s+'.doc')) do
        begin
    // добавляем к названию 'Copy'
        s:=s+'Copy';
        end;
     Templ:=s+'.doc';
     // если не сохранен, то
     if WordApplication1.ActiveDocument.Saved=false then
          // сохраняем
        WordApplication1.ActiveDocument.SaveAs(Templ, EmptyParam, EmptyParam, EmptyParam,
                                                      EmptyParam, EmptyParam, EmptyParam,
                                                      EmptyParam, EmptyParam, EmptyParam,
                                                      EmptyParam, EmptyParam, EmptyParam,
                                                      EmptyParam, EmptyParam, EmptyParam);
     SaveChanges:=false;
     // Закрываем документ
     //WordApplication1.ActiveDocument.Close(SaveChanges,EmptyParam,EmptyParam);
     end;
Application.Terminate;

Автор: z-END 24.4.2005, 16:18
несовсем понятно что написано..
Цитата(Albinos_x @ 24.4.2005, 16:46)
выдаёт ошибку.

Какую ошибку?

Автор: Albinos_x 24.4.2005, 17:02
ругается, говорит что операция недоступна.
думаю что WordApplication1 не разъединяется с вордом при его закрытии и пытается его закрыть...

Автор: Albinos_x 24.4.2005, 22:20
Кто-нибудь знает как это побороть?


Автор: <Spawn> 25.4.2005, 05:23
Вот еще один способ:

Код

procedure TForm1.Button1Click(Sender: TObject);
var
  Unknown: IUnknown;
  Result: HResult;
begin
  Result := GetActiveObject(ProgIDToClassID('Word.Application'), nil, Unknown);
  if Result = MK_E_UNAVAILABLE then
    ShowMessage('Закрыт')
  else
    ShowMessage('Открыт')
end;

Автор: RA 25.4.2005, 13:17
Можно и так smile
if FindWindow('MsoStdCompMgr',nil)<>0 then caption:='On' else caption:='Off';

Автор: Albinos_x 25.4.2005, 16:44
Цитата
GetActiveObject(ProgIDToClassID('Word.Application'), nil, Unknown);


подскажите в каком модуле она лежит, а то делфя не понимает её...

А через WordApplication1 можно как-нибудь определить, потому что предлогаемые варианты определяют не только мою сессию, но и другие.

Цитата
обнаружил следующие косяки
1. Word открыт. Запускаем программу. Документ в ней не создаём. закрываем программу. Закрывается до этого открытый документ + ещё и сохраняется
2. Word закрыт. Запускаем программу. создаём в ней документ. Закрываем документ (Word). Программа выдаёт ошибку.


1. определять мне надо ворд (документ) , который создался программой
2. если пользователь закрыл ворд (документ), который создался программой, то предотвратить попытку его закрытия при уничтожении WordApplication1
Добавлено @ 16:46
прошу прощения, если немного неправильно выразился при постановки вопроса

Автор: <Spawn> 25.4.2005, 19:05
Цитата
подскажите в каком модуле она лежит, а то делфя не понимает её


ActiveX

Автор: Albinos_x 25.4.2005, 20:40
спасибо,
но это - всё равно не решает мою проблему полностью...

Автор: Albinos_x 26.4.2005, 17:57
Решил проблему....

Код
...
var
  Form1: TForm1;
  CreaDok: OleVariant;
...
CreaDok:=WordApplication1.Documents.Add(EmptyParam,EmptyParam,EmptyParam,EmptyParam);
...
procedure TForm1.SpeedButton1Click(Sender: TObject);
var SaveChanges, templ:olevariant;
    s: string;
begin
WordApplication1.AutoQuit:=false;
try
// определяю закрытие документа
  if not VarIsEmpty(CreaDok) then
     begin
     s:=ExtractFilePath(Application.ExeName)+'Temp\Отчёт '+ DateToStr(DateTimePicker1.Date);
     while (FileExists(s+'.doc')) do
        begin
        s:=s+' Copy';
        end;
     Templ:=s+'.doc';
     // если не сохранён
     if WordApplication1.ActiveDocument.Saved=false then
          // сохраняю
        WordApplication1.ActiveDocument.SaveAs(Templ, EmptyParam, EmptyParam, EmptyParam,
                                                      EmptyParam, EmptyParam, EmptyParam,
                                                      EmptyParam, EmptyParam, EmptyParam,
                                                      EmptyParam, EmptyParam, EmptyParam,
                                                      EmptyParam, EmptyParam, EmptyParam);
     SaveChanges:=false;
     // закрываю документ
     WordApplication1.ActiveDocument.Close(SaveChanges,EmptyParam,EmptyParam);
     // закрываю ворд
     WordApplication1.Application.Quit(SaveChanges,EmptyParam,EmptyParam);
     end;
finally
 // если произошла ошибка
 // а она произойдёт, если пользователь документ закрыл
   WordApplication1.AutoConnect:=false;
   WordApplication1.Destroy;
 Application.Terminate;
 end;
end;
...


Только в Form1Close(), эта штука не работает. Пришлось BorderIcons отключить полностью

Автор: Fantasist 5.5.2005, 09:16
А зачем определять, запущен Word или нет?
Вообще реккомендую закладкой servers не пользоваться. Лучше брать только интерфейсы и создавать объекты в run-time - гораздо меньше происходит неожиданных вещей да и из кода очевидно, что происходит.


Автор: Akella 6.5.2005, 15:38
Значит ты неправильно его закрываешь
нужно так
Код

Var
  Excel:variant;
begin
...

  Excel.Quit;
  Excel := Unassigned;

у меня всё работает

Автор: Albinos_x 7.5.2005, 08:51
Цитата
Значит ты неправильно его закрываешь
нужно так


дело в том что в моём случае ошибка возникает ещё до закрытия и вообще при попытке оперирования с этим документом в программе

Автор: Girder 7.5.2005, 13:22
Albinos_x
1. тебе Fantasist дельный совет дал.
2. Конструкцией try except end - не стоит пренебригать.
3. А если у пользователя 150 документов в Word-е? smile

PS: Не забудь создавать(если у тебя её нет) папку "Temp" - Word - за тебя енто не сделает... smile

Вот код:
Код
uses ComObj;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
const wdFormatDocument = $00000000;
var Word,Doc:IDispatch;
    pn,s:string;
    i:integer;
begin
 try
  Word:=GetActiveOleObject('Word.Application');
 except
  Word:=nil;
 end;
 if Word<>nil then
  begin
   try
    Doc:=Variant(Word).ActiveDocument;
   except
    Doc:=nil;
   end;
  end;
 pn:=ExtractFilePath(ParamStr(0))+'Temp\Отчёт '+DateToStr(Now);
 while Doc<>nil do
  begin
   i:=0;
   while (FileExists(pn+' - '+IntToStr(i)+'.doc')) do inc(i);
   s:=pn+' - '+IntToStr(i)+'.doc';
   try
    if Variant(Doc).Saved=false then
     Variant(Doc).SaveAs(s,wdFormatDocument,EmptyParam,EmptyParam,EmptyParam,EmptyParam,
                         EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam);

   except
   end;
   try
    Variant(Doc).Close(false,EmptyParam,EmptyParam);
    Doc:=Variant(Word).ActiveDocument;
   except
    Doc:=nil;
   end;
  end;
 if Word<>nil then
  begin
   try
    Variant(Word).Application.Quit(false,EmptyParam,EmptyParam);
   except
   end;
  end;
end;


PS2: При запуске кода из под Delphi - могут выдаваться ошибки - но не при обычном запуске проги.

Особо... не отлаживал - так что теоретически... smile могут быть ошибки в коде.

И самое главное... так как ентот код ты хочеш засунуть в OnClose - не забудь выдавать для пользователя какое-нить сообщение... типо "Подождите пожалуйста"... smile

Удачи.

Автор: Fantasist 7.5.2005, 19:04
Girder у нас же описания интерфейсов есть - зачем нам с Dispatcheм мучаться.

Я бы переписал это так:

Код

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
    unk:IUnknown;
    Word:_Application;
    Doc:_Document;
    pn,s:string;
    i:integer;
begin
 GetActiveObject(CLASS_WordApplication,0,unk);
 if unk=nil then exit;

 unk.QueryInterface(_Application,Word);
 if Word<>nil then
 begin
   try
     Doc:=Word.ActiveDocument;
     pn:=ExtractFilePath(ParamStr(0))+'Temp\Îò÷¸ò '+DateToStr(Now);
     while Doc<>nil do
     begin
       i:=0;
       while (FileExists(pn+' - '+IntToStr(i)+'.doc')) do inc(i);

       s:=pn+' - '+IntToStr(i)+'.doc';
       try
        if Doc.Saved=false then
          Doc.SaveAs(s,wdFormatDocument,EmptyParam,EmptyParam,EmptyParam,EmptyParam,
                    EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam);
        Doc.Close(false,EmptyParam,EmptyParam);
       except
       end;

       Doc:=Word.ActiveDocument;
     end;
   except
   end;

   try
     Word.Quit(false,EmptyParam,EmptyParam);
   except
   end;
 end;
end;


Обработка ошибок, конечно, выглядит не очень, но пойдет. smile
Добавлено @ 19:08
Цитата(Girder @ 7.5.2005, 10:22)
3. А если у пользователя 150 документов в Word-е?


Тогда компутер у него сдохнет еще до запуска этой программы. smile

Автор: Albinos_x 7.5.2005, 21:40
Цитата
2. Конструкцией try except end - не стоит пренебригать.


не пренебрегаю... (см. мой вариант)

Цитата
3. А если у пользователя 150 документов в Word-е?


Проверял на 5 одновременно открытых документах - закрывается тот который нужен. (в моём варианте)

Цитата
PS: Не забудь создавать(если у тебя её нет) папку "Temp" - Word - за тебя енто не сделает...


и такое есть...

Цитата
PS2: При запуске кода из под Delphi - могут выдаваться ошибки - но не при обычном запуске проги.


знаю, но всё равно, спасибо за предупреждение...
----------------------------------------------
Цитата
Тогда компутер у него сдохнет еще до запуска этой программы.

smile smile smile

PS: ваши варианты пока не проверял...

Цитата
Вообще рекомендую закладкой servers не пользоваться. Лучше брать только интерфейсы и создавать объекты в run-time - гораздо меньше происходит неожиданных вещей да и из кода очевидно, что происходит.


Когда это понял, уже было поздно переделывать прогу...На тот момент уже около 5 тыс. строк... Даже с коментариями очень сложно осуществлять навигацию... Сейчас прежде чем, чего-то туда вставить, приходится сначала делать оттельно и уже рабочий вариант кода туда вставлять и даже с таким подходом возникают иногда проблеммы (сегодня неожиданно одна процедура, в которую вставлял новую функцию, стала выдавать переполнение стека...)

Спасибо всем за помощь!!! smile smile smile

Автор: Albinos_x 27.6.2005, 22:28
Цитата
PS: ваши варианты пока не проверял...


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

моё конечное решение:

Код
...
var
  Form1: TForm1;
  OpenDoc:boolean = false;
...
// при создании  документа
WordDocument1.ConnectTo(WordApplication1.ActiveDocument);
 OpenDoc:=true;
...
procedure TForm1.WordDocument1Close(Sender: TObject);
begin
OpenDoc:=false;
WordDocument1.Disconnect;
WordApplication1.Disconnect;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var s :string;
    SaveChanges, templ : olevariant;
begin
if OpenDoc then
   begin
   s:=ExtractFilePath(Application.ExeName)+'Temp\отчёт '+ DateToStr(DateTimePicker1.Date);
   while (FileExists(s+'.doc')) do
        begin
        Application.ProcessMessages;
        s:=s+' Copy';
        end;
       Templ:=s+'.doc';
     // если не сохранен, то
     if WordApplication1.ActiveDocument.Saved=false then
          // сохраняем
          begin
         WordApplication1.ActiveDocument.SaveAs(Templ, EmptyParam, EmptyParam, EmptyParam,
                                                        EmptyParam, EmptyParam, EmptyParam,
                                                        EmptyParam, EmptyParam, EmptyParam,
                                                        EmptyParam, EmptyParam, EmptyParam,
                                                        EmptyParam, EmptyParam, EmptyParam);
          end;
     SaveChanges:=false;
     WordApplication1.ActiveDocument.Close(SaveChanges,EmptyParam,EmptyParam);
   end;
end;
...


работает на ура и никаких ошибок не возникает...

еще раз всем спасибо за участие и дельные советы smile

Автор: Akella 30.6.2005, 14:24
При раннем связывании всё работает быстрее и проверка типов и ошибок происходит уже на стадии компилирования
Хотя при позднем связывании тоже есть свои прелести

Автор: Albinos_x 19.7.2005, 17:37
Обнаружил, что при некоторых настройках винды, событие FormClose почему-то не обрабатывается... Поэтому приведённый выше код запихнул в событие FormDestroy(Sender: TObject). Тогда проблем не возникнет...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)