Обработка событий MSOffice, IDispEventSimpleImpl
От: BorysB  
Дата: 19.03.05 12:42
Оценка:
Здравствуйте. Я сейчас пишу Addin для MSWord. Мне необходимо реализовать запрет печати. Я использую IDispEventSimpleImpl интерфейс. Наследуюсь от него таким образом:

public IDispEventSimpleImpl<1,CAddin, &__uuidof(MSWord::ApplicationEvents2)>


С помощью OLE/COM Object Viewer нахожу ApplicationEvents2 и нужный мне метод DocumentBeforePrint:

[id(0x00000007), helpcontext(0x00061a86)]
void DocumentBeforePrint(
[in] Document* Doc,
[in] VARIANT_BOOL* Cancel);

Заполняю структуру:
_ATL_FUNC_INFO DocumentBeforePrintInfo = {CC_STDCALL, VT_EMPTY, 2, {VT_DISPATCH|VT_BYREF, VT_BOOL|VT_BYREF}};


Ф-я обработчик выглядит так:

void __stdcall CAddin::DocumentBeforePrint(IDispatch* /*_Document**/ Doc, VARIANT_BOOL *Cancel)
{        
USES_CONVERSION;
    
    _Document* myDoc = (_Document*)Doc;
    HRESULT hr = m_spApp->get_ActiveDocument(&myDoc);
    
    BSTR bstr;
    myDoc->get_Name(&bstr);
        
    CComBSTR b_string = bstr;
    MessageBox(NULL, W2T(b_string), W2T(b_string), MB_OK);
    
    VARIANT_BOOL *myCancel = new VARIANT_BOOL(VARIANT_TRUE);
        
    Cancel = myCancel;
    MessageBox(NULL, "Document is going to be printed", "Message", MB_OK);
}


Дело в том, что все работает, только VARIANT_BOOL *Cancel игнорируется. Я пытался записывать структуру так:

_ATL_FUNC_INFO DocumentBeforePrintInfo = {CC_STDCALL, VT_EMPTY, 2, {VT_DISPATCH, VT_BOOL}};

Пока не могу найти решения. Где-то прочитал, что подобная проблема была при использовании .NET, но она, как пишет Microsoft, исправлена в Офисе 2003. У меня .Net установлен, но этот проект я пишу на VC++6.
Может у кого-то были подобные проблемы. Подскажите что делать.
И еще, как правильно заполнять _ATL_FUNC_INFO, в часности, когда указывать VT_BYREF в зависимости от [in] [out]. Я видел несколько примеров и везде по-разному, у меня ПОКА работает и так, и так.



19.03.05 17:57: Перенесено модератором из 'C/C++. Прикладные вопросы' — Odi$$ey
Re: Обработка событий MSOffice, IDispEventSimpleImpl
От: Elena_ Россия  
Дата: 19.03.05 22:38
Оценка:
Здравствуйте, BorysB, Вы писали:

BB>Я сейчас пишу Addin для MSWord. Мне необходимо реализовать запрет печати. Я использую IDispEventSimpleImpl интерфейс.

BB>Ф-я обработчик выглядит так:
BB>
BB>void __stdcall CAddin::DocumentBeforePrint(IDispatch* /*_Document**/ Doc, VARIANT_BOOL *Cancel)
BB>{        
BB>    VARIANT_BOOL *myCancel = new VARIANT_BOOL(VARIANT_TRUE);
BB>    Cancel = myCancel;
BB>    MessageBox(NULL, "Document is going to be printed", "Message", MB_OK);
BB>}
BB>


BB>Дело в том, что все работает, только VARIANT_BOOL *Cancel игнорируется.


А если просто
*Cancel = VARIANT_TRUE;

тогда что?
Пользователь — друг программиста!
Re[2]: Обработка событий MSOffice, IDispEventSimpleImpl
От: BorysB  
Дата: 20.03.05 09:12
Оценка:
Здравствуйте, Elena_, Вы писали:

E_>А если просто

E_>
E_>*Cancel = VARIANT_TRUE;
E_>

E_>тогда что?

На сколько я помню таком случае Ворд падает, т.к. Cancel указывает на "плохую" область памяти. Именно поэтому я выделяю память под новую переменную. Но я попробуюю еще раз и скажу точно.
Re[3]: Обработка событий MSOffice, IDispEventSimpleImpl
От: Elena_ Россия  
Дата: 20.03.05 15:27
Оценка:
Здравствуйте, BorysB, Вы писали:

E_>>А если просто

E_>>
E_>>*Cancel = VARIANT_TRUE;
E_>>

E_>>тогда что?

