1. 程式人生 > 實用技巧 >c出口之間VB6和VB.NET

c出口之間VB6和VB.NET

內容 介紹GetHashCode在VB6 如何在。net中做一個類似c的匯出 讓我們做一些更復雜的事情:鉤子 .NET來了,讓我們回到VB6專案 結論引用歷史 介紹 本文的目的是在不涉及COM的情況下解釋。net和VB6之間的互操作。為了實現這樣的結果,我們將從VB中匯出一些類似c語言的函式。NET DLL(等一下,您將看到如何操作)。本教程的第一部分將介紹一種技術使用一個非常簡單的示例,然後它將解釋瞭如何設定一個全域性鉤子使用VB(6和. net),正常情況下不可能沒有涉及C或c++,但出口從。net C-way我們會這樣做。 GetHashCode方法在VB6 每個優秀的。net程式設計師都知道String類的GetHashCode方法:它“返回這個字串的雜湊程式碼”。現在假設,出於某種原因,你需要使用演算法[String]。GetHashCode方法在VB6。讓我們考慮一種聰明的方法來做這件事。VB6程式碼(VB6Hasher專案)非常簡單。您只有一個帶有兩個文字框和一個按鈕的表單:當您單擊按鈕時,第一個文字框的內容將被雜湊,結果將顯示在第二個文字框中。 隱藏,複製Code

Private Declare Function JustHash Lib "HashExporter.Net.dll" _
    (ByVal str As String) As Long

Private Sub btnHash_Click()
    txtHash.Text = JustHash(txtInput.Text)
End Sub

如果你對VB6語法有點熟悉,你已經認識宣告語句:它指的是以下簡單的函式在一個外部DLL在VB製作。淨(HashExporter。Net專案): 隱藏,複製Code

Public Function JustHash(ByVal str As String
) As Integer Return str.GetHashCode() End Function

顯然,這種語法不足以實現類似於c的匯出(也就是說,通過Declare語句從VB6中訪問),實際上,您不能在VB中實現這樣的匯出。NET,既不是c#,也不是我知道的任何。NET語言,除了…除了ILAsm (IL組合語言)。不要問我為什麼使用c#或VB。NET沒有實現這個特性… 如何在。net中做一個類似c的匯出 構建完hash匯出器後。Net專案,開啟Visual Studio命令提示符(開始選單,程式,Microsoft .NET Framework SDK, SDK命令提示符),到達包含HashExporter.Net.dll的資料夾,型別: 隱藏,複製Code

ildasm /out:HashExporter.Net.il HashExporter.Net.dll

這個命令從編譯後的DLL中提取ILAsm程式碼:通過一個目錄,您將能夠看到HashExporter.Net。和HashExporter.Net。res已經生成。現在,通過一個簡單的文字編輯器,讓我們對hashexporters . net .il做一些更改。首先要做的是找到以“”開頭的那一行。corflags"並將其(通常指定值0x00000001)替換為"。corflags 0x00000002”:這意味著可執行檔案將只在Win32上工作。然後,在這一行後面加上以下內容: 隱藏,複製Code

.vtfixup [1] int32 fromunmanaged at VT_01
.data VT_01 = int32(0)

這在我們的例子中是可行的,因為我們只需要匯出一個函式,但顯然你可以匯出任意多的函式: 隱藏,複製Code

.vtfixup [3] int32 fromunmanaged at VT_01
.data VT_01 = int32[3] 

然後你必須找到類的宣告包含要匯出方法(類似私人汽車ansi密封HashExporter.Net.mdlHashExporter . class),內部類塊尋找.method公共靜態int32 JustHash (string str) cil管理和右花括號後,新增以下程式碼: 隱藏,複製Code

.vtentry 1:1
.export [1] as JustHash

或更多: 隱藏,複製Code

.vtentry VTable:VTEntryIndex
.export [ExportOrdinal] as ExportedFunctionName

VTable表明(VT_XX)數量的VTable(陣列儲存出口,可以有多個,例如VT_01, VT_02,但通常一個就足夠了),VTEntryIndex VTable的元素的索引,ExportOrdinal序數的出口和ExportedFunctionName代表函式的名字將被匯出。此時,我們可以在命令提示符下重新編寫程式碼: 隱藏,複製Code

ilasm "HashExporter.Net.il" /DLL /OUT:"HashExporter.Net.dll" 
/RESOURCE:"HashExporter.Net.res"

如果您以正確的方式完成了所有的通道,那麼使用依賴Walker (VS工具)開啟新的hashexporters . net .dll,您將在右側窗格中看到匯出函式的名稱!這是實現類似c的匯出的漫長道路:自動化這個過程是可能的。我開發了一個工具,可以像在C/ c++中那樣管理這些匯出:使用.def檔案。在我的例子中,一個後構建工具讀取了一個.defnet檔案並用於編輯ILAsm。無論如何,這是針對。net 1.1的,要在2.0中工作,需要進行一些編輯。也許在將來,我會出版它。與此同時,你可以使用這個[^],但我認為用ILAsm手工工作是有趣的。更多細節,請參見非託管程式碼可以包裝託管方法[^],在Microsoft . net彙編程式[^]和標準ECMA-335 -公共語言基礎設施(CLI)[^],分割槽III: CIL指令集。現在你可以嘗試執行vb6haser .exe看看會發生什麼。 讓我們做一些更復雜的事情:鉤子 Windows鉤子。鉤子是一種子類化,只是它不與單個視窗關聯,而是與執行緒甚至整個系統關聯。它是一種Windows訊息過濾器,允許您在par出現時覆蓋或新增功能收到提示資訊。MSDN[^]鉤子定義: 鉤子是系統訊息處理機制中的一個點,應用程式可以在其中安裝子例程來監視系統中的訊息流量,並在某些型別的訊息到達目標視窗過程之前處理它們。 要設定一個鉤子,你需要從user32.dll呼叫SetWindowsHookEx。下面是VB6的宣告: 隱藏,複製Code

