65.9K
CodeProject is changing. Read more.
Home

Pass Class Method as Static function to API Calls

starIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIconemptyStarIcon

1.86/5 (4 votes)

Mar 13, 2002

viewsIcon

81448

Pass Class Methods to API Calls where Static Functions are required using CThunk class

Introduction

A number of times we need to define static functions in a class to pass them to API Calls like Window Proc, Thread Proc, etc. Typically we define a static/global function and pass this as one parameter and recast that parameter into object again. In these cases, we can define a thunk that generates the Static Procedure at runtime, and pass the generated Proc to the API Function. All we need to set this correctly at runtime and jump to required address.

Code listing

The following class CThunk does the same thing.

/*
Thunk Class 
Parameters:

F1:   Static Proc
F2:   Class function
T1 :  Class

// Function Types F1 & F2 should have same parameters 
// and return type otherwise stack corruption will occur

*/

#if defined(_M_IX86)
#pragma pack(push,1)

template <typename F1,typename F2, typename T1>
class CThunk
{
public:
    struct _ProcThunk
    {
        BYTE m_movcx;          
        DWORD m_pThis;
        BYTE    m_jmp;          // jmp WndProc
        DWORD   m_relproc;      // relative jmp
    };

    _ProcThunk thunk;

    void Init(F2 proc, T1 * pClass)
    {
        //make sure that 'this' is in ecx pointer
        // otherwsie code does not work
#ifdef _DEBUG
        long  pthis;
        _asm  { mov         dword ptr [pthis],ecx }; 
        assert(pthis == (long) this);
#endif
        // put values
        thunk.m_movcx = 0xB9;  //B9
        thunk.m_pThis= (DWORD)pClass;
        thunk.m_jmp = 0xe9;
        thunk.m_relproc = 
            *((int *) &proc) - ((int)this+sizeof(_ProcThunk));

        // write block from data cache and 
        // flush from instruction cache
        FlushInstructionCache(GetCurrentProcess(), 
            &thunk, sizeof(thunk));
    }

    F1 GetStaticProc()
    {
        return reinterpret_cast<F1> (&thunk);
    }
};
#pragma pack(pop)
#else
#error Only X86 supported
#endif

Usage

The following code shows the usage of CThunk class for threads Proc. This class can be used in other places where Static procs are required. In this code CThunk class is used to create a thunk for the _beginthread API Call.

//Test Thread class

typedef void( __cdecl *THREADPROC )( void * );

class CThreadTest
{
protected:
    typedef LRESULT (CThreadTest::*FTN)
        (LPVOID lpThreadParameter);

    // THREADPROC & FTN have same signature
    CThunk<THREADPROC,FTN,CThreadTest> m_th; 

    HANDLE m_hThread;


public:
    //data
    int m_y;
    CThreadTest()
    {
        //Intialize the Thunk
        m_th.Init(CThreadTest::ThreadFunction,this);

    }
    LRESULT ThreadFunction(LPVOID lpThreadParameter)
    {
        int ntime =(int) lpThreadParameter;
        printf("%d",m_y); // this pointer is set correctly
        Sleep(ntime);
        return 0;
    }

    BOOL Create (int nSleeptime)
    {
        //Get Static Proc
        THREADPROC tp =m_th.GetStaticProc();

        // pass proc to  _beginthread
        m_hThread = (HANDLE)_beginthread(tp, 0,
            (LPVOID)nSleeptime);
        return TRUE;
    }

    void WaitForThread()
    {
        WaitForSingleObject(m_hThread,INFINITE);

    }


};



int main(int argc, char* argv[])
{
    CThreadTest t1;
    t1.m_y=100;

    t1.Create(1000);



    t1.WaitForThread();


    return 0;
}