BB>На сколько я помню таком случае Ворд падает, т.к. Cancel указывает на "плохую" область памяти.


Тогда, может быть, где-то еще в программе портится память.

BB>Именно поэтому я выделяю память под новую переменную.


Насколько я понимаю, таким кодом
BB>void __stdcall CAddin::DocumentBeforePrint(IDispatch* /*_Document**/ Doc, VARIANT_BOOL *Cancel)
BB>{        
BB>    VARIANT_BOOL *myCancel = new VARIANT_BOOL(VARIANT_TRUE);
BB>    Cancel = myCancel;
BB>}

Вы вообще ничего не передаете для вызывающей программы, кроме того выделяете память, которая не будет освобождена, так что в любом случае вряд ли этот код подходит
Пользователь — друг программиста!
Re[2]: Обработка событий MSOffice, IDispEventSimpleImpl
От: BorysB  
Дата: 21.03.05 11:51
Оценка:
Здравствуйте, Elena_, Вы писали:
E_>А если просто
E_>
E_>*Cancel = VARIANT_TRUE;
E_>

E_>тогда что?

Все так как я говорил.
При попытке сделать
_ATL_FUNC_INFO DocumentBeforePrintInfo = {CC_STDCALL, VT_EMPTY, 2, {VT_DISPATCH, VT_BOOL}};
...
*Cancel = VARIANT_TRUE;

Получаем при попытке выполнить *Cancel = VARIANT_TRUE:
Unhandeled exeption in WINWORD.EXE (WORDADDIN.DLL):0XC0000005: Accsess Violation
(WORDADDIN.DLL — имя моей длл)


При попытке сделать
_ATL_FUNC_INFO DocumentBeforePrintInfo = {CC_STDCALL, VT_EMPTY, 2, {VT_DISPATCH|VT_BYREF, VT_BOOL|VT_BYREF}};
...
*Cancel = VARIANT_TRUE;

Получаем ошибку после выхода из фуккции (когда управление снова у Ворда):
Unhandeled exeption in WINWORD.EXE :0XC0000005: Accsess Violation

Такое впечатление, что указатели не указывают ни на что. Поэтому я и выделяю память.
Re[4]: Обработка событий MSOffice, IDispEventSimpleImpl
От: BorysB  
Дата: 21.03.05 12:13
Оценка:
Здравствуйте, Elena_, Вы писали:

E_>Насколько я понимаю, таким кодом

E_>
BB>>void __stdcall CAddin::DocumentBeforePrint(IDispatch* /*_Document**/ Doc, VARIANT_BOOL *Cancel)
BB>>{        
BB>>    VARIANT_BOOL *myCancel = new VARIANT_BOOL(VARIANT_TRUE);
BB>>    Cancel = myCancel;
BB>>}
E_>

E_>Вы вообще ничего не передаете для вызывающей программы, кроме того выделяете память, которая не будет освобождена, так что в любом случае вряд ли этот код подходит

Почему таким образом я ничего не передаю? Я эту кашу понимаю следующим образом:
Ворд, судя по всему, — вызывает мою функцию. Я используюю _ATL_FUNC_INFO DocumentBeforePrintInfo = {CC_STDCALL... т.е. stdcall CallingConvention. Следовательно Ворд должен чистить память (The callee cleans the stack. This is the default convention for calling unmanaged functions with platform invoke. MSDN).
Если все правильно то параметры должны передаваться по ссылке:

_ATL_FUNC_INFO DocumentBeforePrintInfo = {CC_STDCALL, VT_EMPTY, 2, {VT_DISPATCH|VT_BYREF, VT_BOOL|VT_BYREF}};


Но я не уверен. И вообще я не могу четко понять относительно кого по ссылке. Моя функция выполняет роль call-back функции и вызывается вместо соответствующей функции этого интерфейса.

id(0x00000007), helpcontext(0x00061a86)]
void DocumentBeforePrint(
[in] Document* Doc,
[in] VARIANT_BOOL* Cancel);

Тогда параметры должны передаваться мне,..по ссылке?........? Почти ничего не понимаю.
Re[5]: Обработка событий MSOffice, IDispEventSimpleImpl
От: Vi2 Удмуртия http://www.adem.ru
Дата: 21.03.05 12:34
Оценка:
Здравствуйте, BorysB, Вы писали:

Для функции
BB>id(0x00000007), helpcontext(0x00061a86)]
BB>void DocumentBeforePrint([in] Document* Doc, [in,out] VARIANT_BOOL* Cancel);

управляющий код данных будет:
BB>_ATL_FUNC_INFO DocumentBeforePrintInfo = {CC_STDCALL, VT_EMPTY, 2, {VT_DISPATCH, VT_BOOL|VT_BYREF}};