Private Declare Function SetWindowsHookEx Lib "user32" _
    Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal _
    lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long

如果你曾經嘗試過在VB6中使用SetWindowsHookEx,很可能你知道這種語言有什麼限制,事實上MSDN文件說: 如果dwThreadId引數為0或者指定了一個由不同程序建立的執行緒的識別符號,那麼lpfn引數必須指向動態連結庫(DLL)中的一個鉤子子程。 SetWindowsHookEx參考[^] 這是因為您想要監視的執行緒(或者如果鉤子是全域性的,dwThreadId = 0的執行緒)需要將指定的DLL載入到自己程序的地址空間中。當您建立一個鉤子時,您必須傳遞給SetWindowsHookEx一個指向一個函式的指標(lpfn引數)。你可能會說:嗯,有什麼問題嗎?VB6有運營商的地址!是的,確實是這樣,而且使用AddressOf也可以工作,但前提是您要嘗試掛鉤由呼叫程序建立的執行緒!正如MSDN所說,接收指標的引數必須指向一個外部DLL的函式,但是VB6(通常)不能以類似c的方式公開函式!因此,不可能建立全域性鉤子或與其他程序關聯的鉤子。 net來了 HookCExport。Net解決方案包含一個稱為HookWndProc的函式,它的定義完全類似於CallWndProc[^]。讓我們重複本文第一部分中完成的過程,以c方式公開這個鉤子過程。 構建HookCExport。Net解決方案使用ildasm在HookCExport.Net. dll編輯HookCExport.Net。如果在HookCExport.Net.DLL中HookWndProc是可見的,檢查依賴Walker 重要提示:要避免系統崩潰,還有一件基本的事情要做。一個全域性鉤子每秒會呼叫回撥函式很多次,因此,這個函式必須非常快,否則你會拖慢整個系統,直到崩潰。如你所知,. net程式在第一次執行時由JIT編譯器編譯,所以我們的DLL在第一次呼叫HookWndProc時得到。這是非常危險的,因為在編譯庫時,同一個函式被多次呼叫,這總是導致系統阻塞。解決方案從SDK命令提示符手動編譯DLL: 隱藏,複製Code

ngen install "HashExporter.Net.dll"

讓我們回到VB6專案 這是VB6HookListener專案的核心,你可以在mdlHooking中找到它: 隱藏,複製Code

'Creates the Hook
Public Sub Hook(hThread As Long)
    Dim hProc As Long
    'Load the external DLL
    hModule = Chk(LoadLibrary("HookCExport.Net.DLL"))
    'Gets the address of the callback function in the external DLL
    hProc = Chk(GetProcAddress(hModule, "HookWndProc"))
    'Sets the Hook for the message sent using SendMessage
    hHook = Chk(SetWindowsHookEx(WH_CALLWNDPROC, hProc, hModule, hThread))
    [...]
End Sub

注意:Chk是一個函式,它檢查API呼叫是否返回0,如果是,則丟擲錯誤,否則返回接收到的值。我們說傳遞給SetWindowsHookEx的函式指標必須在外部DLL中,所以我們使用了LoadLibrary和GetProcAddress,它們分別在記憶體中載入指定的DLL,並獲取指定函式(HookWndProc)的函式指標(地址)。你可能會問為什麼我們沒有像在VB6Hasher例子中那樣使用宣告語句;這有兩個原因:首先,不能在通過Declare語句宣告的函式上使用地址,其次,不能從SetWindowsHookEx獲得所需的模組控制代碼。最後,鉤子被設定好了。解釋關於鉤子的其餘程式碼超出了本文的範圍。 結論 在這篇文章中,我們看到了如何利用VB6中的。net功能來實現一些通常不可能實現的功能,而無需使用笨重的COM包裝器,而只需從VB中暴露出來。NET一些類似c的方法。當您需要使用。net的底層特性時,這項技術非常有用(就像設定一個全域性鉤子一樣)。你再也不需要找爸爸幫忙了! 參考文獻 MSDN,對於各種Win32 API函式[^]非託管程式碼可以封裝託管方法[^]- Emilio Reale如何在Visual Basic .NET中設定一個鉤子[^]- Microsoft知識庫(讀“.NET Framework中不支援全域性鉤子”一節,它是假的!我剛剛在本文中演示了它!)內部Microsoft .NET彙編程式[^]- Serge Lidin, Microsoft Press Standard ECMA-335 - Common Language Infrastructure (CLI)[^],分割槽III: CIL指令集- ECMA-international.org Spy: Monitoring Messages with Spy [^] - vc++ 6.0 SDK示例 歷史 2007年6月26日:初任 本文轉載於:http://www.diyabc.com/frontweb/news2388.html