搜了些thunk原理,其中有一句话实在不理解,有人用过thunk吗? 以下是几个头文件和main.cpp,应该直接能编译运行,异常出现位置见下面代码中注释部分,请教这咋整,谢谢。AJ_Thunk.h
#pragma pack(push,1)
struct AJ_Thunk {
DWORD _mov;
DWORD _this;
BYTE _jmp;
DWORD _relProc; void init(DWORD proc, void* pThis) { _mov = 0x042444C7;
_this = PtrToLong(pThis); _jmp = 0xE9;
_relProc = DWORD((INT_PTR)proc - ((INT_PTR)this + sizeof(AJ_Thunk))); FlushInstructionCache(GetCurrentProcess(), this, sizeof(AJ_Thunk));
}
};
#pragma pack(pop)AJ_Window.h
//#include "AJ_Component.h"
#include <string>
using namespace std;#define AJ_UI_CLASS_NAME "xxxx"
#include "Thunk/AJ_Thunk.h"LRESULT CALLBACK AJ_WndInitProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);LRESULT CALLBACK AJ_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); 
class AJ_Window {
private:

int a;
public:
HWND hWnd; AJ_Thunk* thunk; ATOM registerClass() { WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = AJ_WndInitProc;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = NULL ;
wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION ) ;
wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ) ;
wndclass.hbrBackground = ( HBRUSH ) GetStockObject( WHITE_BRUSH ) ;
wndclass.lpszMenuName = "" ;
wndclass.lpszClassName = AJ_UI_CLASS_NAME;
wndclass.hbrBackground = HBRUSH(COLOR_WINDOW  ) ; return RegisterClass(&wndclass);

}
AJ_Thunk* createThunk() {
thunk = new AJ_Thunk;
thunk->init((DWORD)AJ_WndInitProc, this); return thunk;
}
void showError() {
}
MSG msg;
void wait() {
while(GetMessage( &msg, NULL, 0, 0 )){
TranslateMessage( &msg ) ;
DispatchMessage( &msg ) ;
}
}
AJ_Window() : hWnd(NULL), a(9) {
this->registerClass(); string title = "aj window";
CreateWindow(
AJ_UI_CLASS_NAME,
title.c_str(),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT ,
CW_USEDEFAULT ,
//width ? width : 480,
//height ? height :260,
300,200,
NULL,
NULL,
NULL,
this ) ;
if(hWnd == NULL) {
this->showError();
} }
WNDPROC getThunk() {
return (WNDPROC)thunk;
}
~AJ_Window() {
delete thunk;
} void show() {
ShowWindow(hWnd, true);
}
void hide() {
ShowWindow(hWnd, false);
} void updateWindow() {
::UpdateWindow(hWnd);
}
void onPaint() {
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc, 10, 10, "tttt", 4);
EndPaint(hWnd, &ps);
}
void onDestory() {
PostQuitMessage(0);
}

};
LRESULT CALLBACK AJ_WndInitProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
if(msg == WM_NCCREATE) {
AJ_Window* win = (AJ_Window*)((LPCREATESTRUCT)lParam)->lpCreateParams;
win->hWnd = hWnd;
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)win->createThunk());
WNDPROC thunk = win->getThunk();
return (*thunk)(hWnd, msg, wParam, lParam); // 就这个地方异常
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}LRESULT CALLBACK AJ_WndProc(HWND hWnd, UINT msg, UINT wParam, UINT lParam) {
AJ_Window* pWindow = (AJ_Window*)hWnd;
switch(msg){
  case WM_PAINT:
  pWindow->onPaint();
  break;
  case WM_DESTROY:
  pWindow->onDestory();
  break;
  default:
  return DefWindowProc( hWnd, msg, wParam, lParam ) ;
}
return 0;
}
main.cpp
#include <Windows.h>#include "AJ_Window.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { AJ_Window* win = new AJ_Window(); win->show(); win->wait();
return 0;
}

