Здравствуйте, Disa, Вы писали:
D>Вот я написал Add-in и он работает в ворде2000 и выше а вот в 97 не хочет работать. D>Вопрос: Ворд 97 поддерживает Add-in если да то какая разница в реализации для Ворда2000? D>или просто поясните ситуацию
Дело в том, что Office97 вообще не поддерживает COM Add-Ins, в частности, в нем не реализован интерфейс IDTExtensibility2, который позволяет внешним программам встраиваться в приложения Office. Ну не то, чтобы совсем не позволяет, просто COM Add-Ins не грузятся автоматически при запуске, то есть мы не можем использовать COM расширения напрямую. Но нам никто не мешает загрузить его вручную и передать ему объект Application!
Некоторые офисные приложения поддерживают глобальные макросы AutoXXX, конкретно для Ворда — это AutoExec(), AutoNew(), AutoOpen(), AutoClose() и AutoExit(), которые вызываются автоматически. Если тебя интересует только Ворд, то объясняю что нужно делать для Ворда:
1. Создай шаблон (*.dot)
2. Открой редактор VBA и создай следующие макросы
Dim o As Application
Dim obj As Object
Sub AutoExec()
Set obj = CreateObject("_ИМЯ_ТВОЕГО_ОБЪЕКТА_")
Set o = ThisDocument.Application
obj.Initialize o
End Sub
Sub AutoExit()
If Not obj Is Nothing Then
obj.UnInitialize
End If
Set obj = Nothing
Set o = Nothing
End Sub
3. Помести этот шаблон в папку Startup и проверь чтобы было разрешено выполнение макросов.
4. Создай у себя в коде методы Initialize и UnInitialize, в который выполни необходимые действия. Например так:
STDMETHODIMP CWTWordAddin::Initialize(IDispatch *Application)
{
CComQIPtr<_Application> pApp(Application);
ATLASSERT(pApp);
if( pApp == NULL )
return S_FALSE;
// далее делай все как обычно
.....
}
P.S. В Office97 ты не сможешь поймать события от кнопок меню и тулбаров Поэтому тебе придется организовавать обработку команд через макросы, но это уже тема отдельного вопроса.
В общем при помощи вышеописанных действий (с отличиями в использовании автомакросов) у меня удалось заставить заработать Add-in в Word97, Excel97, PowerPoint97. В Outlook97 и Access97 пока не получилось.
Re[2]: Add-in в Ворде 2000 работает, а в Ворде97 нет!!!!
Здраствуйте Dmitriy Yakovlev & All. Есть у меня COM-аддин для Word, Excel & PowerPoint. Я понял как передать Application в Ворд 97, а как с меню и тулбаром. Я добавляю их в своем COM сервере, неужели надо делать тоже самое только на ВБА и задавать OnAction для меню и тулбара. Вы, Dmitriy Yakovlev, в своем посте написали что Вам удалось заставить заработать Add-in в Word97, Excel97, PowerPoint97. Плз. поделитесь инфой м если можно куски кода ка поймать события от кнопок меню и тулбаров в 97 офисе
Надеюсь на Вашу помощь, заранее благодарен!!!
Re[2]: Add-in в Ворде 2000 работает, а в Ворде97 нет!!!!
Здравствуйте, globus, Вы писали:
G>Здраствуйте Dmitriy Yakovlev & All. Есть у меня COM-аддин для Word, Excel & PowerPoint. Я понял как передать Application в Ворд 97, а как с меню и тулбаром. Я добавляю их в своем COM сервере, неужели надо делать тоже самое только на ВБА и задавать OnAction для меню и тулбара. Вы, Dmitriy Yakovlev, в своем посте написали что Вам удалось заставить заработать Add-in в Word97, Excel97, PowerPoint97. Плз. поделитесь инфой м если можно куски кода ка поймать события от кнопок меню и тулбаров в 97 офисе
G>Надеюсь на Вашу помощь, заранее благодарен!!!
Нет, VBA я использую по минимуму и все делаю в COM-аддине, чтобы избежать больших различий в реализации под разные версии офиса.
Если Вы разобрались как подключиться к Excel & PowerPoint, тогда мне осталось рассказать как обрабатывать команды. Это намного проще, чем можно себе представить: OnAction можно задать в COM-аддине, а в макросе — организовать обратную связь.
При создании команды нужно не забыть указать OnAction, а также TAG, по которому мы позднее будем идентифицировать команду.
Дополнительно к автомакросам нужно добавить еще один метод OnCmd, который мы указали в OnAction для команды. (Можно использовать любое название для этого метода). В нем мы можем получить тэг вызванной команды, ну а дальше оповестить наш аддин о команде уже дело техники
Sub OnCmd()
If Not obj Is Nothing Then
obj.DoCmd97 CommandBars.ActionControl.Tag
End If
End Sub
DoCmd97 – это сом-метод в моем сом-аддине, из которого передается управление в общий метод обработки команды по ее ТЭГу.
Здравствуйте, Dmitriy Yakovlev, Вы писали:
DY>Здравствуйте, globus, Вы писали:
G>>Здраствуйте Dmitriy Yakovlev & All. Есть у меня COM-аддин для Word, Excel & PowerPoint. Я понял как передать Application в Ворд 97, а как с меню и тулбаром. Я добавляю их в своем COM сервере, неужели надо делать тоже самое только на ВБА и задавать OnAction для меню и тулбара. Вы, Dmitriy Yakovlev, в своем посте написали что Вам удалось заставить заработать Add-in в Word97, Excel97, PowerPoint97. Плз. поделитесь инфой м если можно куски кода ка поймать события от кнопок меню и тулбаров в 97 офисе
G>>Надеюсь на Вашу помощь, заранее благодарен!!!
DY>Нет, VBA я использую по минимуму и все делаю в COM-аддине, чтобы избежать больших различий в реализации под разные версии офиса. DY>Если Вы разобрались как подключиться к Excel & PowerPoint, тогда мне осталось рассказать как обрабатывать команды. Это намного проще, чем можно себе представить: OnAction можно задать в COM-аддине, а в макросе — организовать обратную связь.
DY>При создании команды нужно не забыть указать OnAction, а также TAG, по которому мы позднее будем идентифицировать команду. DY>
DY>Дополнительно к автомакросам нужно добавить еще один метод OnCmd, который мы указали в OnAction для команды. (Можно использовать любое название для этого метода). В нем мы можем получить тэг вызванной команды, ну а дальше оповестить наш аддин о команде уже дело техники DY>
Sub OnCmd()
DY> If Not obj Is Nothing Then
DY> obj.DoCmd97 CommandBars.ActionControl.Tag
DY> End If
DY>End Sub
DY>DoCmd97 – это сом-метод в моем сом-аддине, из которого передается управление в общий метод обработки команды по ее ТЭГу. DY>
Здравствуйте, Dmitriy Yakovlev, Вы писали:
DY>Здравствуйте, Disa, Вы писали:
DY>1. Создай шаблон (*.dot)
DY>2. Открой редактор VBA и создай следующие макросы
DY>
DY>Dim o As Application
DY>Dim obj As Object
DY>Sub AutoExec()
DY> Set obj = CreateObject("_ИМЯ_ТВОЕГО_ОБЪЕКТА_")
DY> Set o = ThisDocument.Application
DY> obj.Initialize o
DY>End Sub
DY>Sub AutoExit()
DY> If Not obj Is Nothing Then
DY> obj.UnInitialize
DY> End If
DY> Set obj = Nothing
DY> Set o = Nothing
DY>End Sub
DY>
DY>3. Помести этот шаблон в папку Startup и проверь чтобы было разрешено выполнение макросов.
DY>4. Создай у себя в коде методы Initialize и UnInitialize, в который выполни необходимые действия. Например так:
DY>
DY>STDMETHODIMP CWTWordAddin::Initialize(IDispatch *Application)
DY>{
DY> CComQIPtr<_Application> pApp(Application);
DY> ATLASSERT(pApp);
DY> if( pApp == NULL )
DY> return S_FALSE;
DY> // далее делай все как обычно
DY> .....
DY>}
DY>
Сделал все как написано, и в ВБА скрипте при вызове "obj.Initialize o" выдает "Ошибка выполнения 13, Несоответствие типа"
менял "Dim o As Application" на "Dim o As Object" не помогло.
В idl у меня
Здравствуйте, globus, Вы писали:
G>Сделал все как написано, и в ВБА скрипте при вызове "obj.Initialize o" выдает "Ошибка выполнения 13, Несоответствие типа" G>менял "Dim o As Application" на "Dim o As Object" не помогло. G>В idl у меня
G>
Dim o As Application
Dim obj As Object
Sub AutoExec()
Set obj = CreateObject("WTOfficeAddin.WTWordAddin.1")
Set o = ThisDocument.Application
obj.Init o
End Sub
Sub AutoExit()
If Not obj Is Nothing Then
obj.Uninit
End If
Set obj = Nothing
Set o = Nothing
End Sub
Sub OnCmd()
If Not obj Is Nothing Then
obj.DoCmd97 CommandBars.ActionControl.Tag
End If
End Sub
Re[3]: Add-in в Ворде 2000 работает, а в Ворде97 нет!!!!
Здравствуйте, Dmitriy Yakovlev, большое спасибо за Вашу поддержку, вот написал
Dim o As Application // или Object - все равно
Sub AutoExec()
Set obj = CreateObject("PXCOfficeAddin.Addin")
Set o = ThisDocument.Application
obj.Initialize o.Application
End Sub
Так работает Вот не понимаю только почему так работает а так
obj.Initialize o
не работает...
Re[4]: Add-in в Ворде 2000 работает, а в Ворде97 нет!!!!
Здравствуйте, globus, Вы писали:
G>Здравствуйте, Dmitriy Yakovlev, большое спасибо за Вашу поддержку, вот написал
Всегда рад
G>
G>Dim o As Application // или Object - все равно
G>Sub AutoExec()
G> Set obj = CreateObject("PXCOfficeAddin.Addin")
G> Set o = ThisDocument.Application
G> obj.Initialize o.Application
G>End Sub
G>
G>Так работает Вот не понимаю только почему так работает а так
G>
G>obj.Initialize o
G>
G>не работает...
Ну, возможно, у нас различия в IDL. Я не особо большой спец, но могу предположить что из-за того у тебя в определении параметра IDispatch *pDisp используется [in], то на вход должен прийти readonly объект и, возможно, для полного соответствия типов тебе приходится передавать именно readonly свойство Application объекта Application. Попробуй убрать [in], посмотри что получится.
Property Application As Application
read-only
Member of Word.Application
Re[5]: Add-in в Ворде 2000 работает, а в Ворде97 нет!!!!
Здравствуйте, Dmitriy Yakovlev, Вы писали:
DY>Ну, возможно, у нас различия в IDL. Я не особо большой спец, но могу предположить что из-за того у тебя в определении
параметра IDispatch *pDisp используется [in], то на вход должен прийти readonly объект и, возможно, для полного соответствия типов тебе приходится передавать именно readonly свойство Application объекта Application. Попробуй убрать [in], посмотри что получится. DY>
DY>Property Application As Application
DY> read-only
DY> Member of Word.Application
DY>
Цетирую из книги Э.Трельсена "Модель СОМ приминение ATL 3.0": "[in] — Посылка от клиента к серверу. Клиент выделяет и освобождает память для этого параметра. Все параметры по умолчанию считаются [in], если не указано другое".
Значит проблема не в этом. Любопытно докопатся до истины, приводимый Вами код (ВБА) у всех работает, никто не жалуется, а у меня как всегда где-то чето... Офис 97 русский.
Re[5]: Add-in в Ворде 2000 работает, а в Ворде97 нет!!!!
Здравствуйте, Dmitriy Yakovlev, по ходу приспосабливания своего аддина под Ворд появились новые к Вам вопросы.
В своем проекте подключаю с помощью директивы #import нужную вордовскую тайп либу (MSWORD.OLB). Ну и работаю через смарт-поинтеры. Так мне проще Возникла одна ситуация, ниже кусок кода:
В ХР офисе на этом месте все нормально, в 97 spLink не NULL (смотрю через Watch m_pInterface = 0x02e5973c и все вроде на месте). cnt = 17 (17 гиперлиннок в документе).
И в ДебагВью вижу:
First-chance exception at 0x00000000 in WINWORD.EXE: 0xC0000005: Access violation reading location 0x00000000.
First-chance exception at 0x7c81eb33 in WINWORD.EXE: 0x80010105: The server threw an exception.
Это hr в Watch-е
hr 0x80010105 The server threw an exception. HRESULT
Тут я подумал, что нельза наверное подключать ТайпЛибы от 2000 офиса 97 офису. Если так, то к Вам вопрос — ка тогда быть, делать ли отдельно для 97 офиса все? я видел в Ваших предыдущих постах код:
значит у Вас отдельный билд для 97 офиса.
И Вы так же само подключаете ТайпЛибы (через #define __OFFICE_97) ?
Я думаю Вы поняли мою проблему, в двох словах — Как надо сделать чтобы работало и в 2000 и в 97 офисе. Но если другие тайплибы, то ведь код совсем другой получется — это ж надо будет с другого неймспейса выбирать интерфейсы. Или возможно, Вы сразу ОЛБ 8 версии подключали и таким образом у Вас работает аддин везде. Да если это так, прийдется переписывать ух-как не хочется то
Уже уверен на 90% что Вы наверное подключали msword8.olb И зачем я 2000 то подключал ....
Заранее Вам благодарен!!!
Re[6]: Add-in в Ворде 2000 работает, а в Ворде97 нет!!!!
Здравствуйте, globus, Вы писали:
G>Здравствуйте, Dmitriy Yakovlev, по ходу приспосабливания своего аддина под Ворд появились новые к Вам вопросы. G>В своем проекте подключаю с помощью директивы #import нужную вордовскую тайп либу (MSWORD.OLB). Ну и работаю через смарт-поинтеры. Так мне проще Возникла одна ситуация, ниже кусок кода:
G>
G>В ХР офисе на этом месте все нормально, в 97 spLink не NULL (смотрю через Watch m_pInterface = 0x02e5973c и все вроде на месте). cnt = 17 (17 гиперлиннок в документе). G>И в ДебагВью вижу:
G>
G>First-chance exception at 0x00000000 in WINWORD.EXE: 0xC0000005: Access violation reading location 0x00000000.
G>First-chance exception at 0x7c81eb33 in WINWORD.EXE: 0x80010105: The server threw an exception.
G>
G>Это hr в Watch-е
G>
G>hr 0x80010105 The server threw an exception. HRESULT
G>
G>Тут я подумал, что нельза наверное подключать ТайпЛибы от 2000 офиса 97 офису. Если так, то к Вам вопрос — ка тогда быть, делать ли отдельно для 97 офиса все? я видел в Ваших предыдущих постах код:
G>значит у Вас отдельный билд для 97 офиса. G>И Вы так же само подключаете ТайпЛибы (через #define __OFFICE_97) ? G>Я думаю Вы поняли мою проблему, в двох словах — Как надо сделать чтобы работало и в 2000 и в 97 офисе. Но если другие тайплибы, то ведь код совсем другой получется — это ж надо будет с другого неймспейса выбирать интерфейсы. Или возможно, Вы сразу ОЛБ 8 версии подключали и таким образом у Вас работает аддин везде. Да если это так, прийдется переписывать ух-как не хочется то G>Уже уверен на 90% что Вы наверное подключали msword8.olb И зачем я 2000 то подключал ....
G>Заранее Вам благодарен!!!
Да Вы абсолютно правы!
У меня есть возможность делать для каждой версии офиса свой билд. Хотя реально для 2000, XP и 2003 я использую один и тот же билд с тайплибами от 2000. А вот для офиса 97 у меня отдельный билд с тайплибами именно от 97 офиса. Насчет совсем другого кода — это громко сказано! на самом деле там набор объектов и методов практически один в один такой же как и в 2000 и некоторые отличия элементарно поправляются при помощи @ifdef...#endif, я и сам не знаю почему я решил делать отдельный билд, просто показалось что так лучше будет. Проект у меня довольно большой, но чтобы все компилировалось под 97 у меня ушло ну может быть день работы. Основное время ушло на переделку кода для MS Access (работа с Reports), хотя у меня так и не получилось подключить его позже
Я Вам рекомендую делать также 2 билда, так как если все сделать на тайплибах от 97 то работать оно будет везде! но вот только придется работать через макросы!!! А это очень существенное ограничение, ведь юзер может настроить политику безопасности так, что макросы будут отключены и тогда ...
А неймспейсы там отличаются только некоторыми классами, я воспользовался директивой #define чтобы привести их название к такому же названию как и в 2000 и выше, поэтому ничего переделавать мне не пришлось!
Здравствуйте, Dmitriy Yakovlev, спасибо Вам за предыдущий пост (оценку поставил ).
Наткнулся еще на одну граблю. Для 97 офиса файл excel8.tli содержит вропер диспинтерфейса, тогда как msword8.tli и msppt8.tli — дуал интерфейса. Теперь в коде метода Init (где добавляются менюшки)
вот в этом фрагменте, при выполнении последней строки выскакикает GPF:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.
This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
Теперь смотрю в Watch на spBars. Иерархия вложенности интерфейсов такова:
Заметьте Office::_IMsoDispObj, у всех других (например, из неймспейса Office) Office::_IMsoDispObj нету — m_pInterface сразу наследуется от IDispatch. но впринципе, проблемы в этом не вижу.
Теперь к импорт директиве дописую no_dual_interfaces:
Вижу что надо чтобы и в Office и в MSEXCEL была реализация либо через виртуальную таблицу (как в случае с вордом и поверпоинтом), либо же через диспинтерфейс.
В МСДН в атрибутах директивы import нашел как отключить диспинтерфейс (no_dual_interfaces), но как задать его нету. Может он установлен по умолчанию, но почему тода для екселя реализация через диспинтерфейс?
Отсюда вижу один выход, задать всем в #import атрибут no_dual_interfaces. Но это ж тормозить будет по сравнению с виртуальной таблицей.
В итоге парочка к Вам вопросов, Dmitriy Yakovlev. Посмотрите на Ваш вропер(файл excel8.tli), Ваша реализация случайно не через диспинтерфейс?
И все остальное в том же духе — через вызов _com_dispatch_method. У Вас также? Если да то как У вас тогда работает, если mso97.tli ведь через виртуальную таблицу?
Я возможно не очень доступно выражаю свои вопросы, и может кое-что не коректно, так как с СОМ-ом я осторожно и "на Вы" но думаю, что моя проблема Вам понятна.
Заранее благодарен!!!
Re[8]: Add-in в Ворде 2000 работает, а в Ворде97 нет!!!!
Решил все-таки запостить в старую тему ответ (или, может, не совсем ответ, а метод).
После долгих исканий и экспериментов результатом использования интерфейсов MSOffice с целью automation были следующие:
Ошибка: "fatal error LNK1179: invalid or corrupt file: duplicate COMDAT
'<identifier name>'"
обходится двумя путями:
1) разнести #import разных либ в *.h и в *.cpp (данный метод не подходит для случая, когда в *.h нужно продефайнить типы)
2) убрать в одной из импортируемых либ "named_guids". Если это можно сделать безболезненно — проблема решена, если
эти гуиды нужны в удобочитаемом виде — придется скопировать их определения из tlh в отдельный хедер и включать его
по необходимости.
Далее:
случайным брожением по tlh-кам было выяснено, что ошибка: "Run-Time Check Failure #0 — The value of ESP was not properly saved across a function call.
This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention."
вылезает в сзязи с тем, что многие методы интерфейсов получают параметрами (возвращают) не указатели на интерфейс, как это описано в
OLE/COM viewer'е, а указатели на IDispatch, от которого наследуется данный интерфейс.
Вариантов решения, опять-таки 2:
1) Использовать Invoke пришедшего указателя на IDispatch нужного интерфейса.
Для некоторых методов это единственное решение, т.к. даже в tlh врапперы соответствующих
методов описаны как принимающие VARIANT * или просто VARIANT.
2) Для некоторых методов достаточно сделать явное получение указателя на необходимый интерфейс с помощью
QueryInterface пришедшего (IDispatch*) указателя.
Вроде все (пока что) .
Как что еще накопаю в дальнейшем — обязательно отсвищу.
Удачи всем в юзании MSOffice automation и всего, что с ним связано.