1. 程式人生 > >利用Thunk讓C++成員函式變回調函式

利用Thunk讓C++成員函式變回調函式

Windows API經常需要回調函式,而在C++開發中面向物件當行其道,若能讓C++類的成員函式成為回撥函式,簡直就是大善!但是C++成員函式都隱含了一個this指標用於指向當前的物件。要實現回撥確實不容易。

我大約一年前就接觸到Thunk技術,甚至也看過利用Thunk實現將成員函式變成回撥函式的例子。但是我實在沒了解過C++彙編後的樣子,很容易鑽了牛角尖,看都看不懂,直接用他們的程式又不敢,畢竟出錯後不好處理。前端時間偶爾想起Thunk技術,對未懂技術老這樣懸著很可能影響自己的程式設計師生涯的,於是決心閉關參悟(沒辦法,資質差啊),終於弄明白了。那種感覺啊,就像誠信禮佛的人突然見到如來一樣,或者換了貼近自己的比喻:就像千年色鬼見到美女一樣的興奮。 我忍不住的模仿小說中的修真人士突悟大道後的感嘆:原來如此!

下面的分享一下我的收穫,基本上是出入門徑的寫給初學者的,大俠千萬要止步,小弟皮薄!

稍微研究了一下C++彙編後的程式碼,一般呼叫C++的成員函式之前,都是使用ECX暫存器儲存物件的指標,好在C++成員函式的呼叫約定__thiscall的引數壓棧順序和堆疊平衡的維護都是和回撥函式的呼叫約定__stdcall一樣,所以只需要構造彙編將物件指標儲存在ECX暫存器後JMP到成員函式的執行地址就可以了。先寫個C++結構拼湊這兩條彙編碼:

#pragma pack( push, 1 )
struct MemFunToStdCallThunk
{
BYTE m_mov;
DWORD m_this;
BYTE m_jmp;
DWORD m_relproc;

BOOL Init( DWORD_PTR proc, void* pThis )
{
m_mov = 0xB9;
m_this = PtrToUlong(pThis);
m_jmp = 0xe9;
m_relproc = DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(MemFunToStdCallThunk)));
::FlushInstructionCache( ::GetCurrentProcess(), this, sizeof(MemFunToStdCallThunk) );
return TRUE;
}

void* GetCodeAddress()
{
return this;
}
};
#pragma pack( pop )

這個結構相當於兩條彙編語句:

mov ecx, pThis

jmp [偏移地址]

使用:

class CTestClass
{
private:
int m_nBase;
MemFunToStdCallThunk m_thunk;

void memFun( int m, int n )
{
int nSun = m_nBase + m + n;
CString str;
str.Format( _T("%d"), nSun );
AtlMessageBox( NULL, _U_STRINGorID( str ) );
}

public:
CTestClass()
{
m_nBase = 10;
}

void Test()
{
//UnionCastType:利用聯合將函式指標轉換成DWORD_PTR
m_thunk.Init( UnionCastType<DWORD_PTR>(&CTestClass::memFun), this );
StdCallFun fun = (StdCallFun)m_thunk.GetCodeAddress();
ATLASSERT( fun != NULL );
fun( 1, 3 );
}
};

MemFunToStdCallThunk的Init方法接受成員函式指標和物件指標後就構造成2條彙編碼,當呼叫fun(1,3)時,

首先將引數3和1壓入堆疊,之後跳轉到m_thunk處,也就是那構造的2條彙編碼處,將物件指標儲存到ECX暫存器,之後跳轉到指定的成員函式處執行。一切OK了。

UnionCastType方法的程式碼如下:

template< typename TDst, typename TSrc >
TDst UnionCastType( TSrc src )
{
union
{
TDst uDst;
TSrc uSrc;
}uMedia;
uMedia.uSrc = src;
return uMedia.uDst;

相關推薦

利用ThunkC++成員函式調函式

Windows API經常需要回調函式,而在C++開發中面向物件當行其道,若能讓C++類的成員函式成為回撥函式,簡直就是大善!但是C++成員函式都隱含了一個this指標用於指向當前的物件。要實現回撥確實不容易。 我大約一年前就接觸到Thunk技術,甚至也看過利用Thunk實現將成員函式變成回撥函式的例子。但

如何C++類的成員函式作為函式

Element Implementation Argument-passing order Right to left. Argument-passing convention By value, unless a pointer or reference type is passed. Stack-ma

C++中 執行緒函式為靜態函式 及 類成員函式作為函式

 執行緒函式為靜態函式:   執行緒控制函式和是不是靜態函式沒關係,靜態函式是在構造中分配的地址空間,只有在析構時才釋放也就是全域性的東西,不管執行緒是否執行,靜態函式的地址是不變的,並不在執行緒堆疊中static只是起了一個裝飾的作用,所以二者並沒有必然的關係   執行緒也是一種

c++類的成員函式函式為啥要申明為static的

  眾所周知,C++的類成員函式不能像普通函式那樣用於回撥,因為每個成員函式都需要有一個物件例項去呼叫它。         通常情況下,要實現成員函式作為回撥函式,一種常用的方法就是把該成員函式設計為靜態成員函式,但這樣做有一個缺點,就是會破壞類的結構性,因為靜態成員

C++的類中使用類成員函式作為函式

由於類有隱式的this指標,所以不能直接把類成員函式作為回撥函式使用。現用一例子來展示如何在類中使用類成員函式作為回撥函式。 此例子僅用於展示如何在類中使用類成員函式作為回撥函式 程式碼如下: #include "stdafx.h" #include

C++類成員函式作為函式說起

在網路訊息處理中經常要用到回撥機制。 例如處理非同步網路操作的前攝器設計模式(Proactor),(可以參考 《C++ 網路程式設計 卷2》中關於ACE Proactor模式實現 )。 非同步的 Web 伺服器將這樣來利用前攝器模式:首先讓 Web 伺服器向 OS 發出非同步

C++成員函式作為函式的問題

1. 程式設計分兩類 一,應用程式設計和系統程式設計 系統程式設計就是編寫底層的庫, 應用程式設計就是利用已經編寫好的庫的介面來編寫某種具有某些功能的程式,即應用 所謂的庫,就是為了給應用提

C語言學習及應用筆記之七:C語言中的函式及使用方式

  我們在使用C語言實現相對複雜的軟體開發時,經常會碰到使用回撥函式的問題。但是回撥函式的理解和使用卻不是一件簡單的事,在本篇我們根據我們個人的理解和應用經驗對回撥函式做簡要的分析。 1、什麼是回撥函式   既然談到了回撥函式,首先我們就要搞清楚什麼是回撥函式。在討論回撥函式之前,我們需要說明另一個概念,

【cocos2d-x從c++到js】函式1——按鍵

回撥函式是介面互動和接入各種第三方SDK的關鍵所在,因為回撥函式的C++程式碼是不能自動生成的,一切的一切,都需要手寫完成。 比較不錯的是,Cocos2d-x引擎對於回撥函式提供了完整的包裝機制。我們所需要做的就是了解這個機制,並使用他。學習引擎自己的程式碼

c語言中的函式

先來一段程式碼 #include<stdio.h> void show(void(*ptr)()){  (* ptr)();   } void show1(){ printf("hello world"); } void show2(){ printf("ni

C語言--結構體函式示例

#include <stdio.h> struct component_provider { int component_id; const char *componen

將類的成員函式作為函式(外一篇:友元函式

問題的提出  我們已知道類具有封裝和資訊隱藏的特性。只有類的成員函式才能訪問類的私有成員,程式中的其他函式是無法訪問私有成員的。非成員函式可以訪問類中的公有成員,但是如果將資料成員都定義為公有的,這又破壞了隱藏的特性。另外,應該看到在某些情況下,特別是在對某些成員函式多次呼叫時,由於引數傳遞,型別檢查和安全性

C 函式指標 函式

    http://www.cnblogs.com/chenyuming507950417/archive/2012/01/02/2310114.html  今天討論下C/C++中的回撥函式。     &

如何使 類的成員函式作為函式

如果試圖直接使用C++的成員函式作為回撥函式將發生錯誤,甚至編譯就不能通過。其錯誤是普通的C++成員函式都隱含了一個傳遞函式作為引數,亦即“this”指標,C++通過傳遞this指標給其成員函式從而實現程式函式可以訪問C++的資料成員。這也可以理解為什麼C++類的多個例項

C語言】 使用函式實現氣泡排序

實現功能:既能排序整型數,也可以排序字串 程式碼如下: #include <stdio.h> #include <string.h> int int_cmp(const v

如何實現類的成員函式作為函式

回撥函式(Callback   function)大量用於Windows的系統服務,通過它,程式設計師可以安裝裝置驅動程式和訊息過濾系統,以控制Windows的有效使用。許多程式設計師都發現,利用MFC或者其它的C++應用編寫回調函式是非常麻煩的,其根本原因是回撥函式是基於

利用觀察者模式來獲取執行緒中的資料或者調函式

首先//抽象主題角色,watched:被觀察 public interface Watched { public void addWatcher(Watcher watcher); public void removeWatcher(Watcher wat

c#呼叫c++dll介面及函式

在合作開發時,C#時常需要呼叫C++DLL,當傳遞引數時時常遇到問題,尤其是傳遞和返回字串是,現總結一下,分享給大家: VC++中主要字串型別為:LPSTR,LPCSTR, LPCTSTR, string, CString, LPCWSTR, LPWSTR等 但轉為C#

QT中類的成員函式作為函式

    這裡主要實現的功能:需要設計一個外掛,把外掛內的資料通過函式指標引數的方式傳遞到另外一個類中,顯示出來,使用回撥函式的方式 http://blog.csdn.net/ksn13/article/details/40538083,程式碼的邏輯和上述網站的第三種方法一樣

c++函式/ROS函式

以下均是個人在實際耕碼的過程中遇到的問題和整理的結果,可能會有不對的地方,望各位指正與交流 ------------------------------------------------------------------我會有喵的--------------------