解决方案 »

  1.   

    我是想封装个小的界面库,否则每次写一堆东西去生成一个window太麻烦了。
    请参考这个 http://blog.csdn.net/lqk1985/archive/2009/11/10/4791304.aspx
      

  2.   

    那还不如直接包装CWnd等类来得方便,简单,你用这种方法很容易有问题..以后维护也痛苦
      

  3.   

    想从sdk进行封装,不走mfc,atl,qt之类,虽然这样的代码的确维护性很差,移植性更差。。但传说ATL里就用到了类似thunk技术。于是乎想学习下。。
      

  4.   

    http://blog.csdn.net/lqk1985/archive/2009/11/10/4791304.aspx这绝对是对于新手的误导,这样的代码很大程度上依赖于编译器。不能称之为“技术”。谁能保证编译器每次生成的目标代码都一样?而且编译器在编译的时候会对代码进行优化,那就更不知道生成的目标代码是什么样子了。
      

  5.   

    thunk是在虚继承时为了维护徐函数表用的技术,依赖编译器实现不同。
    不明白你这里也拿来用了,既然都是windows,封装现有的问题不大吧,可移植性应该好点。
      

  6.   

    试了vc6和vc2008, 以下代码能在vc6下跑得很愉快,但是vc2008里就会出exception,异常出现在执行thunk语句处,但vc6下调试看整个流程和vc2008基本一样,只是内存地址不同,不知道2008为啥会有异常
    Unhandled exception at 0x006c4a58 in UI.exe: 0xC0000005: Access violation.
    AJ_Window.cpp
    //#include "AJ_Component.h"
    #include <string>
    using namespace std;#define AJ_UI_CLASS_NAME "xxxx"
    #include "Thunk/AJ_Thunk.h"LRESULT CALLBACK AJ_WndInitProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);LRESULT CALLBACK AJ_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); bool debug = false;
    void showError() {
    if(!debug) return;
    LPVOID buff;
    FormatMessage( 
    FORMAT_MESSAGE_ALLOCATE_BUFFER | 
    FORMAT_MESSAGE_FROM_SYSTEM | 
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    GetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
    (LPTSTR) &buff,
    0,
    NULL 
    ); MessageBox(NULL, (const char*)buff, "", NULL);}
    class AJ_Window {
    private:

    int a;
    public:
    HWND hWnd; AJ_Thunk* thunk; ATOM registerClass() { WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW ;
    wndclass.lpfnWndProc = AJ_WndInitProc;
    wndclass.cbClsExtra = 0 ;
    wndclass.cbWndExtra = 0 ;
    wndclass.hInstance = NULL ;
    wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION ) ;
    wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ) ;
    wndclass.hbrBackground = ( HBRUSH ) GetStockObject( WHITE_BRUSH ) ;
    wndclass.lpszMenuName = "" ;
    wndclass.lpszClassName = AJ_UI_CLASS_NAME;
    wndclass.hbrBackground = HBRUSH(COLOR_WINDOW  ) ; return RegisterClass(&wndclass);

    } AJ_Thunk* getThunk() {
    if(!thunk) {
    thunk = new AJ_Thunk;
    thunk->init((DWORD)AJ_WndProc, this);
    }
    return thunk;
    }
    void wait() {
    MSG msg;
    while(GetMessage( &msg, NULL, 0, 0 )){
    TranslateMessage( &msg ) ;
    DispatchMessage( &msg ) ;
    }
    }
    AJ_Window() : hWnd(NULL), thunk(NULL), a(9) {
    showError();
    this->registerClass();
    showError(); string title = "aj window";
    CreateWindow(
    AJ_UI_CLASS_NAME,
    title.c_str(),
    WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT ,
    CW_USEDEFAULT ,
    //width ? width : 480,
    //height ? height :260,
    300,200,
    NULL,
    NULL,
    NULL,
    this ) ; showError(); } ~AJ_Window() {
    delete thunk;
    } void show() {
    showError();
    int succ = ShowWindow(hWnd, SW_SHOWNORMAL);
    showError();
    UpdateWindow(hWnd); }
    void hide() {
    ShowWindow(hWnd, false);
    } void updateWindow() {
    ::UpdateWindow(hWnd);
    }
    void onPaint() {
    PAINTSTRUCT ps;
    HDC hdc;
    hdc = BeginPaint(hWnd, &ps);
    TextOut(hdc, 10, 10, "tttt", 4);
    EndPaint(hWnd, &ps);
    }
    void onDestory() {
    PostQuitMessage(0);
    }

    };
    LRESULT CALLBACK AJ_WndInitProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    showError();
    if(msg == WM_NCCREATE) {
    AJ_Window* win = (AJ_Window*)((LPCREATESTRUCT)lParam)->lpCreateParams;
    win->hWnd = hWnd;
    showError();
    SetWindowLong(hWnd, GWL_WNDPROC, (LONG)win->getThunk());
    showError();
    WNDPROC thunk = (WNDPROC)win->getThunk();
    return (thunk)((HWND)win, msg, wParam, lParam);
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
    }LRESULT CALLBACK AJ_WndProc(HWND pWin, UINT msg, WPARAM wParam, LPARAM lParam) {
    AJ_Window* pWindow = (AJ_Window*)pWin;
    switch(msg){
      case WM_PAINT:
      pWindow->onPaint();
      break;
      case WM_DESTROY:
      pWindow->onDestory();
      break;
      default:
      return DefWindowProc( pWindow->hWnd, msg, wParam, lParam ) ;
    }
    return 0;
    }
      

  7.   

    应该是
     AJ_Thunk* getThunk() {
            if(!thunk) {
                thunk = new AJ_Thunk;
                thunk->init((DWORD)AJ_WndProc, this);
            }
            return thunk;
        }
    估计是new的问题
    试试使用VirtualAlloc之类的API分配内存
      

  8.   

    楼上说的对,不能用new,且thunk必须是类的第一个数据成员。
    VC6和VC2008出现差异没碰到过,倒是因为WIN2003的数据执行保护会导致非法操作。
    关于thunk更详细的说明请看这里:http://blog.csdn.net/ringphone/archive/2004/09/28/118883.aspx
    不过这篇文章里的代码不能在WIN2003下运行,可运行的版本请到我博客下载RingSDK看里面的代码。
      

  9.   

    多谢, 改了下  vc2008下能运行了。
    AJ_Thunk* getThunk() {
    if(!thunk) {
    thunk = (AJ_Thunk*)::VirtualAlloc(NULL, sizeof( AJ_Thunk ), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    thunk->init((DWORD)AJ_WndProc, this);
    }
    return thunk;
    }