Quantcast

Fwd: [Thread] Solution to conflict with MFC?

classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Fwd: [Thread] Solution to conflict with MFC?

Thorsten Ottosen-3
Hi Thread maintainers,

Anthony speaks about a patch to make this work. Does anyone know where
it is? And could it be applied?

Thanks

-Thorsten

-------- Original Meddelelse --------
Subject: [Thread] Solution to conflict with MFC?
Date: Tue, 26 Apr 2011 13:28:56 +0200
From: Christian Larsen <[hidden email]>
Reply-To: [hidden email]
To: [hidden email]
Newsgroups: gmane.comp.lib.boost.user

Hello,

I know this has been asked before, but I could not find a good solution.
I'm experiencing problems with an application using both MFC and
Boost.Thread. Specifically the assertion

ASSERT(AfxGetModuleState() != AfxGetAppModuleState());

in AfxCoreInitModule() fails. I link Boost.Thread statically into a DLL
in my project.

 From previous posts to this list and elsewhere, e.g.
http://lists.boost.org/boost-users/2009/04/46929.php, I see that the
issue is caused by setting _pRawDllMain in tss_pe.cpp. Commenting this
line does "solve" the problem, but I would rather not have to hack the
Boost source code this way.

It seems there is a patch somewhere for this problem (referred to in
http://lists.boost.org/boost-users/2009/04/47015.php), but it appears it
never made it into the source. Is there any chance of this issue being
solved in a better way?

Best regards,
Christian Larsen
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Fwd: [Thread] Solution to conflict with MFC?

Anthony Williams-4
Thorsten Ottosen <[hidden email]> writes:

> Anthony speaks about a patch to make this work. Does anyone know where
> it is? And could it be applied?

It is more of a hack than a patch: remove the use of _pRawDllMain from
tss_pe.cpp, and add a new object file outside the boost thread library
that contains a _pRawDllMain that calls both the MFC and Boost
initialization functions. The user must explicitly add that object file
to their project.

Anthony
--
Author of C++ Concurrency in Action     http://www.stdthread.co.uk/book/
just::thread C++0x thread library             http://www.stdthread.co.uk
Just Software Solutions Ltd       http://www.justsoftwaresolutions.co.uk
15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Fwd: [Thread] Solution to conflict with MFC?

Thorsten Ottosen-3
Den 27-04-2011 17:13, Anthony Williams skrev:
> Thorsten Ottosen<[hidden email]>  writes:

> It is more of a hack than a patch: remove the use of _pRawDllMain from
> tss_pe.cpp, and add a new object file outside the boost thread library
> that contains a _pRawDllMain that calls both the MFC and Boost
> initialization functions. The user must explicitly add that object file
> to their project.

Hm. That does sound like a hack. But at least it doesn't require users
to modify boost source code whenever they upgrade boost.

Is there any possibility that the initialization of this pointer
in tss_pe.cpp can be made dynamic based on some parameter
passed to the code? It would be really cool if we could just say

#define BOOST_THREAD_DISABLED_DLL_CALLBACK 1
#include <boost/thread.hpp>

in the code that needs it. AFAICR, we can have global data in headers
as long as it is inside some template.

-Thorsten
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Fwd: [Thread] Solution to conflict with MFC?

Anthony Williams-4
Thorsten Ottosen <[hidden email]> writes:

> Den 27-04-2011 17:13, Anthony Williams skrev:
>> Thorsten Ottosen<[hidden email]>  writes:
>
>> It is more of a hack than a patch: remove the use of _pRawDllMain from
>> tss_pe.cpp, and add a new object file outside the boost thread library
>> that contains a _pRawDllMain that calls both the MFC and Boost
>> initialization functions. The user must explicitly add that object file
>> to their project.
>
> Hm. That does sound like a hack. But at least it doesn't require users
> to modify boost source code whenever they upgrade boost.
>
> Is there any possibility that the initialization of this pointer
> in tss_pe.cpp can be made dynamic based on some parameter
> passed to the code? It would be really cool if we could just say
>
> #define BOOST_THREAD_DISABLED_DLL_CALLBACK 1
> #include <boost/thread.hpp>
>
> in the code that needs it. AFAICR, we can have global data in headers
> as long as it is inside some template.

For the DLL callback to be called automatically, there must be an extern
"C" global variable called _pRawDllMain, which must be statically
initialized to point to the callback function.

I don't see how you could put that in a header without risking multiple
definition errors --- the header that initialized it would have to be
included exactly once across the whole project. Failure to include it
anywhere would mean that the init function would not be linked.

I haven't tried it, but I think that if the application defines
boost::tss_cleanup_implemented() then tss_pe.cpp will not get linked
from the library, so the DLL callback will not be linked, and the MFC
one should therefore work. Of course, you will then need to ensure that
boost::on_thread_exit() is called when every thread exits to avoid
leaking memory and/or resources.

Anthony
--
Author of C++ Concurrency in Action     http://www.stdthread.co.uk/book/
just::thread C++0x thread library             http://www.stdthread.co.uk
Just Software Solutions Ltd       http://www.justsoftwaresolutions.co.uk
15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Fwd: [Thread] Solution to conflict with MFC?

Thorsten Ottosen-3
Den 27-04-2011 18:21, Anthony Williams skrev:
> Thorsten Ottosen<[hidden email]>  writes:
>
>> Den 27-04-2011 17:13, Anthony Williams skrev:
>>> Thorsten Ottosen<[hidden email]>   writes:

>> Is there any possibility that the initialization of this pointer
>> in tss_pe.cpp can be made dynamic based on some parameter
>> passed to the code? It would be really cool if we could just say
>>
>> #define BOOST_THREAD_DISABLED_DLL_CALLBACK 1
>> #include<boost/thread.hpp>
>>
>> in the code that needs it. AFAICR, we can have global data in headers
>> as long as it is inside some template.
>
> For the DLL callback to be called automatically, there must be an extern
> "C" global variable called _pRawDllMain, which must be statically
> initialized to point to the callback function.
>
 > I don't see how you could put that in a header without risking >
 >multiple
 > definition errors --- the header that initialized it would have to be
 > included exactly once across the whole project. Failure to include it
 > anywhere would mean that the init function would not be linked.

I searched the source directory to locate this variable. Is

extern BOOL (WINAPI * const _pRawDllMain)(HANDLE, DWORD,LPVOID);

not just a declaration of a variable located somewhere else?

If so, we only need to put the initialization of this variable
in a header.

> I haven't tried it, but I think that if the application defines
> boost::tss_cleanup_implemented() then tss_pe.cpp will not get linked
> from the library, so the DLL callback will not be linked, and the MFC
> one should therefore work. Of course, you will then need to ensure that
> boost::on_thread_exit() is called when every thread exits to avoid
> leaking memory and/or resources.

yeah, that won't work well. Then it's far better to include a seperate
.cpp file.

-Thorsten

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Fwd: [Thread] Solution to conflict with MFC?

Peter Schregle
In reply to this post by Anthony Williams-4
Am 27.04.2011 18:21, schrieb Anthony Williams:
>
> I don't see how you could put that in a header without risking multiple
> definition errors --- the header that initialized it would have to be
> included exactly once across the whole project. Failure to include it
> anywhere would mean that the init function would not be linked.
>

Would __declspec (selectany) be of any help?

Peter

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Fwd: [Thread] Solution to conflict with MFC?

Anthony Williams-4
In reply to this post by Thorsten Ottosen-3
Thorsten Ottosen <[hidden email]> writes:

> Den 27-04-2011 18:21, Anthony Williams skrev:
>> Thorsten Ottosen<[hidden email]>  writes:
>>
>>> Den 27-04-2011 17:13, Anthony Williams skrev:
>>>> Thorsten Ottosen<[hidden email]>   writes:
>
>>> Is there any possibility that the initialization of this pointer
>>> in tss_pe.cpp can be made dynamic based on some parameter
>>> passed to the code? It would be really cool if we could just say
>>>
>>> #define BOOST_THREAD_DISABLED_DLL_CALLBACK 1
>>> #include<boost/thread.hpp>
>>>
>>> in the code that needs it. AFAICR, we can have global data in headers
>>> as long as it is inside some template.
>>
>> For the DLL callback to be called automatically, there must be an extern
>> "C" global variable called _pRawDllMain, which must be statically
>> initialized to point to the callback function.
>>
>> I don't see how you could put that in a header without risking >
>> multiple
>> definition errors --- the header that initialized it would have to be
>> included exactly once across the whole project. Failure to include it
>> anywhere would mean that the init function would not be linked.
>
> I searched the source directory to locate this variable. Is
>
> extern BOOL (WINAPI * const _pRawDllMain)(HANDLE, DWORD,LPVOID);
>
> not just a declaration of a variable located somewhere else?
As you've written it, it would be. In the real code there's actually an initializer:

extern BOOL (WINAPI * const _pRawDllMain)(HANDLE, DWORD, LPVOID)=&dll_callback;

which means that it is a const variable with external linkage.

> If so, we only need to put the initialization of this variable
> in a header.

But doing so would yield multiple initialization errors.

>> I haven't tried it, but I think that if the application defines
>> boost::tss_cleanup_implemented() then tss_pe.cpp will not get linked
>> from the library, so the DLL callback will not be linked, and the MFC
>> one should therefore work. Of course, you will then need to ensure that
>> boost::on_thread_exit() is called when every thread exits to avoid
>> leaking memory and/or resources.
>
> yeah, that won't work well. Then it's far better to include a seperate
> .cpp file.

Anyone care to try the attached file?

Anthony
--
Author of C++ Concurrency in Action     http://www.stdthread.co.uk/book/
just::thread C++0x thread library             http://www.stdthread.co.uk
Just Software Solutions Ltd       http://www.justsoftwaresolutions.co.uk
15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976

#include <windows.h>
#include <boost/thread/detail/tss_hooks.hpp>
extern "C" BOOL WINAPI RawDllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID);

