AFX_MANAGE_STATE – всегда ли?

Все, что вы хотели знать о программизме, но боялись спросить.
vg
Маньяк
Сообщения: 2803
Зарегистрирован: 29 май 2003, 22:29
Откуда: Магадан - Миссиссага

AFX_MANAGE_STATE – всегда ли?

Сообщение vg »

Возможно, из-за недостатка моего опыта вопрос покажется очень простым. В MSDN я не нашёл однозначного ответа «на все случаи жизни». Прошу помочь. Как-то опускал такие "мелочи". Вот решил для себя расставить точки над и. Надо сказать, что я не получил ответов на ряде Российских форумов.

Вопрос в том, собственно, а всегда ли необходимо использовать этот макро в Regular DLL MFC?

1) DLL изготавливается не с «uses the shared MFC libraries», a «statically linked MFC».
Есть подозрение, что в этом случае AFX_MANAGE_STATE не нужен вовсе. Так ли?

2) Практически во всех статьях MSDN сказано, что если «shared MFC libraries», то используйте AFX_MANAGE_STATE во всех экспортируемых функциях (я бы поправил здесь писателей от мелкософт – не экспортируемых, а вызываемых).

Но так ли?

Положим, есть класс в «Regular DLL MFC whis shared MFC libraries»:

Код: Выделить всё

class CI_ODBCquery: public IQueryInterface 
{ 
private: 
    CRecordset* Query; 
    … 
    … 
    CString connection; 
    CString error; 
    LPCTSTR error2; 
    bool msgerror; 
public: 
     void __stdcall Connection (LPCTSTR ConnectionStr); 
     void __stdcall CanErrorMessage(const int can_msg); 
     void __stdcall ErrorMessage (LPTSTR* outval ); 
     void __stdcall ErrorMessage2 (LPTSTR* outval ); 
      … 
      … 
}; 
Четыре функции в конце декларации класса CI_ODBCquery доступны программисту для вызовов после «загрузки» DLL, т.е. программист вызывает эти функции DLL непосредственно.

Функция CanErrorMessage(const int can_msg) совсем простая. Она устанавливает msgerror в true/false:

Код: Выделить всё

void __stdcall CI_ODBCquery::CanErrorMessage(const int can_msg) 
{ 
       msgerror = can_msg ? true:false; 
} 
Спрашивается, ну зачем здесь что-то «синхронизировать» в MFC при помощи макро AFX_MANAGE_STATE? Думаю, не требуется макро AFX_MANAGE_STATE. Так?

Функция ErrorMessage2(LPTSTR* outval ) – не сложнее. Она только «возвращает» указатель на нуль-терминированную строку error2:

Код: Выделить всё

void __stdcall CI_ODBCquery::ErrorMessage2(LPTSTR* outval) 
{ 
       *outval = error2; 
} 
Не требуется макро AFX_MANAGE_STATE. Так?

Функция ErrorMessage(LPTSTR* outval ) – чуть «сложнее». Она «возвращает» указатель на нуль-терминированную строку – буфер класса MFC CString error:

Код: Выделить всё

void __stdcall CI_ODBCquery::ErrorMessage1(LPTSTR* outval) 
{ 
       *outval = (LPTSTR)((LPCTSTR)error); 
} 
Здесь, как бы и самое место тому AFX_MANAGE_STATE, поскольку речь идёт об непосредственном обращении к объекту error класса MFC CString. Но!!! Переменная error была инициализирована, а потом возможно «перезаписана» неоднократно совершенно из других приват-функций класса CI_ODBCquery. Сомнительно, что и здесь следует использовать AFX_MANAGE_STATE. Так?

С функцией Connection (LPCTSTR ConnectionStr), см. выше, возможно дело чуть сложнее, поскольку из её тела происходит «перераспределение» памяти, используемой, переменной CString connection:

Код: Выделить всё

void __stdcall CI_ODBCquery::Connection(LPCTSTR ConnectionStr) 
{ 
      connection = _TEXT("DSN="); 
      connection += ConnectionStr; 
      connection += _TEXT(";UID=;PWD="); 
      … 
      … 
} 
Казалось бы, что раз мы «напрямую» задействуем MFC CString «из вне», то наличие AFX_MANAGE_STATE просто обязательно. Но!!! Переменная connection была инициализирована пустой строкой в конструкторе CI_ODBCquery до того, как программист может сделать вызов Connection(….). Я могу сильно ошибаться, но, на мой взгляд, класс CString слишком «прост» для того, что бы необходима была «синхронизация неизвестно чего при помощи макро AFX_MANAGE_STATE.

