Легенда:
новое сообщение
закрытая нитка
новое сообщение
в закрытой нитке
старое сообщение
|
- Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
- Новичкам также крайне полезно ознакомиться с данным документом.
| |
[C++] Это очень страшно. 28.09.03 01:41 Число просмотров: 1233
Автор: void <Grebnev Valery> Статус: Elderman
|
Cпасибо, Tlo, за мнение.
> Ничего нового, конечно, но может поможет.
Поможет ;)
Тем более, что это мнение человека, который, как видно, в этом направлении уже "копал".
|
<programming>
|
[c++] afx_manage_state – всегда ли? 25.09.03 06:39
Автор: void <Grebnev Valery> Статус: Elderman
|
Возможно, из-за недостатка моего опыта вопрос покажется очень простым,
но прошу не отсылать к 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()
{
AFX_MANAGE_STATE(afxGetStaticModuleState())
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. Прошу подсказать мне, что же на самом деле происходит?
|
|
[C++] Это очень страшно. 27.09.03 18:09
Автор: Tlo Статус: Незарегистрированный пользователь
|
(Ох, как вспомню как я бился с dll'ками, статически линкуемыми с MFC, страшно становиться).
Теперь немного по делу. Если ты принимаешь правила framework'а. то принимаешь их полностью. Поэтому, если тебе говорят, что переключать контексты надо во всех экспортируемых, то надо их переключать. А иначе придется делать заключения ореализацииклассов famework'а (так как ты, безусловно корректно, сделал для CString), что не всегда возможно, особенно, если хост и dll'ка собраны с разными версиями билдами MFC (не говоря уже о разных версиях).
Но это все баблинг (и наверное, void, все-таки не для тебя, а для менее искушенных). А что касается непосредственно AFX_MODULE_STATE, то если не ошибаюсь он хранит только инфу, необходимую для mfc'овых хуков - любые функции dll, создающие окна, например те, которые работают с mfc'овыми CAsyncSocket'ами (отгадайте почему :), должны переключить контекст -, и что-то там с DAO.
Здравый же смысл, действительно подсказывает, что тривиальные функции, неимеющие сношений с MFC не должны переключать контекст модулей (операция, прямо скажем сама по себе нетривиальная). Но опять-таки подчеркну свое imho (входящее в резонанс с mfc'овым ho) - если framework навязывает - надо выполнять. Это как с параметрами операций типа IUnknown - можно AddRef не делать - и так работать будет, но это уже отклонение от стандарта, и вся ответственность лежит уже на вас.
Ничего нового, конечно, но может поможет.
|
| |
[C++] Это очень страшно. 28.09.03 01:41
Автор: void <Grebnev Valery> Статус: Elderman
|
Cпасибо, Tlo, за мнение.
> Ничего нового, конечно, но может поможет.
Поможет ;)
Тем более, что это мнение человека, который, как видно, в этом направлении уже "копал".
|
|
|