[linkerr] DllMain already defined
От: HappyMan Россия  
Дата: 21.05.12 09:25
Оценка:
Привет!
есть такая проблема: есть проект 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 (везде статик)

Заранее спасибо
Re: [linkerr] DllMain already defined
От: okman Беларусь https://searchinform.ru/
Дата: 21.05.12 10:01
Оценка:
Здравствуйте, 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.
Re: [linkerr] DllMain already defined
От: okman Беларусь https://searchinform.ru/
Дата: 21.05.12 10:12
Оценка:
Здравствуйте, HappyMan.

Ой, вот я сейчас написал, не подумав.
Наверное, не стоит отключать дефолтную реализацию DllMain из MFC.
Там может быть какая-то инициализация, без которой dll-ка не заведется.
Re: [linkerr] DllMain already defined
От: MasterZiv СССР  
Дата: 21.05.12 10:47
Оценка:
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 вообще -- это достаточно
редкий случай.
Posted via RSDN NNTP Server 2.1 beta
Re[2]: [linkerr] DllMain already defined
От: HappyMan Россия  
Дата: 21.05.12 11:42
Оценка:
Здравствуйте, 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.
Re[3]: [linkerr] DllMain already defined
От: MasterZiv СССР  
Дата: 21.05.12 12:08
Оценка:
On 05/21/2012 03:42 PM, HappyMan wrote:

> У меня как раз такой случай — статическая либа использует MFC (так же

> статически), DLL-ка, к которой линкуется либа не использует MFC.

Тогда там не должно быть втогого DLLMAIN из статического MFC.
Думай, как оно появилось.

Какие у тебя -DAFX??? определены в проекте ?
Posted via RSDN NNTP Server 2.1 beta
Re[4]: [linkerr] DllMain already defined
От: HappyMan Россия  
Дата: 21.05.12 12:27
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>On 05/21/2012 03:42 PM, HappyMan wrote:


>> У меня как раз такой случай — статическая либа использует MFC (так же

>> статически), DLL-ка, к которой линкуется либа не использует MFC.

MZ>Тогда там не должно быть втогого DLLMAIN из статического MFC.

MZ>Думай, как оно появилось.

MZ>Какие у тебя -DAFX??? определены в проекте ?


Спасибо, что навели на решение: в статической либе был дефайн _USRDLL вместо _USRLIB
Re[5]: [linkerr] DllMain already defined
От: HappyMan Россия  
Дата: 24.05.12 14:24
Оценка:
HM>Спасибо, что навели на решение: в статической либе был дефайн _USRDLL вместо _USRLIB

Вопрос снова открыт. Убрав макрос _USRDLL, видимо, не инициализируются внутренности MFC (в DllMain). Солюшн компилируются и линкуется, но при вызове функции из либы, AfxGetApp() возвращает NULL, а показ диалога не возможен (assert в AfxGetResourceHandle()).
Сразу отвечу про ресурсы в статической либе: все rc файлы я включил в свой основной проект (через секции TEXTINCLUDE), так что с ними проблем быть не должно.
Re[6]: [linkerr] DllMain already defined
От: MasterZiv СССР  
Дата: 24.05.12 14:41
Оценка:
> Вопрос снова открыт. Убрав макрос _USRDLL, видимо, не инициализируются
> внутренности MFC (в DllMain).

Инициализировать надо явным образом. Как -- не помню.

Солюшн компилируются и линкуется, но при вызове
> функции из либы, AfxGetApp() возвращает NULL, а показ диалога не возможен
> (assert в AfxGetResourceHandle()).

AfxGetApp() чтобы что-то возвращало, объект CWinApp надо создать.
Ты его создаёшь ?

Чтобы AfxGetResourceHandle() работал,надо
перед созданием диалога вызывать
AfxSetResourceHandle().
Posted via RSDN NNTP Server 2.1 beta
Re[7]: [linkerr] DllMain already defined
От: HappyMan Россия  
Дата: 24.05.12 14:55
Оценка:
MZ>Чтобы AfxGetResourceHandle() работал,надо
MZ>перед созданием диалога вызывать
MZ>AfxSetResourceHandle().

AfxSetResourceHandle() — надо вызывать, если ресурсы находятся в другой библиотеке. А либа и ее ресурсы включаются в основной проект. Или я что-то не правильно понимаю?
Re[7]: [linkerr] DllMain already defined
От: HappyMan Россия  
Дата: 24.05.12 14:58
Оценка:
Здравствуйте, MasterZiv, Вы писали:


>> Вопрос снова открыт. Убрав макрос _USRDLL, видимо, не инициализируются