BB>Тогда параметры должны передаваться мне,..по ссылке?........? Почти ничего не понимаю.

Правила просты: если есть *, то к типу добавляешь |VT_BYREF, но если тип — интерфейс, то добавлять не надо, т.к. интерфейс сам имеет одну *. Чтобы интерфейс имел |VT_BYREF, нужно чтобы было две *, т.е. [in] Document** Doc.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[6]: Обработка событий MSOffice, IDispEventSimpleImpl
От: BorysB  
Дата: 21.03.05 15:43
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Правила просты: если есть *, то к типу добавляешь |VT_BYREF, но если тип — интерфейс, то добавлять не надо, т.к. интерфейс сам имеет одну *. Чтобы интерфейс имел |VT_BYREF, нужно чтобы было две *, т.е. [in] Document** Doc.


Спасибо, все так и сделал, но, увы, не помогло.
Получается, что способ передачи параметров по большому счету не зависит от [in] [out].
А если у нас [optional], то можно ли передавать просто NULL, или нужно какие-то VT_EMPTY обязательно?
Re[3]: Обработка событий MSOffice, IDispEventSimpleImpl
От: BorysB  
Дата: 21.03.05 17:07
Оценка:
Попробовал сделать то же самое для BeforeSave. Никакого эфекта. Параметры не играют никакой роли. Что это можеть быть даже и не знаю.
Re[4]: Обработка событий MSOffice, IDispEventSimpleImpl
От: Elena_ Россия  
Дата: 21.03.05 20:58
Оценка:
Здравствуйте, BorysB, Вы писали:

BB>Попробовал сделать то же самое для BeforeSave. Никакого эфекта. Параметры не играют никакой роли. Что это можеть быть даже и не знаю.


Вот есть такое описание ошибки, хотя у Вас вроде все кроме Cancel работает, вряд ли это то самое, но там и пример есть, может пригодиться

BUG: ATL COM Event Handler May Receive Arguments in Reverse Order Q288724
Пользователь — друг программиста!
Re[7]: Обработка событий MSOffice, IDispEventSimpleImpl
От: Vi2 Удмуртия http://www.adem.ru
Дата: 22.03.05 05:18
Оценка:
Здравствуйте, BorysB, Вы писали:

BB>Спасибо, все так и сделал, но, увы, не помогло.


Т.е. сделал так:
_ATL_FUNC_INFO DocumentBeforePrintInfo = {CC_STDCALL, VT_EMPTY, 2, {VT_DISPATCH, VT_BOOL|VT_BYREF}};

void __stdcall CAddin::DocumentBeforePrint(IDispatch* /*_Document**/ Doc, VARIANT_BOOL *Cancel)
{
    /*все остальное несущественно*/
    *Cancel = VARIANT_TRUE;
    /*все остальное несущественно*/
}
и не работает?

BB>Получается, что способ передачи параметров по большому счету не зависит от [in] [out].


Почему не зависит? Очень даже зависит. Если параметр не [out], то его невозможно изменить или передать вовне сервера. Если он не [in], то бесполезно проверять его входное значение.

BB>А если у нас [optional], то можно ли передавать просто NULL, или нужно какие-то VT_EMPTY обязательно?


Как правило, optional параметр передается специальным Variant-ом с vt:=VT_ERROR и scode:=DISP_E_PARAMNOTFOUND.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[5]: Обработка событий MSOffice, IDispEventSimpleImpl
От: BorysB  
Дата: 22.03.05 06:53
Оценка:
Здравствуйте, Elena_, Вы писали:

E_>Вот есть такое описание ошибки, хотя у Вас вроде все кроме Cancel работает, вряд ли это то самое, но там и пример есть, может пригодиться


E_>BUG: ATL COM Event Handler May Receive Arguments in Reverse Order Q288724


Спасибо за совет. Буду пробовать...
Re[5]: Обработка событий MSOffice, IDispEventSimpleImpl
От: BorysB  
Дата: 22.03.05 14:15
Оценка:
Здравствуйте, Elena_, Вы писали:

E_>Вот есть такое описание ошибки, хотя у Вас вроде все кроме Cancel работает, вряд ли это то самое, но там и пример есть, может пригодиться


E_>BUG: ATL COM Event Handler May Receive Arguments in Reverse Order Q288724


Спасибо огромное! Сделал как написано в Q288724, сначала не помогло. Но потом изменил void __stdcall на STDMETHOD и все вместе заработало. Но эта статья, реально, очень важная вещь.
Всем огромное спасибо за помощь!!!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.