AFX_MANAGE_STATE – всегда ли?
Добавлено: 26 сен 2003, 17:55
Возможно, из-за недостатка моего опыта вопрос покажется очень простым. В 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»:
Четыре функции в конце декларации класса CI_ODBCquery доступны программисту для вызовов после «загрузки» DLL, т.е. программист вызывает эти функции DLL непосредственно.
Функция CanErrorMessage(const int can_msg) совсем простая. Она устанавливает msgerror в true/false:
Спрашивается, ну зачем здесь что-то «синхронизировать» в MFC при помощи макро AFX_MANAGE_STATE? Думаю, не требуется макро AFX_MANAGE_STATE. Так?
Функция ErrorMessage2(LPTSTR* outval ) – не сложнее. Она только «возвращает» указатель на нуль-терминированную строку error2:
Не требуется макро AFX_MANAGE_STATE. Так?
Функция ErrorMessage(LPTSTR* outval ) – чуть «сложнее». Она «возвращает» указатель на нуль-терминированную строку – буфер класса MFC CString error:
Здесь, как бы и самое место тому AFX_MANAGE_STATE, поскольку речь идёт об непосредственном обращении к объекту error класса MFC CString. Но!!! Переменная error была инициализирована, а потом возможно «перезаписана» неоднократно совершенно из других приват-функций класса CI_ODBCquery. Сомнительно, что и здесь следует использовать AFX_MANAGE_STATE. Так?
С функцией Connection (LPCTSTR ConnectionStr), см. выше, возможно дело чуть сложнее, поскольку из её тела происходит «перераспределение» памяти, используемой, переменной CString connection:
Казалось бы, что раз мы «напрямую» задействуем 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
….
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. Прошу подсказать мне, что же на самом деле происходит?
Вопрос в том, собственно, а всегда ли необходимо использовать этот макро в 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 );
…
…
};
Функция CanErrorMessage(const int can_msg) совсем простая. Она устанавливает msgerror в true/false:
Код: Выделить всё
void __stdcall CI_ODBCquery::CanErrorMessage(const int can_msg)
{
msgerror = can_msg ? true:false;
}
Функция ErrorMessage2(LPTSTR* outval ) – не сложнее. Она только «возвращает» указатель на нуль-терминированную строку error2:
Код: Выделить всё
void __stdcall CI_ODBCquery::ErrorMessage2(LPTSTR* outval)
{
*outval = error2;
}
Функция ErrorMessage(LPTSTR* outval ) – чуть «сложнее». Она «возвращает» указатель на нуль-терминированную строку – буфер класса MFC CString error:
Код: Выделить всё
void __stdcall CI_ODBCquery::ErrorMessage1(LPTSTR* outval)
{
*outval = (LPTSTR)((LPCTSTR)error);
}
С функцией Connection (LPCTSTR ConnectionStr), см. выше, возможно дело чуть сложнее, поскольку из её тела происходит «перераспределение» памяти, используемой, переменной CString connection:
Код: Выделить всё
void __stdcall CI_ODBCquery::Connection(LPCTSTR ConnectionStr)
{
connection = _TEXT("DSN=");
connection += ConnectionStr;
connection += _TEXT(";UID=;PWD=");
…
…
}
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;
}
Или ещё смешнее:
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. Прошу подсказать мне, что же на самом деле происходит?