>> внутренности MFC (в DllMain).

MZ>Инициализировать надо явным образом. Как -- не помню.


Что бы создать CWinApp надо вначале провентилировать MFC, но пока я не знаю как.
Re[8]: [linkerr] DllMain already defined
От: MasterZiv СССР  
Дата: 24.05.12 15:07
Оценка:
On 05/24/2012 06:55 PM, HappyMan wrote:

> AfxSetResourceHandle() — надо вызывать, если ресурсы находятся в другой

> библиотеке. А либа и ее ресурсы включаются в основной проект. Или я что-то не
> правильно понимаю?

Неправильно, AfxSetResourceHandle() надо вызвать всегда.
Posted via RSDN NNTP Server 2.1 beta
Re[8]: [linkerr] DllMain already defined
От: MasterZiv СССР  
Дата: 24.05.12 15:18
Оценка:
On 05/24/2012 06:58 PM, HappyMan wrote:

> MZ>Инициализировать надо явным образом. Как -- не помню.


Создай проект user DLL, это DLL, которая использует MFC
и работает с приложением, которое НЕ использует MFC.
И поэтому там надо инициализировать MFC руками.

Погляди, скопируй код в свой.

Да, я честно говоря до конца не уверен, будет ли такая конфигурация
работать : приложение и DLL, к которой MFC прилинкован статически.
Posted via RSDN NNTP Server 2.1 beta
Re[9]: [linkerr] DllMain already defined
От: AlexGin Беларусь  
Дата: 28.05.12 13:01
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>Да, я честно говоря до конца не уверен, будет ли такая конфигурация

MZ>работать : приложение и DLL, к которой MFC прилинкован статически.

Нет, не будет работать!

Вот подробности:

http://www.codeguru.com/cpp/cpp/cpp_mfc/tutorials/article.php/c4017/MFC-DLL-TUTORIAL-PART-1.htm
http://www.codeguru.com/cpp/cpp/cpp_mfc/tutorials/article.php/c4019/MFC-DLL-TUTORIAL-PART-2.htm
http://www.codeguru.com/cpp/cpp/cpp_mfc/tutorials/article.php/c4023/MFC-DLL-TUTORIAL-PART-3.htm
Re[9]: [linkerr] DllMain already defined
От: AlexGin Беларусь  
Дата: 28.05.12 13:10
Оценка:
Здравствуйте, 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; 
        }
Re[10]: [linkerr] DllMain already defined
От: MasterZiv СССР  
Дата: 28.05.12 14:11
Оценка:
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)
Posted via RSDN NNTP Server 2.1 beta
Re[10]: [linkerr] DllMain already defined
От: MasterZiv СССР  
Дата: 28.05.12 14:15
Оценка:
On 05/28/2012 05:01 PM, AlexGin wrote:

> Нет, не будет работать!

>
> Вот подробности:

Это очень сложный вопрос, а в статьях очень много букаф.
Вполне возможно даже, что какой-то код в таком проекте
будет работать, а другой -- не будет. Далеко не все
части MFC требуют наличие его проинициализированных
статических данных.

Хотя я бы просто не стал мучится, даже пробовать --
пишеш DLL, значит и MFC должно быть в DLL.
И в идеале приложение его должно инициализировать.
Posted via RSDN NNTP Server 2.1 beta
Re[11]: [linkerr] DllMain already defined
От: AlexGin Беларусь  
Дата: 28.05.12 15:11
Оценка:
Здравствуйте, 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
Это правильно!
Re[11]: [linkerr] DllMain already defined
От: AlexGin Беларусь  
Дата: 28.05.12 15:28
Оценка:
Здравствуйте, 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) обеспечит нам дальнейшие грабли
Re[12]: [linkerr] DllMain already defined
От: MasterZiv СССР  
Дата: 28.05.12 16:29
Оценка:
On 05/28/2012 07:28 PM, AlexGin wrote:
> Допустим, что я сделал по твоему рецепту, то есть написал этот код в таком виде:
> Здесь я предполагаю, что мы работаем даже не в головном *.exe модуле, а в
> какой-либо другой (не Telecontrol.dll) библиотеке:

Это всё равно. AfxSetResourceHandle надо ставить всегда.

> Что будет дальше, когда мы выйдем из данного участка?

> Хендл ресурсов останется на бибилитотеке Telecontrol.dll, вместо перехода на
> текущую библиотеку.

Что такое "текущая библиотека" ?

> Наличие хендла на *старой библиотеке* (которая Telecontrol.dll) обеспечит нам

> дальнейшие грабли

