|
|
Comments and Discussions
|
|
 |

|
IS it me, or in Thunk32.h at the bottom where it reads
#define BOOST_PP_ITERATION_PARAMS_1 (3,(0,THUNK32_MAX_ARGS,"Thunk32_template.h"))
??=include BOOST_PP_ITERATE()
#undef BOOST_PP_ITERATION_PARAMS_1
should it instead be
#define BOOST_PP_ITERATION_PARAMS_1 (3,(0,THUNK32_MAX_ARGS,"Thunk32_template.h"))
#include BOOST_PP_ITERATE()
#undef BOOST_PP_ITERATION_PARAMS_1
I had to make such a change to get the Thunk32 project to compile. I had downloaded the demo file, and then added the project into my solution (talking visual studio 2010 here) But now when I try to build the project that is using the Thunk32 functionality, I get linker errors; unresolved externals, which from the error message I believe are pointing the a problem with some thunk code that is public trying to use code that is protected... or a public template code is trying to use some protected thunkbase code.
Any help would be really appreciated.
|
|
|
|

|
An excellent article! Thanks for this.
And i have question:
When i want to use a __cdecl covention - do I must to change an asm code for it? I'm looking on msdn for the difference of the __stdcall and __cdecl but didn't find how it realise in this case. Can you help?
|
|
|
|

|
I have been searching for a solution for this prob for some time and couldn't find a decent solution for using member functions as callbacks.
Really good work. But one thing that annoys me a lot is the size of joost library. I am still not able to install it correctly therefore the demo project is not working. But i am sure if i spent some time on it then this will be the most efficient and generic solution. If this project worked correctly then i will be going to integrate this solution in my project. Can I selectively add in the source control only those joost library file which are used in your project? or I have to add the complete library in the source control?
Take a very good care of Yourself.
Sayed Ahmad Mursil
|
|
|
|

|
Support for 64 bit is also one issue where i am not sure this approach will be the best alternative.. I have seen your article on 64 bit support as well and i dont think that thunking is Win64 is feasible.
Mursil
|
|
|
|

|
I'm fairly certain the dependencies the Thunk32 libraries have to boost are headers only. You do not have to build, or include, any of the library files for it to work. Just download the source package (or binary distribution) from http://www.boost.org, set the include paths accordingly in your development environment, and you should be ready to go.
|
|
|
|

|
This method is close to the one in ATL 3.0 for window thunk in 'AtlBase.h' (struct _stdcallthunk), but in call WndProc the ATL thunk change the first parameter (HWND) with the pointer of the CWindowImpl derived class to access the related instance in the static callback (WindowProc).
I remake ATL to compile with GCC (in a posix environment) without using this method. It's dangerous and is not pure C/C++, the assembly code is not 'portable'. I used another method, more expensive, but in pure C/C++ code. You need a global object (like in ATL CComModule) and before the callback invocation (in same example, before the CreateWindowEx API) enter a critical section and call a method of the global object that save the pointer of the object you need in the callback in a array (vector or map), then call the API that invoke the callback and leave the critical section.
In the callback enter critical section, get the pointer to the object from the global object (CComModule) and leave critical section.
To do this you need an hash value or a unique identifier to save the pair into map (or the index of an array) and to retrieve it. The callback is in sama scope of your code, but the trick is to exit from the object instance and remain in global scope, so the global object maintain a pointer of all the instancies of the objects used in the callback. The callback can access this object to ask it the right pointer based on an identifier. but you can use this method only if in the callback there is a value to distinguish each object into array, for WindowProc is natural use the HWND, it's unique for each window and can be associated with the object we need to reference.
This method is not fast if there are many object to store into array, but don't make use of assembly. If there is no global object, you can use thread local storage TLS to save object pointers.
bye, caio
-- modified at 0:35 Sunday 5th August, 2007
|
|
|
|

|
Yeah, there are many different approaches to the wndproc problem. Another widely used technique is to add windows hooks to capture the first few messages arriving prior to the WM_CREATE. That enables you to do the jump from a global or static wndproc, to a member function wndproc, in a pure C++ way -- without missing any messages, nor keeping a map to target the right class instance.
As for the thunking, it isn't as much "dangerous" as it is unportable and horribly impractical for x64 builds (I made a post about that on my blog).
|
|
|
|

|
my system is the linux/ps2 kit. will your code work on this? the processor is mips so im pretty sure the assembler stuff wont work at all, will it?
loving your work.
|
|
|
|

