VB.NETでマシン語を使う
2005年12月14日
現在のSFCは、Win32APIの殆どをVB.NET内で宣言する形になっている。これは、DynaWrapから脱却するための一つの方法であったのだが、逆にWin32API以外の関数をDLLから呼び出して実行することは出来ない(DynaWrapなら可能)。
そこで、やはり最終的にはDynaCall様の物をVB.NET内に構築して実行する形にしたいと思っている。これには、DynaCallの様なインラインアセンブラが必要である。
前に一度述べたように、こちらのページではインラインマシン語の使い方を紹介している。ただし、ver 2.0の.NET frameworkが必要で、これはまだβバージョンである。正式なver 2.0の登場が待てないので、別の形でインラインマシン語を利用する方法を考えてみた。
前の記事では、Win32APIのEnumWindowsを利用すると、メモリ上に構築されたコードに制御が移ることを確認した。従って、マシン語のコードをメモリ上に構築し、同じ様に呼び出せばよいということである。かくしてできたテストプログラムが以下の通り
作成したマシン語コードの中で別の関数(dcSub())を呼び出すことを試してみた。将来的には、複雑な操作はそういった関数の中で行い、マシン語でしかできない操作のみをこのコード内で行うように設定できるはずである。実行結果は、以下の通り
うまく行っているようである。
そこで、やはり最終的にはDynaCall様の物をVB.NET内に構築して実行する形にしたいと思っている。これには、DynaCallの様なインラインアセンブラが必要である。
前に一度述べたように、こちらのページではインラインマシン語の使い方を紹介している。ただし、ver 2.0の.NET frameworkが必要で、これはまだβバージョンである。正式なver 2.0の登場が待てないので、別の形でインラインマシン語を利用する方法を考えてみた。
前の記事では、Win32APIのEnumWindowsを利用すると、メモリ上に構築されたコードに制御が移ることを確認した。従って、マシン語のコードをメモリ上に構築し、同じ様に呼び出せばよいということである。かくしてできたテストプログラムが以下の通り
Imports System
Imports System.Runtime.InteropServices
Imports Microsoft.VisualBasic
Module Main
Delegate Sub d_DcSub()
Delegate Function d_EnumWindowsProc(hwnd As Integer, lParam As Integer) As Boolean
Declare Function EnumWindows Lib "user32" (x As d_EnumWindowsProc, y As d_DcSub) As Integer
Declare Function EnumWindows Lib "user32" (x As Integer, y As Integer) As Integer
Sub Main(ByVal CmdArgs() As String)
'Get the pointer of DcSub
Dim dGate1 as d_DcSub=AddressOf DcSub
EnumWindows(AddressOf EnumWindowsProc,dGate1)
Dim p_DcSub as integer=fPointer
Console.WriteLine("p_DcSub="+hex(p_DcSub))
'Get address of DynaCall
Dim dcAddress as integer=DynaCall
Console.WriteLine("DynaCall address: "+hex(dcAddress))
'Call the DynaCall through EnumWindws
EnumWindows(dcAddress,p_DcSub)
End Sub
private fPointer as integer=0
Function EnumWindowsProc(hwnd As Integer, lParam As Integer) As Boolean
fPointer=lParam
Return false
End Function
Private Sub DcSub()
Console.WriteLine("DcSub OK")
End Sub
private gch as GCHandle
private AsmCode() as byte
private AsmCodeSize as integer=0
Private Function DynaCall() as integer
AddCode(&h58) 'pop eax //contains return address
AddCode(&h58) 'pop eax //contains hWnd
AddCode(&h58) 'pop eax //contains lParam (address of DcSub)
AddCode(&h83,&hec,&h0c) 'sub esp,0000000c //return to original stack position
AddCode(&hff,&hd0) 'call eax //call DcSub()
AddCode(&h33,&hc0) 'xor eax,eax //eax=0
AddCode(&hc2,&h08,&h00) 'ret 0008 //remove 8 bytes from stack and return eax
gch = GCHandle.Alloc(AsmCode, GCHandleType.Pinned)
return gch.AddrOfPinnedObject().ToInt32()
End Function
Private Sub AddCode(b1 as byte)
Redim Preserve AsmCode(AsmCodeSize)
AsmCode(AsmCodeSize)=b1
AsmCodeSize=AsmCodeSize+1
End Sub
Private Sub AddCode(b1 as byte,b2 as byte)
AddCode(b1)
AddCode(b2)
End Sub
Private Sub AddCode(b1 as byte,b2 as byte,b3 as byte)
AddCode(b1)
AddCode(b2)
AddCode(b3)
End Sub
Private Sub AddCode(b1 as byte,b2 as byte,b3 as byte,b4 as byte)
AddCode(b1)
AddCode(b2)
AddCode(b3)
AddCode(b4)
End Sub
End Module作成したマシン語コードの中で別の関数(dcSub())を呼び出すことを試してみた。将来的には、複雑な操作はそういった関数の中で行い、マシン語でしかできない操作のみをこのコード内で行うように設定できるはずである。実行結果は、以下の通り
p_DcSub=15B26E DynaCall address: 49A6470 DcSub OK
うまく行っているようである。