Нет, если весь код будет правильным, будет соответствовать этим правилам.
Тут главное понять, что AfxSetResourceHandle надо ставить всегда,
и надеятся на какую-то "текущую библиотеку" бессмысленно.
Если это правило соблюдается, то всё будет работать всегда.

Другая модель поведения с "текущим активным источником ресурсов" тоже
конечно же допустима, только возни с ней больше, а толку мало.

AfxSetResourceHandle() собственно и разрабатывался с заточкой под
модель с "текущим активным источником ресурсов".
Ну и если у тебя одно приложение и одна .dll — может оно и хорошо.
Если модулей несколько сотен, и любой чих может вызвать смену "текущего
ресурса" -- дело другое.
Posted via RSDN NNTP Server 2.1 beta
Re[13]: [linkerr] DllMain already defined
От: AlexGin Беларусь  
Дата: 29.05.12 06:52
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>On 05/28/2012 07:28 PM, AlexGin wrote:

>> Допустим, что я сделал по твоему рецепту, то есть написал этот код в таком виде:
>> Здесь я предполагаю, что мы работаем даже не в головном *.exe модуле, а в
>> какой-либо другой (не Telecontrol.dll) библиотеке:

MZ>Это всё равно. AfxSetResourceHandle надо ставить всегда.

Ну а если мы обращаемся к "своему" модулю? То есть в переключении ресурсов нет необходимости.

>> Что будет дальше, когда мы выйдем из данного участка?

>> Хендл ресурсов останется на бибилитотеке Telecontrol.dll, вместо перехода на
>> текущую библиотеку.

MZ>Что такое "текущая библиотека" ?

У меня имеется проект, где есть основной модуль (назовем его MyProg.exe) и примерно 15 модулей *.dll.
Я привел выше код из библиотеки поддержки отображения специальных ситуаций (назовем ее Special.dll) — вот ее я и назвал текущей.
Приведенный мною код характерен для случая, когда библиотеке Special.dll требуется поработать с окнами и ресурсами библиотеки телеуправления (под названием Telecontrol.dll).

>> Наличие хендла на *старой библиотеке* (которая Telecontrol.dll) обеспечит нам

>> дальнейшие грабли

MZ>Нет, если весь код будет правильным, будет соответствовать этим правилам.

MZ>Тут главное понять, что AfxSetResourceHandle надо ставить всегда,
MZ>и надеятся на какую-то "текущую библиотеку" бессмысленно.
MZ>Если это правило соблюдается, то всё будет работать всегда.
+1
Соглашусь, это в действительности будет работать.
ИМХО надеяться на "текущую библиотеку" вполне допустимо.
Конечно при условии, что данный файл *.cpp находится в одном, соответствующем библиотеке, проекте (*.dll или *.exe модуля).

MZ>Другая модель поведения с "текущим активным источником ресурсов" тоже

MZ>конечно же допустима, только возни с ней больше, а толку мало.
Почему же больше возни?
В твоем подходе всюду, где есть использование ресурсов (даже своих), надо ставить AfxSetResourceHandle.
В моем подходе — вмешательство требуется только тогда, когда вызываются окна "чужого" модуля.

MZ>AfxSetResourceHandle() собственно и разрабатывался с заточкой под

MZ>модель с "текущим активным источником ресурсов".
MZ>Ну и если у тебя одно приложение и одна .dll — может оно и хорошо.
MZ>Если модулей несколько сотен, и любой чих может вызвать смену "текущего
MZ>ресурса" -- дело другое.
У меня модулей примерно 15 штук.
Скажем тогда так: любое сознательное обращение к "чужому" модулю, вызывает смену "текущего ресурса"!

Мою подход вообще-то взят не с потолка, он предлагается разными авторами:
http://www.codeguru.com/cpp/cpp/cpp_mfc/tutorials/article.php/c4023/MFC-DLL-TUTORIAL-PART-3.htm
http://www.ucancode.net/Visual_C_MFC_Example/Export-dialog-to-mfc-extension-dll.htm

Разработчики MFC из MS также поддерживает данный подход:
http://msdn.microsoft.com/en-us/library/h5f7ck28%28v=vs.80%29.aspx

...use the functions AfxGetResourceHandle and AfxSetResourceHandle to save the old handle and set the new handle. Be sure to restore the old resource handle before you return to the client application. For an example of using this approach to explicitly load a menu, see Testdll2 .cpp in the MFC sample DLLHUSK.



З.Ы. В общем ясное дело — тема начала переходить в КСВ
И мой и твой подход — имеют право на жизнь.
Применять тот или иной — скорее дело вкуса.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.