3) Возможно, то, что ниже - просто моё брюзжание. Но, например, ЭТО (и подобное ему) просто раздражает:

Knowledge Base Articles BUG: Wincore.cpp Line 879 Assert When Using MFC Classes
Q192853
….


Код: Выделить всё

STDMETHODIMP CTest::TestMethod() 
{ 
    [b]AFX_MANAGE_STATE(afxGetStaticModuleState()) [/b]
    CDatabase db; 
    db.OpenEx("DSN=LocalServer;Database=pubs;UID=sa;PWD=;"); 
    db.Close(); 

return S_OK; 
} 
the assertion dialog appears.


Или ещё смешнее:


Visual C++ Concepts: Adding Functionality
Exported DLL Function Entry Points
….
….
AFX_MANAGE_STATE does not need to be put into every function in the DLL. For example, InitInstance can be called by the MFC code in the application without AFX_MANAGE_STATE because MFC automatically shifts the module state before InitInstance and then switches it back after InitInstance returns. The same is true for all message-map handlers. Regular DLLs actually have a special master window procedure that automatically switches the module state before routing any message.

Т.е., товарищи от мелкософт здесь и выше говорят, о том, что вообщем-то AFX_MANAGE_STATE не только не всегда следует использовать, но «просто так» - это ещё и вредно.

PS. Прошу подсказать мне, что же на самом деле происходит?
Woozy
Завсегдатай
Сообщения: 278
Зарегистрирован: 03 мар 2003, 08:55
Откуда: RU->BC->ON->FI -> Chicago, IL -> Seattle, WA

Re: AFX_MANAGE_STATE – всегда ли?

Сообщение Woozy »

У меня необходимость управлять этим AFX_MANAGE_STATE возникла для того чтобы прочитать ресурс диалога непосредствнно из кода DLL. Посмотри внутренности функции, а также, кажется GetModuleInstance API, должно проясниться.

Мне несколько лень лезть самому, рискну предположить, что AFX_MANAGE_STATE устанавливает внутреннюю переменную MFC, в которой лежит хэндл для доступа к модулю, чаще всего к ресурсам.

Только я разобрался с этой штукой (с полгода назад), как дали отбой MFC, и всё было переписано на API + ATL.
vg
Маньяк
Сообщения: 2803
Зарегистрирован: 29 май 2003, 22:29
Откуда: Магадан - Миссиссага

Сообщение vg »

Да, Woozy, спасибо
У меня необходимость управлять этим AFX_MANAGE_STATE возникла для того чтобы прочитать ресурс диалога непосредствнно из кода DLL. Посмотри внутренности функции, а также, кажется GetModuleInstance API, должно проясниться.
С этим понятно. Но речь в моём посте, собственно, о том, о чём там речь. Извини за каламбур. А всегда ли надо? Меня поражает иногда реакция публики на форумах, когда макро AFX_MANAGE_STATE пичкают в качестве панацеи. Для диалогов - нет вопросов. Там надо использовать AFX_MANAGE_STATE . Ресурсы-нет вопросов.
Мне несколько лень лезть самому, рискну предположить, что AFX_MANAGE_STATE устанавливает внутреннюю переменную MFC, в которой лежит хэндл для доступа к модулю, чаще всего к ресурсам.
Так оно и есть, Woozy ("...AFX_MANAGE_STATE устанавливает внутреннюю переменную MFC..."). По крайней мере, так написано в MSDN. Но в моей проге (той о которой пост) нет обращений к ресурсам.

PS. Если не затруднит, может поспрашиваешь у ваших? Там ближе к мелкософту, думаю, больше проффи, чем здесь. Сам я, как не в своей тарелке, когда нет чёткого понимания этих деталей. Буду благодарен.
Woozy
Завсегдатай
Сообщения: 278
Зарегистрирован: 03 мар 2003, 08:55
Откуда: RU->BC->ON->FI -> Chicago, IL -> Seattle, WA

Сообщение Woozy »

