Форум: "Основная";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.04.25;
Скачать: [xml.tar.bz2];




Вниз

Вопрос по OLE-Automation(ранние связывание) 


kimblch   (2002-04-10 02:29) [0]

Как узнать запусщен ли Word, и как отловить ситуацию когда во время выполнения программы закрывается Word, я раньше использовал позднее связывание там все просто.... а здесь чегото найти не могу как это сделать, мож подскажите



Дмитрий Орехов   (2002-04-10 06:56) [1]

if not VarIsEmpty(XLApp) then
Это у меня для Excel, но думаю принцип тот же. XLApp - это переменная типа Varint.
XLApp:=CreateOleObject("Excel.Application");



kimblch   (2002-04-10 11:16) [2]

>Дмитрий
так в том то и дело........ насколько я знаю то ты привел это есть позднее связывание (CreatOleОbject)... при нем можно использовать функцию GetActiveOleObject("Word")(В контексте try except) и можно... а я же использую ранние связывание у меня переменная типа TWordApplication (что из закладки Servers) когда этой компоненте ставишь свойство AutoConnect=True при запуске приложения автоматически апускается Word, а пользователь может во время работы приложения закрыть ворд и при попытке обратиться к верду выдается соотбщение Сервер RPC не отвечает (Word то закрыт) поэтому такой вопрос и возник... необхожимо при каждой попытке обратиться к верду проверять а запущен ли он........
мож кто посоветует... чтонибудь полезное



Fantasist   (2002-04-10 22:28) [3]


> так в том то и дело........ насколько я знаю то ты привел
> это есть позднее связывание (CreatOleОbject)... при нем
> можно использовать функцию GetActiveOleObject("Word")(В
> контексте try except) и можно... а я же использую ранние
> связывание у меня переменная типа TWordApplication (что
> из закладки Servers) когда этой компоненте ставишь свойство
> AutoConnect=True при запуске приложения автоматически апускается
> Word, а пользователь может во время работы приложения закрыть
> ворд и при попытке обратиться к верду выдается соотбщение
> Сервер RPC не отвечает (Word то закрыт) поэтому такой вопрос
> и возник... необхожимо при каждой попытке обратиться к верду
> проверять а запущен ли он........
> мож кто посоветует... чтонибудь полезное


Не это не раннее связывание. Раннее связывание - это связывание на момент компиляции при помощи информации о типах доступной в Type Library. TWordApplication создает приложение Word через, СreateComObject. Единственно что, он не использует IDispatch вроде. Хотя не уверен.
В общем, должно быть там какое свойство. Можно использовать GetActiveObject - скорее всего, именно эта функция в любом случае используется. Хотя возможен вариант с событиями - ворд наверняка возвращает тебе событие о закрытии. Можно вообще извратиться, после создания word"a получить handle его окна и потом проверять его.



Fantasist   (2002-04-10 22:31) [4]

Да, кстати, OLE-Automatation, как я и сказал, по определению - позднее связывание.



kull   (2002-04-10 23:17) [5]


> if not VarIsEmpty(XLApp) then

Ни фига это не поможет, если Word ручками закроют.
В переменной сылка-то останется...



kimblch   (2002-04-11 02:55) [6]

2 Fantastic
По определению Ole-Automation просто связывание.... а уже оно может быть поздним или ранним.... наверное всетаки так
Да кстати функция CreateOleObject()типа IDispatch, а при раннем связывание используестя переменная другого типа например компонента типа TWordApplication.... т.е. на момент компиляции создан класс, который содержит всю информацию об объекте сервера автоматизации (интерфейс, описание доступных методов и свойств).. так всетаки как можно сделать



Fantasist   (2002-04-11 08:51) [7]


> По определению Ole-Automation просто связывание.... а уже
> оно может быть поздним или ранним.... наверное всетаки так


Нет наверно все-таки не так. :) Automation технологи базирующаяся на использовании IDispatch и переменных типа Variant.

Вот раннее связывание(при использовании FlashPlayer):
var
sh:TShockwavePlayer;
begin
sh:=TShokwavePlayer.Create;
sh.LoadMovie(5,"url");
sh.Play;
end;