|
Sorry for being such a terribly slow responder.
I'm afraid the code won't work given that architecture. At the same time, it shouldn't be too much work to rewrite the asm code. Once that's completed, all that's left to do is avoid all platform specific function calls, which I'll have to admit I haven't focused much on in this library.
|
|
|
|

|
more easy to use
support parameters and return value
class c1
{
public:
void test1(){}
};
....
c1 o1;
xThisCall calltest( &o1, &c1::test1 );
calltest.call();
xThisCall calltestcopy = calltest;
calltestcopy.call();
////////////////////////////////////////////code//////////////////////////////////////
namespace xlibplus
{
template < class TRet, class T >
inline TRet ThisCall0( T func, LPVOID pThis )
{
TRet lpRet;
__asm mov ecx, pThis;
//__asm push eax
__asm call dword ptr[func];
__asm mov lpRet, eax
return lpRet;
}
template < class TRet, class T, class Tp1 >
inline TRet ThisCall1( T func, LPVOID pThis, Tp1 lpParam1 )
{
TRet lpRet;
__asm push dword ptr[lpParam1]
__asm mov ecx, pThis;
//__asm push eax
__asm call dword ptr[func];
__asm mov lpRet, eax
return lpRet;
}
template < class TRet, class T, class Tp1, class Tp2 >
inline TRet ThisCall2( T func, LPVOID pThis, Tp1 lpParam1, Tp2 lpParam2 )
{
TRet lpRet;
__asm push dword ptr[lpParam2]
__asm push dword ptr[lpParam1]
__asm mov ecx, pThis;
//__asm push eax
__asm call dword ptr[func];
__asm mov lpRet, eax
return lpRet;
}
template < class TRet, class T, class Tp1, class Tp2, class Tp3 >
inline TRet ThisCall3( T func, LPVOID pThis, Tp1 lpParam1, Tp2 lpParam2, Tp3 lpParam3 )
{
TRet lpRet;
__asm push dword ptr[lpParam3]
__asm push dword ptr[lpParam2]
__asm push dword ptr[lpParam1]
__asm mov ecx, pThis;
//__asm push eax
__asm call dword ptr[func];
//__asm push eax
__asm mov lpRet, eax
return lpRet;
}
template < class TRet, class T, class Tp1, class Tp2, class Tp3, class Tp4 >
inline TRet ThisCall4( T func, LPVOID pThis, Tp1 lpParam1, Tp2 lpParam2, Tp3 lpParam3, Tp4 lpParam4 )
{
TRet lpRet;
__asm push dword ptr[lpParam4]
__asm push dword ptr[lpParam3]
__asm push dword ptr[lpParam2]
__asm push dword ptr[lpParam1]
__asm mov ecx, pThis;
//__asm push eax
__asm call dword ptr[func];
__asm mov lpRet, eax
return lpRet;
}
template < class TRet, class T, class Tp1, class Tp2, class Tp3, class Tp4, class Tp5 >
inline TRet ThisCall5( T func, LPVOID pThis, Tp1 lpParam1, Tp2 lpParam2, Tp3 lpParam3, Tp4 lpParam4, Tp5 lpParam5 )
{
TRet lpRet;
__asm push dword ptr[lpParam5]
__asm push dword ptr[lpParam4]
__asm push dword ptr[lpParam3]
__asm push dword ptr[lpParam2]
__asm push dword ptr[lpParam1]
__asm mov ecx, pThis;
//__asm push eax
__asm call dword ptr[func];
__asm mov lpRet, eax
return lpRet;
}
template < class T >
inline LPVOID F2P( T func )
{
__asm mov eax, dword ptr[func];
}
template< class TRet = LPVOID >
class xThisCallCustom
{
typedef xThisCallCustom xThisClass;
public:
xThisCallCustom()
{
m_lpThis = NULL;
m_lpFunc = NULL;
}
xThisCallCustom(const xThisClass & thiscall )
{
m_lpThis = thiscall.m_lpThis;
m_lpFunc = thiscall.m_lpFunc;
}
template
xThisCallCustom(LPVOID lpThis, T func)
{
m_lpThis = lpThis;
m_lpFunc = F2P(func);
}
LPVOID getThisPtr()const{ return m_lpThis;}
VOID setThisPtr( LPVOID lpThis ){ m_lpThis = lpThis;}
LPVOID getFuncPtr()const{ return m_lpFunc;}
template VOID setFuncPtr( T func ){ m_lpFunc = F2P( func );}
TRet call()
{
if( !Assigned() )return NULL;
return ThisCall0( m_lpFunc, m_lpThis );
}
template < class Tp1 >
TRet call( Tp1 lpParam1 )
{
if( !Assigned() )return NULL;
return ThisCall1( m_lpFunc, m_lpThis, lpParam1 );
}
template < class Tp1, class Tp2 >
TRet call( Tp1 lpParam1, Tp2 lpParam2 )
{
if( !Assigned() )return NULL;
return ThisCall2( m_lpFunc, m_lpThis, lpParam1, lpParam2 );
}
template < class Tp1, class Tp2, class Tp3 >
TRet call( Tp1 lpParam1, Tp2 lpParam2, Tp3 lpParam3 )
{
if( !Assigned() )return NULL;
//LPVOID lpRet = NULL;
return ThisCall3( m_lpFunc, m_lpThis, lpParam1, lpParam2, lpParam3 );
//__asm pop lpRet;
//return lpRet;
}
template < class Tp1, class Tp2, class Tp3, class Tp4 >
TRet call( Tp1 lpParam1, Tp2 lpParam2, Tp3 lpParam3, Tp4 lpParam4 )
{
if( !Assigned() )return NULL;
return ThisCall4( m_lpFunc, m_lpThis, lpParam1, lpParam2, lpParam3, lpParam4 );
}
template < class Tp1, class Tp2, class Tp3, class Tp4, class Tp5 >
TRet call( Tp1 lpParam1, Tp2 lpParam2, Tp3 lpParam3, Tp4 lpParam4, Tp5 lpParam5 )
{
if( !Assigned() )return NULL;
return ThisCall5( m_lpFunc, m_lpThis, lpParam1, lpParam2, lpParam3, lpParam4, lpParam5 );
}
template < class TTHIS >
TRet callWithThis(TTHIS * pThis)
{
if( !Assigned() )return NULL;
return ThisCall0( m_lpFunc, pThis );
}
template < class TTHIS, class Tp1 >
TRet callWithThis( TTHIS * pThis, Tp1 lpParam1 )
{
if( !Assigned() )return NULL;
return ThisCall1( m_lpFunc, pThis, lpParam1 );
}
template < class TTHIS, class Tp1, class Tp2 >
TRet callWithThis( TTHIS * pThis, Tp1 lpParam1, Tp2 lpParam2 )
{
if( !Assigned() )return NULL;
return ThisCall2( m_lpFunc, pThis, lpParam1, lpParam2 );
}
template < class TTHIS, class Tp1, class Tp2, class Tp3 >
TRet callWithThis( TTHIS * pThis, Tp1 lpParam1, Tp2 lpParam2, Tp3 lpParam3 )
{
if( !Assigned() )return NULL;
return ThisCall3( m_lpFunc, pThis, lpParam1, lpParam2, lpParam3 );
}
template < class TTHIS, class Tp1, class Tp2, class Tp3, class Tp4 >
TRet callWithThis( TTHIS * pThis, Tp1 lpParam1, Tp2 lpParam2, Tp3 lpParam3, Tp4 lpParam4 )
{
if( !Assigned() )return NULL;
return ThisCall4( m_lpFunc, pThis, lpParam1, lpParam2, lpParam3, lpParam4 );
}
template < class TTHIS, class Tp1, class Tp2, class Tp3, class Tp4, class Tp5 >
TRet callWithThis( TTHIS * pThis, Tp1 lpParam1, Tp2 lpParam2, Tp3 lpParam3, Tp4 lpParam4, Tp5 lpParam5 )
{
if( !Assigned() )return NULL;
return ThisCall5( m_lpFunc, pThis, lpParam1, lpParam2, lpParam3, lpParam4, lpParam5 );
}
xThisClass & operator =( const xThisClass & thiscall )
{
this->m_lpFunc = thiscall.m_lpFunc;
this->m_lpThis = thiscall.m_lpThis;
return *this;
}
BOOL Assigned(){ return (m_lpFunc != NULL);}
protected:
LPVOID m_lpThis;
LPVOID m_lpFunc;
};
typedef xThisCallCustom<> xThisCall;
typedef xThisCallCustom<> xEventCall;
typedef xThisCallCustom xCompareCall;
};
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
|
A quick introduction to thunking, as well as a demonstration of a simple library which does the work for us.
| Type | Article |
| Licence | Apache |
| First Posted | 16 Dec 2006 |
| Views | 55,848 |
| Downloads | 416 |
| Bookmarked | 52 times |
|
|