下面的例子完全用VB进行ASM编程的示例,本例获得CPU ID.工程文件分为一个form1.frm 和一个模块module1.bas----------------------form1.frm的源文件---------------------VERSION 5.00 Begin VB.Form Form1 Caption = "Form1" ClientHeight = 1965 ClientLeft = 60 ClientTop = 345 ClientWidth = 3105 LinkTopic = "Form1" ScaleHeight = 1965 ScaleWidth = 3105 StartUpPosition = 2 'Bildschirmmitte Begin VB.CommandButton Command1 Caption = "Get CPU Name" Height = 495 Left = 840 TabIndex = 0 Top = 315 Width = 1425 End Begin VB.Label Label2 Alignment = 2 'Zentriert AutoSize = -1 'True BeginProperty Font Name = "MS Sans Serif" Size = 9.75 Charset = 0 Weight = 400 Underline = 0 'False Italic = 0 'False Strikethrough = 0 'False EndProperty Height = 240 Left = 1515 TabIndex = 2 Top = 1065 Width = 60 End Begin VB.Label Label1 Alignment = 2 'Zentriert AutoSize = -1 'True BeginProperty Font Name = "Arial" Size = 12 Charset = 0 Weight = 700 Underline = 0 'False Italic = 0 'False Strikethrough = 0 'False EndProperty Height = 285 Left = 1515 TabIndex = 1 Top = 1350 Width = 75 End End Attribute VB_Name = "Form1" Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = False Attribute VB_PredeclaredId = True Attribute VB_Exposed = False Option ExplicitPrivate Sub Command1_MouseDown(Button As Integer, Shift As Integer, x As Single, Y As Single) Label1 = "" Label2 = ""End SubPrivate Sub Command1_Click()
Label1 = GetCpuName() & " CPU" Label2 = "You have a" & IIf(InStr("AEIOU", Left$(Label1, 1)), "n", "")End Sub ------------------------------end---------------------------------下面是modu1e.bas的源代码----------------------module1.bas的源文件-------------------------- Option Explicit ' 'This shows how to incorporate machine code into VB ''''''''''''''''''''''''''''''''''''''''''''''''''' 'The example fills the array with a few machine instructions and then copies 'them to a procedure address. The modified procedure is then called thru 'CallWindowProc. The result of this specific machine code is your CPU Vendor Name. ' '########################################################################## 'Apparently it gets a Stack Pointer Error, but I don't know why; if anybody 'can fix that please let me know... [email protected] 'The Error is not present in the native compiled version; so I think it got 'something to do with the P-Code Calling Convention (strange though)... '########################################################################## ' 'Sub Dummy serves to reserve some space to copy the machine instructions into. ' ' 'Tested on Intel and AMD CPU's (uncompiled and compiled) ' ' Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long) Private x As LongPublic Function GetCpuName() As String
Dim MachineCode(0 To 35) As Byte Dim VarAddr As Long Dim FunctAddr As Long Dim EAX As Long Dim CPUName(1 To 12) As Byte
MachineCode(31) = &HC9 'leave MachineCode(32) = &HC2 'ret 16 I tried everything from 0 to 24 MachineCode(33) = &H10 ' but all produce the stack error MachineCode(34) = &H0
'tell cpuid what we want EAX = 0
'get address of Machine Code VarAddr = VarPtr(MachineCode(0))
'get address of Sub Dummy FunctAddr = GetAddress(AddressOf Dummy)
'copy the Machine Code to where it can be called CopyMemory ByVal FunctAddr, ByVal VarAddr, 35 '35 bytes machine code
'call it On Error Resume Next 'apparently it gets a stack pointer error when in P-Code but i dont know why CallWindowProc FunctAddr, EAX, VarPtr(CPUName(1)), VarPtr(CPUName(9)), VarPtr(CPUName(5)) 'Debug.Print Err; Err.Description 'MsgBox Err & Err.Description On Error GoTo 0
End FunctionPrivate Function GetAddress(Address As Long) As Long GetAddress = AddressEnd FunctionPrivate Sub Dummy() 'the code below just reserves some space to copy the machine code into 'it is never executed x = 0 x = 1 x = 2 x = 3 x = 4 x = 5 x = 6 x = 7 x = 8 x = 9 x = 10 x = 0 x = 1 x = 2 x = 3 x = 4 x = 5 x = 6 x = 7 x = 8 x = 9 x = 10
End Sub ------------------------------end-------------------------------------- 摘自《vb情报站》 http://www.vbprobe.com/tips/showdoc.asp?detail_id=2064
除非你先生成C++代码的汇编代码,在VB里嵌入汇编代码来执行该断程序
Begin VB.Form Form1
Caption = "Form1"
ClientHeight = 1965
ClientLeft = 60
ClientTop = 345
ClientWidth = 3105
LinkTopic = "Form1"
ScaleHeight = 1965
ScaleWidth = 3105
StartUpPosition = 2 'Bildschirmmitte
Begin VB.CommandButton Command1
Caption = "Get CPU Name"
Height = 495
Left = 840
TabIndex = 0
Top = 315
Width = 1425
End
Begin VB.Label Label2
Alignment = 2 'Zentriert
AutoSize = -1 'True
BeginProperty Font
Name = "MS Sans Serif"
Size = 9.75
Charset = 0
Weight = 400
Underline = 0 'False
Italic = 0 'False
Strikethrough = 0 'False
EndProperty
Height = 240
Left = 1515
TabIndex = 2
Top = 1065
Width = 60
End
Begin VB.Label Label1
Alignment = 2 'Zentriert
AutoSize = -1 'True
BeginProperty Font
Name = "Arial"
Size = 12
Charset = 0
Weight = 700
Underline = 0 'False
Italic = 0 'False
Strikethrough = 0 'False
EndProperty
Height = 285
Left = 1515
TabIndex = 1
Top = 1350
Width = 75
End
End
Attribute VB_Name = "Form1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option ExplicitPrivate Sub Command1_MouseDown(Button As Integer, Shift As Integer, x As Single, Y As Single) Label1 = ""
Label2 = ""End SubPrivate Sub Command1_Click()
Label1 = GetCpuName() & " CPU"
Label2 = "You have a" & IIf(InStr("AEIOU", Left$(Label1, 1)), "n", "")End Sub
------------------------------end---------------------------------下面是modu1e.bas的源代码----------------------module1.bas的源文件--------------------------
Option Explicit
'
'This shows how to incorporate machine code into VB
'''''''''''''''''''''''''''''''''''''''''''''''''''
'The example fills the array with a few machine instructions and then copies
'them to a procedure address. The modified procedure is then called thru
'CallWindowProc. The result of this specific machine code is your CPU Vendor Name.
'
'##########################################################################
'Apparently it gets a Stack Pointer Error, but I don't know why; if anybody
'can fix that please let me know... [email protected]
'The Error is not present in the native compiled version; so I think it got
'something to do with the P-Code Calling Convention (strange though)...
'##########################################################################
'
'Sub Dummy serves to reserve some space to copy the machine instructions into.
'
'
'Tested on Intel and AMD CPU's (uncompiled and compiled)
'
'
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)
Private x As LongPublic Function GetCpuName() As String
Dim MachineCode(0 To 35) As Byte
Dim VarAddr As Long
Dim FunctAddr As Long
Dim EAX As Long
Dim CPUName(1 To 12) As Byte
'set up machine code
MachineCode(0) = &H55 'push ebp
MachineCode(1) = &H8B 'move ebp,esp
MachineCode(2) = &HEC
MachineCode(3) = &H57 'push edi
MachineCode(4) = &H52 'push edx
MachineCode(5) = &H51 'push ecx
MachineCode(6) = &H53 'push ebx
MachineCode(7) = &H8B 'move eax,dword ptr [ebp+8]
MachineCode(8) = &H45
MachineCode(9) = &H8
MachineCode(10) = &HF 'cpuid
MachineCode(11) = &HA2
MachineCode(12) = &H8B 'mov edi,dword ptr [ebp+12]
MachineCode(13) = &H7D
MachineCode(14) = &HC
MachineCode(15) = &H89 'move dword ptr [edi],ebx
MachineCode(16) = &H1F
MachineCode(17) = &H8B 'mov edi,dword ptr [ebp+16]
MachineCode(18) = &H7D
MachineCode(19) = &H10
MachineCode(20) = &H89 'move dword ptr [edi],ecx
MachineCode(21) = &HF
MachineCode(22) = &H8B 'mov edi,dword ptr [ebp+20]
MachineCode(23) = &H7D
MachineCode(24) = &H14
MachineCode(25) = &H89 'move dword ptr [edi],edx
MachineCode(26) = &H17
MachineCode(27) = &H58 'pop ebx MachineCode(28) = &H59 'pop ecx MachineCode(29) = &H5A 'pop edx MachineCode(30) = &H55 'pop edi
MachineCode(31) = &HC9 'leave MachineCode(32) = &HC2 'ret 16 I tried everything from 0 to 24
MachineCode(33) = &H10 ' but all produce the stack error
MachineCode(34) = &H0
'tell cpuid what we want
EAX = 0
'get address of Machine Code
VarAddr = VarPtr(MachineCode(0))
'get address of Sub Dummy
FunctAddr = GetAddress(AddressOf Dummy)
'copy the Machine Code to where it can be called
CopyMemory ByVal FunctAddr, ByVal VarAddr, 35 '35 bytes machine code
'call it
On Error Resume Next 'apparently it gets a stack pointer error when in P-Code but i dont know why
CallWindowProc FunctAddr, EAX, VarPtr(CPUName(1)), VarPtr(CPUName(9)), VarPtr(CPUName(5))
'Debug.Print Err; Err.Description
'MsgBox Err & Err.Description
On Error GoTo 0
GetCpuName = StrConv(CPUName(), vbUnicode) 'UnicodeName
End FunctionPrivate Function GetAddress(Address As Long) As Long GetAddress = AddressEnd FunctionPrivate Sub Dummy() 'the code below just reserves some space to copy the machine code into
'it is never executed x = 0
x = 1
x = 2
x = 3
x = 4
x = 5
x = 6
x = 7
x = 8
x = 9
x = 10
x = 0
x = 1
x = 2
x = 3
x = 4
x = 5
x = 6
x = 7
x = 8
x = 9
x = 10
End Sub
------------------------------end--------------------------------------
摘自《vb情报站》 http://www.vbprobe.com/tips/showdoc.asp?detail_id=2064
先说说VC++的编程。首先在VC++中生成Win32 DLL工程。在这个工程中添加几个函数供VB用户调用。一个DLL中的函数要想被VB调用,必须满足两个条件:一是调用方式为stdcall,另一个是必须是export的。要做到第一条,只须在函数声明前加上__stdcall关键字。如:
short __stdcall sample(short nLen, short *buffer)
要做到第二条,需要在*.def文件中加上如下的几行:
EXPORTS
sample @1
这里的sample是你要在VB中调用的函数名,@1表示该函数在DLL中的编号,每个函数都不一样。注意这里的函数名是区分大小写的。至于你说的需要传递大量数据,可以这样做,在VB中用一个数组存放数据,然后将该数组的大小和地址传给VC(至于如何在VB中编程我会在下面介绍)。就象上面的例子,nLen是数组大小,buffer是数组地址,有了这两条,你可以象使用VC的数组一样进行处理了。至于输出图形,可以生成WMF或BMP格式,让VB调用。不过,我认为也可以直接输出到视窗,只要VB将窗口的句柄hWnd和hDC以及视窗的绘图位置(VB和VC采用的坐标系必须一致才行)传给VC就行了。而VB的AutoRedraw属性必须为False,在Paint事件中调用VC的绘图程序。
再谈谈VB的编程。VB调用DLL的方法和调用Windows API的方法是一样的,一般在VB的书中有介绍。对于上面一个例子,先要声明VC函数:
Declare Function sample Lib "mydll.dll" (ByVal nLen As Integer, buffer As Integer) As Integer
这里mydll.dll是你的dll的名字。你可能已经注意到了两个参数的声明有所不同,第一个参数加上了ByVal。规则是这样的:如果在VC中某个参数声明为指针和数组,就不加ByVal,否则都要加上ByVal。在VB中调用这个函数采用这样的语法:
sample 10, a(0)
这里的a()数组是用来存放数据的,10为数组长度,这里的第二个参数不能是a(),而必须是要传递的数据中的第一个。这是VB编程的关键。
下面在说几个可能遇到的问题。一个问题是VB可能报告找不到dll,你可以把dll放到system目录下,并确保VB的Declare语句正确。另一个问题是VB报告找不到需要的函数,这通常是因为在VC中*.def文件没设置。第三种情况是VB告诉不能进行转换,这可能是在VC中没有加上__stdcall关键字,也可能是VB和VC的参数类型不一致,注意在VC中int是4个字节(相当于VB的Long),而VB的Integer只有2个字节。必须保证VB和VC的参数个数相同,所占字节数也一致。最后一个要注意的问题是VC中绝对不能出现数组越界的情况,否则会导致VB程序崩溃。
总的来说,你和你的伙伴需要一些时间来进行协调和摸索,但这种方法绝对可行,也不难掌握。