позднее:
var
sh:Variant;
begin
sh:=CreateOleObject("Tут ProgID Shockwave"a");
sh.LoadMovie(5,"url");
sh.Play;
end;

Во втором вариенте, компилятор понятие не имеет о том, что за объект будет создан. В первом - знает, получив информацию из TypeLib.





kimblch   (2002-04-11 09:06) [8]

2Fantasist
не это уже прикольно.........
чегото я уже нифига не понимаю кто из нас тупит..... и где
то что ты написал(примеры разных типов связывания) я согласен все правильно только вот CreateOleObject() имеет тип IDispatch как ни крути(не верьшь нажми F1 в Delphi).......... а CreateOleObject() - это позднее связывание (объект создается во время выполнения приложения и на момент компиляции нам о его методах нифига не известно) если я не прав объясните где моя логика дала трещину.....
Кстати в Automation есть еще интерфейс vTAble(Если чо)помимо "IDispatch и переменных типа Variant."
ЗЫ: Я кстати использую метод №1 в твоих примерах ...... вот и хотелосьбы узнать как решить мою проблему



REA   (2002-04-11 10:53) [9]

Я когда свой сервер-клиент писал не придумал сходу как это отследить и заключил все функции в Try Except



Romkin   (2002-04-11 11:07) [10]

В случае Local server соединение в любом случае происходит с использованием IDispatch, в случае импорта библиотеки типов просто проверка вызовов идет на этапе компиляции, и нет вызова GetIDsOfNames (только Invoke)
Поэтому смело подключаемся к запущенному word:

var
A: IDispatch;
AServer: _Application

A := GetActiveOLEObject(...
AServer := A as _Application; //или просто _Application(A);
WordServer.ConnectTo(AServer);

А вот выяснить, закрылся ли сервер, очень непросто, ИМХО невозможно. Просто при обращении выдается исключение.
Поэтому может просто скрывать word сразу после подключения, и показывать только по окончании работы? Второй путь - использовать TOleContainer, и показывать Word в своем приложении



Севостьянов Игорь   (2002-04-11 11:09) [11]

В принципе мой ответ из области предположения, т.к. не пробовал, но...

Активный ли Word - как насчет поиска указателя на окно или на процесс ( FindWindow, EnumThreadWindows, EnumWindows and etc) ?

Закрытие Word - как насчет отлавливания сообщений WM_CLOSE, WM_DESTROY, WM_NCDESTROY для этого окна... ( PeekMessage(Msg, hWnd, 0, 0, PM_REMOVE), GetMessage())
А еще
DWORD WaitForSingleObject(
HANDLE hHandle, // handle of object to wait for
DWORD dwMilliseconds // time-out interval in milliseconds
);


Вопросы по мылу...



Art_east   (2002-04-11 11:50) [12]

2kimblch
Если ты используешь TWordApplication, то отловить ситуацию закрытия Word"а пользователем можно по событию TWordApplication.OnQuit. Здесь Word немножко хулиганит, потому что т.к. на него есть ссылка из твоей проги, следовательно его RefCount>0, следовательно он должен просто уйти в инвизибл (как это делает напримерExcel), но никак не уничтожиться. Но поскольку он всё таки уничтожается можно например прописать в этом событии WordApplication1.Disconnect дабы избавится от ссылки на несуществующий интерфейс, а если в ConnectKind поставить ckRunningOrNew то при следующем обращении Word запустится снова.
А проверить запущен ли Word, можно так
function GetWord: IUnknown;
begin
if not Succeeded(GetActiveObject(ProgIDToClassID("Word.Application"), nil, Result)) then
Result := CreateComObject(ProgIDToClassID("Word.Application"));
WordApplication1.ConnectTo((pUnk as _Application));
end

WordApplication1.ConnectTo((GetWord as _Application));

что собственно и делает TWordApplication в методе Connect при ConnectKind = ckRunningOrNew



Севостьянов Игорь   (2002-04-11 13:01) [13]

Да похоже Art_east (11.04.02 11:50) прав и это будет наиболее оптимальный вариант решения проблемы
Желаю удачи



serg   (2002-04-11 13:36) [14]

Что-то не понимаю...
А почему бы не воспользоваться TWordApplication.OnQuit ?



Fantasist   (2002-04-11 21:09) [15]


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


Ха!
Я в своем первом постинге предложил три способа:

1. Обрабатывать сообщения от Word.
2. Использовать GetActiveObject.
3. Брать Handle окна Word"a при его создании и дальше вертеться вокруг него.



Fantasist   (2002-04-11 22:47) [16]


> чегото я уже нифига не понимаю кто из нас тупит..... и где
> то что ты написал(примеры разных типов связывания) я согласен
> все правильно только вот CreateOleObject() имеет тип IDispatch
> как ни крути(не верьшь нажми F1 в Delphi).......... а
> CreateOleObject() - это позднее связывание (объект создается
> во время выполнения приложения и на момент компиляции нам
> о его методах нифига не известно) если я не прав объясните
> где моя логика дала трещину.....
> Кстати в Automation есть еще интерфейс vTAble(Если чо)помимо
> "IDispatch и переменных типа Variant."


Так, интересно, давайте разберемся.
Что есть ранее и позднее связывание? Давайте определим так:
* ранее связывание - это вызовы методов через vtable.
* позднее - вызов методов через IDispatch::GetIDsOfNames() и IDispatch::Invoke()

Вроде не наврал. Давайте теперь специально лезу в Word2000.pas.
Метод Сonnect:

var
punk: IUnknown;
begin
if FIntf = nil then
begin
punk := GetServer;
ConnectEvents(punk);
Fintf:= punk as _Application;
end;
end;

вызываетcя TOleServer.GetServer и создается там это таким образом:


if not Succeeded(GetActiveObject(FServerData^.ClassId, nil, Result)) then
Result := CreateComObject(FServerData^.ClassId);


(Тут, кстати, используется GetActiveObject, как предлогал я)
Ага.Получаем IUnknown и преобразуем его к _Application, который является дуальным интерфейсом. Дальше методы TWordApplication вызываются используя этот интерфейс, значит по vtable, и значит тут все-таки ранее связывание согласно вышеданному соглашению(коламбур :) ), я ошибался. Почти. Ибо TWordApplicationProperties преобразует этот интерфейс к IDsipatch(через OleVariant) и пользуется им. Значит у нас присутсвуют оба способа связывания.

Vtable как и интерфейс относятся к понятию COM. Automatation - это технология использующая COM, так что их смешивать не надо. Хотя я тут говорить не буду, почему-то терминология в COM слегка не однозначна. Мне всегда казалось, что Automataion именно основан на использовании IDispatch и Variant. Но может где-то этот термин понимается по другому, или его надо понимать по другому.

И вот еще что. Когда вы делаете так:

var
Word:TWordApplication;
begin
Word:=TWordApplication.Create;
end;

вы создаете паскалевский(делфийский) экземпляр класса, но никак не СOM-объект. COM-объект создается уже внутри этого класса и к его созданию вы никакого отнашение не имеете и повлиять не можете. То, что я показывал в первом примере (с ShockWave) - это совсем другое.



kimblch   (2002-04-12 02:57) [17]

2Art_east
попытался сделать твоим методом

>function GetWord: IUnknown;
>begin
> if not Succeeded(GetActiveObject(ProgIDToClassID
>("Word.Application"), nil, Result)) then
> Result := CreateComObject(ProgIDToClassID
>("Word.Application"));
> WrdApp.ConnectTo((pUnk as _Application));
>end;

только вот дельфи5 ругается на GetActiveObject не может найти такую функцию help тоже молчит
Подскажите пожалуйста что не так.... мож какой модуль не прописан (ComObj прописан)



kimblch   (2002-04-12 03:48) [18]

наверно так умею только я.......
написал чегото ..... плохо понимая что это. так эта фигня еще и работает... :)
короче перед тем как обратиться к верду вызываю GetWord(); и уже не важно запусщен ли ворд или нет