vg писал(а):С этим понятно. Но речь в моём посте, собственно, о том, о чём там речь. Извини за каламбур. А всегда ли надо?
Во первых, хочу порекомендовать тебе форумы на http://www.rsdn.ru - там очень даже отвечают на такие вопросы.

Во вторых, нет, не надо в каждой функции вызывать, если ты уверен, что текущим модулем установлен тот, к которому обращаются при чтении ресурсов - то есть некоторых данных, хранящихся непосредственно в EXE или DLL. Сама MFC использует свои собственные ресурсы. Твой код может использовать ресурсы, заведённые тобой. В зависимости от контекста ресурса и надо переключаться. Я бы определил, что чаще требуется, там бы стоял статус по умолчанию, и вызовов этой функции не было бы нужно после изначально правильной установки. Для того случая (менее частого), когда ты читаешь ресурсы из другого модуля, там бы явно и переключал этот самый статус. По завершении использования (менее частого) ресурса возвращал бы исходный контекст.
vg
Маньяк
Сообщения: 2803
Зарегистрирован: 29 май 2003, 22:29
Откуда: Магадан - Миссиссага

Сообщение vg »

Woozy
Во первых, хочу порекомендовать тебе форумы на http://www.rsdn.ru - там очень даже отвечают на такие вопросы.
Да, спасибо. Дальше можно и там посмотреть.
Во вторых, нет, не надо в каждой функции вызывать, если ты уверен, что текущим модулем установлен тот, к которому обращаются при чтении ресурсов - то есть некоторых данных, хранящихся непосредственно в EXE или DLL.
Из-за моей малограмотности (это не "рисовка") этой уверенности и не хватает часто. Про тривиальные "составляющие" ресурсов (диалоги, строки, битмапы и т.д.) мы здесь не говорим. Конечно, там следует использовать AFX_MANAGE_STATE. Уверенность для остального есть только для некоторых из тех случаев, о которых я и постил.
Справедливости ради надо отметить, что сегодня я получил от "наших" весьма здравое, правильное указание. Суть его в кратце в том, что "если ты принимаешь правила framework. то принимаешь их полностью". Так, что, наверное, я прислушаюсь к этому "нашему" товарищу.
Woozy
Завсегдатай
Сообщения: 278
Зарегистрирован: 03 мар 2003, 08:55
Откуда: RU->BC->ON->FI -> Chicago, IL -> Seattle, WA

Сообщение Woozy »

Но если ты написал функцию, что вызывается из MFC-ного диалога, а она вообще не имеет отношения к UI, либо не создаёт никаких новых объектов UI, а только манипулирует с созданными - там точно не нужен этот вызов. Рекомендация "вызывать всегда" для людей, что не хотят понять, когда та внутренняя переменная пригодна к использованию, и в этом надо быть уверенным, а когда нет.
vg
Маньяк
Сообщения: 2803
Зарегистрирован: 29 май 2003, 22:29
Откуда: Магадан - Миссиссага

Сообщение vg »

Но если ты написал функцию, что вызывается из MFC-ного диалога, а она вообще не имеет отношения к UI, либо не создаёт никаких новых объектов UI
Не там (с моей проге) ничего общего с UI. Это проект нашего "корпоративного" API доступа к данным. Некая спецификация интерфейсов (в широком смысле слова) + опытная реализация API для девелопперов, которые будут подрядчиками по отношению к нашей конторе.

Спасибо, Woozy, за мнение. Кстати, а почему все отальные молчат? Неужно обиделись, аль считают ниже своего достоинства? (мои мысли в слух).
Woozy
Завсегдатай
Сообщения: 278
Зарегистрирован: 03 мар 2003, 08:55
Откуда: RU->BC->ON->FI -> Chicago, IL -> Seattle, WA

Сообщение Woozy »

Итак, если, например, к тому же строки из ресурсов не читаешь, хоть и без UI, тебе и беспокоиться незачем.
vg писал(а):Неужно обиделись, аль считают ниже своего достоинства? (мои мысли в слух).
Ты всерьёз думаешь, что все про всё могут знать? :shock:
vg
Маньяк
Сообщения: 2803
Зарегистрирован: 29 май 2003, 22:29
Откуда: Магадан - Миссиссага

Сообщение vg »