namespace
{
    BOOL WINAPI dll_callback(HANDLE h, DWORD dwReason, LPVOID p)
    {
        if(!RawDllMain(static_cast<HINSTANCE>(h),dwReason,p))
            return false;
       
        switch (dwReason)
        {
        case DLL_THREAD_DETACH:
            boost::on_thread_exit();
            break;
        case DLL_PROCESS_DETACH:
            boost::on_process_exit();
            break;
        }
        return true;
    }
}

extern "C"
{
    extern BOOL (WINAPI * const _pRawDllMain)(HANDLE, DWORD, LPVOID)=&dll_callback;
}

namespace boost
{
    void tss_cleanup_implemented()
    {}
}

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Fwd: [Thread] Solution to conflict with MFC?

Christian Larsen-2
Den 28-04-2011 08:41, Anthony Williams skrev:
> Anyone care to try the attached file?
Including your test.cpp in all DLLs using both MFC and Boost.Thread did
the trick. Thank you very much!

Best regards,
Christian

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Fwd: [Thread] Solution to conflict with MFC?

Thorsten Ottosen-3
In reply to this post by Peter Schregle

> Would __declspec (selectany) be of any help?

 From

http://msdn.microsoft.com/en-US/library/5tkz6s71%28v=VS.80%29.aspx