procedure GetWord();
begin
try
wrdApp.ConnectTo(wrdApp.Application as _Application);
except
MainForm.FormCreate(MainForm);
end;
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
wrdApp:=TWordApplication.Create(Self);
with wrdApp do
begin
ConnectKind := ckRunningOrNew;
AutoConnect := True;
AutoQuit := False;
Visible:=True;
end;
end;


ВОПРОС ВОТ В ЧЕМ коректно ли так делать.... будет ли освобождаться память... глюки всякие не полезут... (а то всякие объекты классы, я тут просто запутался)



Art_east   (2002-04-12 15:53) [19]

2kimblch
Относительно твоего сообщения (12.04.02 02:57): GetActiveObject лежит в модуле ActiveX.
А насчёт примера (12.04.02 03:48) имхо происходит следующее:
когда ты вызываешь wrdApp.ConnectTo(wrdApp.Application as _Application); при закрытом пользователем в процессе работы Word"е, то идёт идёт обращение к методу _Application.Get_Application (см. Word97.pas или Word2000.pas они лежат в ProgramFiles\Borland\Delphi5\Ocx\Servers), а поскольку _Application (это интерфейс через который TWordApplication Общается с Word"ом)уже не существует, у тебя валится эксепшн и ты идёшь в FormCreate где заново создаешь уже существующий wrdApp. Если тебя не смущает лишний эксепшн и создание нового TWordApplication при каждом обращении в Word"у, то хотя бы пропиши в Except wrdApp.Free перед FormCreate дабы память не захламлять, а то мало ли чего, вдруг она тебе ещё пригодится :)
хотя по-моему мой вариант оптимальнее, но как говорится хозяин барин
желаю удачи




Форум: "Основная";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.04.25;
Скачать: [xml.tar.bz2];




Наверх





Память: 0.79 MB
Время: 0.031 c
1-80993           Vova33                2002-04-12 16:53  2002.04.25  
Пакеты


7-81093           VS                    2002-01-31 09:35  2002.04.25  
Как при поиске файла на диске переключиться на следующий диск


14-81043          flomo                 2002-03-19 20:36  2002.04.25  
маленькая проблема


1-80890           Doctor Deejay         2002-04-14 17:21  2002.04.25  
Снова RichEdit


14-81055          Елена                 2002-03-20 07:06  2002.04.25  
Как сделатьтак, чтобы компонент думал, будто запущена Делфи?