Даже строк не читаю из ресурсов.
Ты всерьёз думаешь, что все про всё могут знать?
Ну, может и не так прямолинейно, но в общем, и если говорить про развитые страны, где-то так. Понятно, что есть и другие форумы в Канаде, и не все ходят только сюда. Я просто думаю, что в Канаде больше профи, чем в у нас. Это объективно. Всё зависит от экономик стран.
Woozy
Завсегдатай
Сообщения: 278
Зарегистрирован: 03 мар 2003, 08:55
Откуда: RU->BC->ON->FI -> Chicago, IL -> Seattle, WA

Сообщение Woozy »

vg, тебе не надо вызывать ту функцию вовсе. :D

Когда человек не занимался этим, то его профессионализм в другой области не помогает.
vg
Маньяк
Сообщения: 2803
Зарегистрирован: 29 май 2003, 22:29
Откуда: Магадан - Миссиссага

Сообщение vg »

vg, тебе не надо вызывать ту функцию вовсе.
1) Подозревал :lol: Об этомж и топик.
Лучше десять раз посоветоваться, а потом принять решение.

Хотя, думаю, надо мне самому здесь немного ещё поразбираться. Дело в том, что в том API используются классы-обёртки МFC ODBC и ADO.
Когда обращаешься к ним (они в DLL) непосредственно (из "вне"), то там нужен AFX_MANAGE_STATE. Об этом и народ и MS говорит.

Ну а для простых случаев, о которых собственно была речь в моём первом посте в начале топика - там я не буду использовать этот макро (как впрочем и не использую).
Woozy
Завсегдатай
Сообщения: 278
Зарегистрирован: 03 мар 2003, 08:55
Откуда: RU->BC->ON->FI -> Chicago, IL -> Seattle, WA

Сообщение Woozy »

vg писал(а):Когда обращаешься к ним (они в DLL) непосредственно (из "вне"), то там нужен AFX_MANAGE_STATE. Об этом и народ и MS говорит.
Для исполняемого кода вообще всё равно, установлен статус или нет. Это касается доступа к данным ресурсов в DLL, надо устанавливать этот статус, чтобы отрабатывали функции, что лезут в ресурсы.
Последний раз редактировалось Woozy 27 сен 2003, 17:57, всего редактировалось 1 раз.
vg
Маньяк
Сообщения: 2803
Зарегистрирован: 29 май 2003, 22:29
Откуда: Магадан - Миссиссага

Сообщение vg »

Knowledge Base Articles BUG: Wincore.cpp Line 879 Assert When Using MFC Classes
Q192853
А это (см. в начале топика)? "Нашинские" с опытом подсказали, что проблема там вообще имеется (для объектов доступа к данным).
Сколько видел примеров написания COM-серверов с аргегацией объектов OLE DB, там AFX_MANAGE_STATE понатыкано в каждом методе интерфейсов. Хотя конечно сорсы других девелоперов - это не сорс MS.
Woozy
Завсегдатай
Сообщения: 278
Зарегистрирован: 03 мар 2003, 08:55
Откуда: RU->BC->ON->FI -> Chicago, IL -> Seattle, WA

Сообщение Woozy »

vg писал(а):
Knowledge Base Articles BUG: Wincore.cpp Line 879 Assert When Using MFC Classes
Q192853
А это (см. в начале топика)? "Нашинские" с опытом подсказали, что проблема там вообще имеется (для объектов доступа к данным).
MFC кучу хрени хранит в собственных ресурсах. Бросайте MFC, кака.
vg
Маньяк
Сообщения: 2803
Зарегистрирован: 29 май 2003, 22:29
Откуда: Магадан - Миссиссага

Сообщение vg »

MFC кучу хрени хранит в собственных ресурсах. Бросайте MFC, кака.
Да и бросил бы. Дык пока туповат слегка для более достойных весчей.
Мож если до Канады доеду, там и начну новую жизнь с листа, без MFC :lol:
Там, в MFC всё не намного сложнее по сравнению с рисовалками BCB++, а иногда и проще. Как бы MFC не ругали - библиотека не самая плохая.

PS.
Когда уж тямы не хватает совсем, а надо что-то быстро, то я так и делаю - бросаю каку-MFC и делаю в BCB++.
:lol:
Ответить