"A global data item can normally be initialized only once in an EXE or
DLL project. selectany can be used in initializing global data defined
by headers, when the same header appears in more than one source file.
selectany is available in both the C and C++ compilers."

I guess this could be exactly what we need.

-Thorsten
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Fwd: [Thread] Solution to conflict with MFC?

Vyacheslav Lanovets
Hi,

In MSVC __declspec (selectany) cannot be used for functions but it's possible to emulate using "__declspec(noinline) inline" (http://blogs.msdn.com/b/freik/archive/2005/10/26/485276.aspx). Seems to produce same mangled name as normal _cdecl.

The workaround from Anthony Williams works well to make MFC work with boost::thread but it should be included only once per project.

For boost linked dynamically, the following file allows inclusion in any number of files in the project. Actually, I included it in StdAfx.h. Did not give it extensive testing but seems to work both on Windows CE / Windows Mobile and Win32 builds.

Comments are welcome.
 

#ifdef _MSC_VER

#if !defined(_LIB) && (defined(_AFXEXT) || defined(_USRDLL) || defined(_WINDLL)) // DLLs only

#include <boost/thread/thread.hpp>
#include <boost/thread/detail/tss_hooks.hpp> 

// Use custom entry point to call into boost::thread hooks
// It's safe to call hooks before global data initialization by CRTL because boost::thread overrides RawDllMain which is also called earlier than CRTL's DLLMain.
#pragma comment(linker, "/ENTRY:tps_entry")

extern "C" BOOL WINAPI
_DllMainCRTStartup(
                                   HANDLE  hDllHandle,
                                   DWORD   dwReason,
                                   LPVOID  lpreserved
                                   );

// "__declspec(noinline) inline" is used to get __declspec(selectany) flag
// because __declspec(selectany) cannot be applied to functions directly
// Could use template for that but then mangled name should be designated as entry point
extern "C" __declspec(noinline) inline BOOL WINAPI tps_entry(
        HANDLE  hDllHandle,
        DWORD   dwReason,
        LPVOID  lpreserved
        )
{
        // here define DLL hook (and EXE hook below)
        switch (dwReason)
        {
        case DLL_PROCESS_ATTACH:
                boost::on_process_enter();
                break;
        case DLL_THREAD_ATTACH:
                boost::on_thread_exit();
                break;
        case DLL_THREAD_DETACH:
                boost::on_thread_exit();
                break;
        case DLL_PROCESS_DETACH:
                boost::on_process_exit();
                break;
        }
        return _DllMainCRTStartup(hDllHandle, dwReason, lpreserved);
}

// Special protocol to indicate to boost::thread that we did support custom tss cleanup hooks
// Use of "__declspec(noinline) inline" allows multiple definition across the project as results in __declspec(selectany) flag
namespace boost
{
        __declspec(noinline) inline void tss_cleanup_implemented()
        {
        }
}

// Just to force inclusion of custom entry point to obj. Template is used to get __declspec(selectany) flag.
// Inline functions are not compiled in; even under debug.
template <typename> int tps_dummy_reserved()
{
        return &boost::tss_cleanup_implemented && &tps_entry;
}
template int tps_dummy_reserved<int>();

#endif // DLLs only


#endif
Loading...