|
說明
基於最佳化的考量,通常程式一些常用的部分會透過組合語言來做最佳化的動作,但這對於VB的使用者而言卻是一項難題,VB並不支援這樣的功能,我們得繞一段遠路,透過如何取得lst檔相同的方法,我們在多做一個鏈節器,Link.EXE做法如下
- 先安裝C2.zip中的C2.EXE 安裝方法請參考如何取得VB編譯後的lst檔
- 將E:\Program Files\Microsoft Visual Studio\VB98\Link.EXE改名為
E:\Program Files\Microsoft Visual Studio\VB98\iLink.EXE
- 下載Link.zip
- 解壓縮後將Link.exe放到E:\Program Files\Microsoft Visual Studio\VB98目錄下
準備完成後 透過以下範例 將一步步教你如何鏈結 請先下載以下範例LinkWith_C_asm.zip 內部含有一個VB,C以及ASM的程式 VB的程式如下
'以下程式在Form中
Option Explicit Private Declare Function GetTickCount Lib "kernel32" () As Long Private Sub Command1_Click() Dim i As Long, l As Long
Dim bgt As Long, ent As Long bgt = GetTickCount()
For i = 1 To 1000000 l = GetSum() Next
ent = GetTickCount()
MsgBox "費時:" & ent - bgt
End Sub
Private Sub Command2_Click() Dim l As Long l = GetSum() MsgBox l End Sub
'以下程式在模組中 Option Explicit
Public Function GetSum() As Long
Dim i As Long, l As Long
For i = 1 To 100 l = l + i Next
GetSum = l End Function
我們動手寫個GetSum這個函數 要做的是1累加到100 組語如下
.386P .model FLAT PUBLIC GetSum .code
GetSum PROC NEAR xor eax, eax mov ecx, 1
loop1: add eax, ecx inc ecx cmp ecx, 100 jle loop1 ret 0 GetSum ENDP
END
另外我們也用C寫一個來比較
和ASM鏈結的方法如下
- 先取得VB編譯後的lst檔 如果不會請參考如何取得VB編譯後的lst檔
當出現Link畫面時 請先不要Link 由於GetSum是在Module1.bas中,他的輸出會在Module1.lst 用記事本打開Module1.lst 內容如下
TITLE C:\gs\Module1.bas .386P include listing.inc if @Version gt 510 .model FLAT else _TEXT SEGMENT PARA USE32 PUBLIC 'CODE' _TEXT ENDS _DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
_DATA ENDS CONST SEGMENT DWORD USE32 PUBLIC 'CONST' CONST ENDS _BSS SEGMENT DWORD USE32 PUBLIC 'BSS' _BSS ENDS _TLS SEGMENT DWORD USE32 PUBLIC 'TLS' _TLS ENDS text$1 SEGMENT PARA USE32 PUBLIC '' text$1 ENDS
; COMDAT ?GetSum@Module1@@AAGXXZ text$1 SEGMENT PARA USE32 PUBLIC '' text$1 ENDS FLAT GROUP _DATA, CONST, _BSS ASSUME CS: FLAT, DS: FLAT, SS: FLAT endif
PUBLIC ?GetSum@Module1@@AAGXXZ ; Module1::GetSum EXTRN __imp____vbaErrorOverflow:NEAR ; COMDAT ?GetSum@Module1@@AAGXXZ text$1 SEGMENT
?GetSum@Module1@@AAGXXZ PROC NEAR ; Module1::GetSum, COMDAT
; 4 : Public Function GetSum() As Long
xor eax, eax
; 5 : Dim i As Long, l As Long
; 6 : ; 7 : For i = 1 To 100
mov ecx, 1 $L27:
; 8 : l = l + i
add eax, ecx jo SHORT $L19 add ecx, 1
jo SHORT $L19 cmp ecx, 100 ; 00000064H jle SHORT $L27
; 9 : Next ; 10 : ; 11 : GetSum = l ; 12 : End Function
ret 0
$L19: call DWORD PTR __imp____vbaErrorOverflow ?GetSum@Module1@@AAGXXZ ENDP ; Module1::GetSum text$1 ENDS END
- 注意用紅色標明的部分 GetSum備編譯後 函數名稱已經改為?GetSum@Module1@@AAGXXZ 我們需要修改一下原來組語中的函數名稱 修改如下
.386P .model FLAT PUBLIC ?GetSum@Module1@@AAGXXZ .code
?GetSum@Module1@@AAGXXZ PROC NEAR xor eax, eax mov ecx, 1 loop1: add eax, ecx inc ecx cmp ecx, 100 jle loop1 ret 0 ?GetSum@Module1@@AAGXXZ ENDP END
這個程式我放在Module1.asc
- 編譯Module1.asc
建議使用MASM編譯 比較不會有格式問題 請輸入 ml /c /Cp /coff /Zm Module1.asc 然後將編譯出的Module1.OBJ覆蓋原先由VB編譯出的Module1.OBJ
- 然後按下Link視窗的開始Link按鈕 即可完成編譯
和C鏈結的方法如下
- 先將C轉為ASM 由於C編譯器和VB函數命名方式不同 不能直接編成OBJ在鏈結 只要把C輸出成LST即可 以下以BCC為例子
輸入 BCC32 -5 -S -Ox Module1.cpp 他會將lst輸出到Module1.asm 之後鏈結方法就和之前的Asm鏈結法一樣
至於使用這個方法 效能能提升多少呢 以下是在Pentium 4-M 1.8GHz,512MB的機器下的測試結果
效能確實是有提升
程式
Option Explicit
Private Declare Function OpenProcess Lib "kernel32" _ (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, _ ByVal dwProcessId As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" _ (ByVal hObject As Long) As Long Private Declare Function GetExitCodeProcess Lib "kernel32" _
(ByVal hProcess As Long, lpExitCode As Long) As Long
Const PROCESS_QUERY_INFORMATION = &H400 Const SYNCHRONIZE = &H100000 Const STILL_ALIVE = &H103
Dim ExitCode As Long Dim hProcess As Long
Private Sub Command1_Click() Dim pid As Long
Command1.Enabled = False Me.Hide DoEvents
pid = Shell("iLink " & Command, vbHide)
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION + SYNCHRONIZE,
0, pid)
Do Call GetExitCodeProcess(hProcess, ExitCode) DoEvents Loop While ExitCode = STILL_ALIVE
Call CloseHandle(hProcess)
Unload Me
End Sub
Private Sub Form_Load() List1.Clear
List1.AddItem "這個程式可以暫緩Link.exe執行" List1.AddItem "再按下""開始Link""前 你可以先編譯" List1.AddItem "你的程式(用C或是Assembly)所做出的lst檔"
List1.AddItem "(記得函數名稱命名必須和和替換掉程式的命名相同)" List1.AddItem "編譯只要用任何32bit的Assembly編譯器應該都可以" List1.AddItem " TASM編譯方式是這樣 tasm32 /ml xxx.lst "
List1.AddItem " MASM編譯方式是這樣 ml / c / Cp / coff /Zm xxx.lst" List1.AddItem "編譯完成後 按下""開始Link""即可"
End Sub
範例下載
文件出處
整理時間
|