Привет!
есть такая проблема: есть проект A, которая есть статическая либа (которая статически слинкована с MFC). Есть проект B (ATL DLL-ка), в которой либу A хочется использовать. Так вот при линковке вылезает проблема, что DllMain определена дважды. 1>uafxcwd.lib(dllmodul.obj) : error LNK2005: _DllMain@12 already defined in dllmain.obj
Оно и понятно, т.к. в кишках MFC есть DllMain (http://support.microsoft.com/kb/148791)
Может можно как-то это все-таки слинковать? Напрмер, экспортивровав MFC-шный DllMain, и я его вызову в своем DllMain.
Все проекты настроены на использование одинаковых версий библиотек окружения RunTime и MFC (везде статик)
Здравствуйте, HappyMan, Вы писали:
HM>есть такая проблема: есть проект A, которая есть статическая либа (которая статически слинкована с MFC). Есть проект B (ATL DLL-ка), в которой либу A хочется использовать. Так вот при линковке вылезает проблема, что DllMain определена дважды. 1>>uafxcwd.lib(dllmodul.obj) : error LNK2005: _DllMain@12 already defined in dllmain.obj
Поможет ключ компоновщика /ENTRY.
Там можно указать, какая именно точка входа будет использована.
Понятно, что двух DllMain быть не может — Вам нужно переименовать одну из них и
прописать ее имя в ключе /ENTRY.
Ой, вот я сейчас написал, не подумав.
Наверное, не стоит отключать дефолтную реализацию DllMain из MFC.
Там может быть какая-то инициализация, без которой dll-ка не заведется.
On 05/21/2012 01:25 PM, HappyMan wrote:
> есть такая проблема: есть проект A, которая есть статическая либа (которая > статически слинкована с MFC). Есть проект B (ATL DLL-ка), в которой либу A > хочется использовать. Так вот при линковке вылезает проблема, что DllMain > определена дважды. > 1>uafxcwd.lib(dllmodul.obj) : error LNK2005: _DllMain@12 already defined in > dllmain.obj > > Оно и понятно, т.к. в кишках MFC есть DllMain > (http://support.microsoft.com/kb/148791) > Может можно как-то это все-таки слинковать? Напрмер, экспортивровав MFC-шный > DllMain, и я его вызову в своем DllMain.
У тебя свой DllMain есть ?
Если есть, удаляй, будет работать стандартный.
Если тебе нужен свой -- могу рассказать как и что делать.
> Все проекты настроены на использование одинаковых версий библиотек окружения > RunTime и MFC (везде статик)
Статики нельзя использовать если у тебя есть .dll.
Есть .dll -- значит уже два модуля, .dll и .exe.
А два модуля должны разделять ОДИН CRT и ОДИН MFC.
Ну, странно, потому как если ты используешь MFC статически, то
там не будет своего стандартного MFC-шного DllMain.
Так как ты делаешь, можно делать только в одно случае, если
пишешь .dll, использующую MFC, в то время как само приложение
и другие .dll не будут использовать MFC вообще -- это достаточно
редкий случай.
Здравствуйте, MasterZiv, Вы писали:
MZ>У тебя свой DllMain есть ? MZ>Если есть, удаляй, будет работать стандартный. MZ>Если тебе нужен свой -- могу рассказать как и что делать.
Есть свой DllMain, и он мне крайне нужен.
>> Все проекты настроены на использование одинаковых версий библиотек окружения >> RunTime и MFC (везде статик)
MZ>Статики нельзя использовать если у тебя есть .dll. MZ>Есть .dll -- значит уже два модуля, .dll и .exe. MZ>А два модуля должны разделять ОДИН CRT и ОДИН MFC.
MZ>Ну, странно, потому как если ты используешь MFC статически, то MZ>там не будет своего стандартного MFC-шного DllMain.
MZ>Так как ты делаешь, можно делать только в одно случае, если MZ>пишешь .dll, использующую MFC, в то время как само приложение MZ>и другие .dll не будут использовать MFC вообще -- это достаточно MZ>редкий случай.
У меня как раз такой случай — статическая либа использует MFC (так же статически), DLL-ка, к которой линкуется либа не использует MFC.
On 05/21/2012 03:42 PM, HappyMan wrote:
> У меня как раз такой случай — статическая либа использует MFC (так же > статически), DLL-ка, к которой линкуется либа не использует MFC.
Тогда там не должно быть втогого DLLMAIN из статического MFC.
Думай, как оно появилось.
Здравствуйте, MasterZiv, Вы писали:
MZ>On 05/21/2012 03:42 PM, HappyMan wrote:
>> У меня как раз такой случай — статическая либа использует MFC (так же >> статически), DLL-ка, к которой линкуется либа не использует MFC.
MZ>Тогда там не должно быть втогого DLLMAIN из статического MFC. MZ>Думай, как оно появилось.
MZ>Какие у тебя -DAFX??? определены в проекте ?
Спасибо, что навели на решение: в статической либе был дефайн _USRDLL вместо _USRLIB
HM>Спасибо, что навели на решение: в статической либе был дефайн _USRDLL вместо _USRLIB
Вопрос снова открыт. Убрав макрос _USRDLL, видимо, не инициализируются внутренности MFC (в DllMain). Солюшн компилируются и линкуется, но при вызове функции из либы, AfxGetApp() возвращает NULL, а показ диалога не возможен (assert в AfxGetResourceHandle()).
Сразу отвечу про ресурсы в статической либе: все rc файлы я включил в свой основной проект (через секции TEXTINCLUDE), так что с ними проблем быть не должно.
> Вопрос снова открыт. Убрав макрос _USRDLL, видимо, не инициализируются > внутренности MFC (в DllMain).
Инициализировать надо явным образом. Как -- не помню.
Солюшн компилируются и линкуется, но при вызове > функции из либы, AfxGetApp() возвращает NULL, а показ диалога не возможен > (assert в AfxGetResourceHandle()).
AfxGetApp() чтобы что-то возвращало, объект CWinApp надо создать.
Ты его создаёшь ?
Чтобы AfxGetResourceHandle() работал,надо
перед созданием диалога вызывать
AfxSetResourceHandle().
AfxSetResourceHandle() — надо вызывать, если ресурсы находятся в другой библиотеке. А либа и ее ресурсы включаются в основной проект. Или я что-то не правильно понимаю?
>> Вопрос снова открыт. Убрав макрос _USRDLL, видимо, не инициализируются >> внутренности MFC (в DllMain).
MZ>Инициализировать надо явным образом. Как -- не помню.
Что бы создать CWinApp надо вначале провентилировать MFC, но пока я не знаю как.
On 05/24/2012 06:55 PM, HappyMan wrote:
> AfxSetResourceHandle() — надо вызывать, если ресурсы находятся в другой > библиотеке. А либа и ее ресурсы включаются в основной проект. Или я что-то не > правильно понимаю?
Неправильно, AfxSetResourceHandle() надо вызвать всегда.
On 05/24/2012 06:58 PM, HappyMan wrote:
> MZ>Инициализировать надо явным образом. Как -- не помню.
Создай проект user DLL, это DLL, которая использует MFC
и работает с приложением, которое НЕ использует MFC.
И поэтому там надо инициализировать MFC руками.
Погляди, скопируй код в свой.
Да, я честно говоря до конца не уверен, будет ли такая конфигурация
работать : приложение и DLL, к которой MFC прилинкован статически.
Здравствуйте, MasterZiv, Вы писали:
MZ>Да, я честно говоря до конца не уверен, будет ли такая конфигурация MZ>работать : приложение и DLL, к которой MFC прилинкован статически.
Здравствуйте, MasterZiv, Вы писали:
MZ>On 05/24/2012 06:55 PM, HappyMan wrote:
>> AfxSetResourceHandle() — надо вызывать, если ресурсы находятся в другой >> библиотеке. А либа и ее ресурсы включаются в основной проект. Или я что-то не >> правильно понимаю?
MZ>Неправильно, AfxSetResourceHandle() надо вызвать всегда.
Так первоначальный вызов AfxSetResourceHandle делается не в пользовательском *.cpp файле, а в библитотеке MFC.
Мы делаем вызов AfxSetResourceHandle — когда "возвращеаем" хендл — нашему проекту.
Пример:
CCommandData* pCommandData = (CCommandData*)ptr->GetThis();
if (pCommandData)
{
HINSTANCE hClientResources = AfxGetResourceHandle();
AfxSetResourceHandle(::GetModuleHandle("Telecontrol.dll"));
// ЗДЕСЬ МЫ РАБОТАЕМ С РЕСУРСАМИ БИБЛТОТЕКИ "Telecontrol.dll"
..................................
..................................
..................................
AfxSetResourceHandle(hClientResources);
delete pCommandData;
}
On 05/28/2012 05:10 PM, AlexGin wrote:
> Так первоначальный вызов AfxSetResourceHandle делается не в пользовательском > *.cpp файле, а в библитотеке MFC.
Наоборот, там он никогда не делается.
MFC не нужно делать AfxSetResourceHandle для своих ресурсов -- смотри код в
AfxFindResource или что -то в этом роде.
Или ещё почитай про extension DLL.
> Пример: > > CCommandData* pCommandData = (CCommandData*)ptr->GetThis(); > if (pCommandData) > { > HINSTANCE hClientResources = AfxGetResourceHandle();
hClientResources = AfxGetResourceHandle(); -- это не нужно.
> AfxSetResourceHandle(::GetModuleHandle("Telecontrol.dll")); > // ЗДЕСЬ МЫ РАБОТАЕМ С РЕСУРСАМИ БИБЛТОТЕКИ "Telecontrol.dll" > .................................. > .................................. > .................................. > AfxSetResourceHandle(hClientResources); --
-- и это не нужно. > delete pCommandData; > }
НЕ нужно возвращать обратно ресурсник, это бессмысленно.
Итак, простое правило:
1) КАЖДЫЙ раз в коде, непосредственно перед тем, как выполнить какую-то
операцию, которая загружает откуда-то ресурсы, ты должен
проставить хэндл библиотеки с ресурсами с помощью AfxSetResourceHandle().
Исключение составляют ресурсы из библиотек MFC и других extension DLL.
2) Если у тебя в коде идёт подряд скажем 20 операций, загружающих ресурсы,
нужно ли ставить AfxSetResourceHandle() перед каждой из них -- зависит
от твоего кода. Если ты уверен на 100%, что никакой другой код в промежутках
(вызовы дочерних функций, вызовы сообщений и их обработка) не переустановит
ResourceHandle, то можешь сделать это только один раз, в начале.
3) Возвращать его при этом нет смысла -- см правило 1)
On 05/28/2012 05:01 PM, AlexGin wrote:
> Нет, не будет работать! > > Вот подробности:
Это очень сложный вопрос, а в статьях очень много букаф.
Вполне возможно даже, что какой-то код в таком проекте
будет работать, а другой -- не будет. Далеко не все
части MFC требуют наличие его проинициализированных
статических данных.
Хотя я бы просто не стал мучится, даже пробовать --
пишеш DLL, значит и MFC должно быть в DLL.
И в идеале приложение его должно инициализировать.
Здравствуйте, MasterZiv, Вы писали:
MZ>On 05/28/2012 05:01 PM, AlexGin wrote:
>> Нет, не будет работать! >> >> Вот подробности:
MZ>Это очень сложный вопрос, а в статьях очень много букаф. MZ>Вполне возможно даже, что какой-то код в таком проекте MZ>будет работать, а другой -- не будет. Далеко не все MZ>части MFC требуют наличие его проинициализированных MZ>статических данных.
В статьях приводится то, что является best practice в данном случае.
Да, вполне возможно, что где-то эти приемы избыточны, но что от них будет вред — сомневаюсь.
MZ>Хотя я бы просто не стал мучится, даже пробовать -- MZ>пишеш DLL, значит и MFC должно быть в DLL. MZ>И в идеале приложение его должно инициализировать.
+100
Это правильно!
Здравствуйте, MasterZiv, Вы писали:
>> Пример: >> >> CCommandData* pCommandData = (CCommandData*)ptr->GetThis(); >> if (pCommandData) >> { >> HINSTANCE hClientResources = AfxGetResourceHandle(); MZ>hClientResources = AfxGetResourceHandle(); -- это не нужно.
>> AfxSetResourceHandle(::GetModuleHandle("Telecontrol.dll")); >> // ЗДЕСЬ МЫ РАБОТАЕМ С РЕСУРСАМИ БИБЛТОТЕКИ "Telecontrol.dll" >> .................................. >> .................................. >> .................................. >> AfxSetResourceHandle(hClientResources); -- MZ>-- и это не нужно. >> delete pCommandData; >> }
MZ>НЕ нужно возвращать обратно ресурсник, это бессмысленно.
MZ>Итак, простое правило: MZ>1) КАЖДЫЙ раз в коде, непосредственно перед тем, как выполнить какую-то MZ>операцию, которая загружает откуда-то ресурсы, ты должен MZ>проставить хэндл библиотеки с ресурсами с помощью AfxSetResourceHandle(). MZ>Исключение составляют ресурсы из библиотек MFC и других extension DLL.
MZ>2) Если у тебя в коде идёт подряд скажем 20 операций, загружающих ресурсы, MZ>нужно ли ставить AfxSetResourceHandle() перед каждой из них -- зависит MZ>от твоего кода. Если ты уверен на 100%, что никакой другой код в промежутках MZ>(вызовы дочерних функций, вызовы сообщений и их обработка) не переустановит MZ>ResourceHandle, то можешь сделать это только один раз, в начале.
MZ>3) Возвращать его при этом нет смысла -- см правило 1)
Допустим, что я сделал по твоему рецепту, то есть написал этот код в таком виде:
Здесь я предполагаю, что мы работаем даже не в головном *.exe модуле, а в какой-либо другой (не Telecontrol.dll) библиотеке:
CCommandData* pCommandData = (CCommandData*)ptr->GetThis();
if (pCommandData)
{
AfxSetResourceHandle(::GetModuleHandle("Telecontrol.dll"));
// ЗДЕСЬ МЫ РАБОТАЕМ С РЕСУРСАМИ БИБЛТОТЕКИ "Telecontrol.dll"
..................................
..................................
..................................
delete pCommandData;
}
Что будет дальше, когда мы выйдем из данного участка?
Хендл ресурсов останется на бибилитотеке Telecontrol.dll, вместо перехода на текущую библиотеку.
Наличие хендла на старой библиотеке (которая Telecontrol.dll) обеспечит нам дальнейшие грабли
On 05/28/2012 07:28 PM, AlexGin wrote: > Допустим, что я сделал по твоему рецепту, то есть написал этот код в таком виде: > Здесь я предполагаю, что мы работаем даже не в головном *.exe модуле, а в > какой-либо другой (не Telecontrol.dll) библиотеке:
Это всё равно. AfxSetResourceHandle надо ставить всегда.
> Что будет дальше, когда мы выйдем из данного участка? > Хендл ресурсов останется на бибилитотеке Telecontrol.dll, вместо перехода на > текущую библиотеку.
Что такое "текущая библиотека" ?
> Наличие хендла на *старой библиотеке* (которая Telecontrol.dll) обеспечит нам > дальнейшие грабли
Нет, если весь код будет правильным, будет соответствовать этим правилам.
Тут главное понять, что AfxSetResourceHandle надо ставить всегда,
и надеятся на какую-то "текущую библиотеку" бессмысленно.
Если это правило соблюдается, то всё будет работать всегда.
Другая модель поведения с "текущим активным источником ресурсов" тоже
конечно же допустима, только возни с ней больше, а толку мало.
AfxSetResourceHandle() собственно и разрабатывался с заточкой под
модель с "текущим активным источником ресурсов".
Ну и если у тебя одно приложение и одна .dll — может оно и хорошо.
Если модулей несколько сотен, и любой чих может вызвать смену "текущего
ресурса" -- дело другое.