熱度 1|
“你很想推開門去看看門后的世界,你始終沒有推開那扇門,你只是靜靜地等,等著有人從那扇門出來,把你輕輕抱起。只是你等了很久很久,來看你的人都走了,來勸你的人都走了,來愛你的人都走了,那扇門依然寂寞地對你輕輕微啟……”
這是trick大神為vb6提供了一個補丁,讓vb6可以直接調(diào)用cdecl的函數(shù)。這種簡單易用的方式,看起來不起眼,但無論如何它還是為vb6/vba打開了一扇門。因為太多的c函數(shù)庫默認是cdecl,c++庫的導(dǎo)出函數(shù)也是cdecl方式,很多知名的c/c++ 數(shù)學(xué)計算庫,圖形庫,音、視頻庫、pdf庫……,對于一些人來說,在特定的場合,如果能用上這些知名而且性能很好的庫,還是能帶來不少方便的地方。
例子1:
聲明windows自帶的msvcrt的c函數(shù)庫 和普通的winapi聲明差不多,就是多了一個Cdecl關(guān)鍵字
public Declare Function snwprintf1 CDecl Lib "msvcrt" _
Alias "_snwprintf" ( _
ByVal pszBuffer As Long, _
ByVal lCount As Long, _
ByVal pszFormat As Long, _
ByRef pArg1 As Any) As Long
public Declare Function snwprintf2 CDecl Lib "msvcrt" _
Alias "_snwprintf" ( _
ByVal pszBuffer As Long, _
ByVal lCount As Long, _
ByVal pszFormat As Long, _
ByRef pArg1 As Any, _
ByRef pArg2 As Any) As Long
public Declare Function wtoi64 CDecl Lib "msvcrt" _
Alias "_wtoi64" ( _
ByVal psz As Long) As Currency
調(diào)用msvrt的函數(shù):
sBuf = Space$(255)
Debug.Print Left$(sBuf, snwprintf1(StrPtr(sBuf), Len(sBuf), StrPtr("Test %ld"), ByVal 123&))
Debug.Print Left$(sBuf, snwprintf2(StrPtr(sBuf), Len(sBuf), StrPtr("Test %ld, %s"), ByVal 123&, ByVal StrPtr("Hello")))
Debug.Print wtoi64(StrPtr("123456789"))
例子2:
回調(diào)函數(shù)的調(diào)用。比如qsort 給vb的數(shù)組排序。這個我們在普通使用中,估計會用得很多。
Public Declare Sub qsort CDecl Lib "msvcrt" ( _
ByRef pFirst As Any, _
ByVal lNumber As Long, _
ByVal lSize As Long, _
ByVal pfnComparator As Long)
Sub Main()
Dim z() As Long
Dim i As Long
Dim s As String
ReDim z(500)
For i = 0 To UBound(z)
z(i) = Int(Rnd * 10000)
Next
qsort z(0), UBound(z) + 1, LenB(z(0)), AddressOf Comparator
For i = 0 To UBound(z)
Debug.Print z(i)
Next
End Sub
Private Function Comparator CDecl( _
ByRef a As Long, _
ByRef b As Long) As Long
Comparator = a - b
End Function
vb數(shù)組的排序非常的快。
通過以上例子,我們可以看出,在使用c/c++ 的函數(shù)時,指針會用得很頻繁,一般強烈建議把指針用longptr來替換long,這樣子代碼易讀性一目了然。強烈推薦 msvbvm60.tlb里的指針系列函數(shù),會帶來非常方便的指針操作。
例子3: cairo圖形庫的簡單調(diào)用。注:OLE_HANDLE在stdole中定義了,這是每個vb/vba必須要有的
Private Declare Function cairo_win32_surface_create CDecl Lib "cairo.dll" ( _
ByVal hDc As OLE_HANDLE) As OLE_HANDLE
Private Declare Function cairo_create CDecl Lib "cairo.dll" ( _
ByVal pSurface As OLE_HANDLE) As OLE_HANDLE
Private Declare Sub cairo_set_line_width CDecl Lib "cairo.dll" ( _
ByVal pCr As OLE_HANDLE, _
ByVal dValue As Double)
Private Declare Sub cairo_set_source_rgb CDecl Lib "cairo.dll" ( _
ByVal pCr As OLE_HANDLE, _
ByVal dR As Double, _
ByVal dG As Double, _
ByVal dB As Double)
Private Declare Sub cairo_rectangle CDecl Lib "cairo.dll" ( _
ByVal pCr As OLE_HANDLE, _
ByVal dX As Double, _
ByVal dY As Double, _
ByVal dW As Double, _
ByVal dH As Double)
Private Declare Sub cairo_stroke CDecl Lib "cairo.dll" ( _
ByVal pCr As OLE_HANDLE)
Private Declare Sub cairo_destroy CDecl Lib "cairo.dll" ( _
ByVal pCr As OLE_HANDLE)
Private Declare Sub cairo_surface_destroy CDecl Lib "cairo.dll" ( _
ByVal pSurface As OLE_HANDLE)
Private Sub Form_Load()
Dim pSurf As Long
Dim pCr As Long
pSurf = cairo_win32_surface_create(Me.hDc)
pCr = cairo_create(pSurf)
cairo_set_line_width pCr, 3
cairo_set_source_rgb pCr, 1, 0.5, 0.5
cairo_rectangle pCr, 10, 10, 300, 200
cairo_stroke pCr
cairo_destroy pCr
cairo_surface_destroy pSurf
End Sub
這個例子只是為了簡單說明可以輕易調(diào)用cdecl 的函數(shù)庫。Vbrichclient6已經(jīng)提供有完整的cario的包裝類。
例子4:簡單調(diào)用sqlite3.dll
Private Const SQLITE_OK As Long = 0
Private Const SQLITE_ROW As Long = 100
Private Declare Function sqlite3_open CDecl Lib "sqlite3" ( _
ByVal filename As String, _
ByRef ppDB As OLE_HANDLE) As Long
Private Declare Function sqlite3_prepare_v2 CDecl Lib "sqlite3" ( _
ByVal db As OLE_HANDLE, _
ByVal zSql As String, _
ByVal nByte As Long, _
ByRef ppStmt As OLE_HANDLE, _
ByRef pzTail As Any) As Long
Private Declare Function sqlite3_step CDecl Lib "sqlite3" ( _
ByVal pStmt As OLE_HANDLE) As Long
Private Declare Function sqlite3_finalize CDecl Lib "sqlite3" ( _
ByVal pStmt As OLE_HANDLE) As Long
Private Declare Function sqlite3_close CDecl Lib "sqlite3" ( _
ByVal ppDB As OLE_HANDLE) As Long
Private Declare Function sqlite3_column_text16 CDecl Lib "sqlite3" ( _
ByVal pStmt As OLE_HANDLE, _
ByVal iCol As Long) As Long
Private Declare Function SysAllocString Lib "oleaut32" ( _
ByRef pOlechar As Any) As Long
Private Declare Function PutMem4 Lib "msvbvm60.dll" ( _
ByRef pDst As Any, _
ByVal lVal As Long) As Long
Sub Main()
Dim pDB As OLE_HANDLE
Dim pStmt As OLE_HANDLE
Dim lResult As Long
Dim sBstrRes As String
lResult = sqlite3_open(":memory:", pDB)
If lResult <> SQLITE_OK Then
MsgBox "Cannot open database", vbCritical
GoTo CleanUp
End If
lResult = sqlite3_prepare_v2(pDB, "SELECT SQLITE_VERSION()", -1, pStmt, ByVal 0&)
If lResult <> SQLITE_OK Then
MsgBox "Cannot open database", vbCritical
GoTo CleanUp
End If
lResult = sqlite3_step(pStmt)
If lResult = SQLITE_ROW Then
PutMem4 ByVal VarPtr(sBstrRes), SysAllocString(ByVal sqlite3_column_text16(pStmt, 0))
Debug.Print sBstrRes
End If
CleanUp:
If pStmt Then sqlite3_finalize pStmt
If pDB Then sqlite3_close pDB
End Sub
這個例子也只是簡單調(diào)用sqlite3操作數(shù)據(jù)庫,com版的sqlite3包裝非常的多,很容易輕易獲得到。
1、vb/vba的string(bstr)與c的char的轉(zhuǎn)換問題
字符串在跨語言調(diào)用上,是相當(dāng)麻煩的事情。常常會把人搞得暈頭轉(zhuǎn)向。
不少的c庫函數(shù)的字符串是用char 數(shù)組,相當(dāng)于ansi 字符串。在vb/vba中常用byte和char對應(yīng),byte()數(shù)組來對應(yīng) c庫的字符串。如果在 聲明中 傳參是byref 方式,那傳 byte(0)就相當(dāng)于傳 c 函數(shù)的字符串指針。如果是byval方式,那就是varptr(byte(0)) 也是相當(dāng)于傳 c函數(shù)的字符串指針。
Vb的string和c的char字符串 轉(zhuǎn)換函數(shù):
Strconv() 這個會頻繁調(diào)用進行互轉(zhuǎn)。參數(shù) vbfromunicode 就是將vb的string轉(zhuǎn)成ansi字符串。參數(shù)vbunicode 就是將 ansi字符串轉(zhuǎn)成 vb的string.
SysAllocStringByteLen() 將 ansi字符串轉(zhuǎn)成 bstr
注:ansi字符串 英文是單字節(jié),中文是雙字節(jié)。
2、vb/vba的string(bstr)與c/c++的wchar_T的轉(zhuǎn)換問題
Vb/vba的string本身在內(nèi)部使用unicode,c/c++的wchar_t就是unicode。
所以如果傳給c/c++函數(shù)的wchar_t參數(shù),直接 strptr( bstr) 就可以了。
接收 c/c++函數(shù)的返回值,一般常用SysAllocString() 將unicode字符串轉(zhuǎn)成bstr
Sys字符串系列函數(shù)在oleaut32.dll中,這個系列函數(shù)在跨語言調(diào)用中,會經(jīng)常用到。
不少的winapi.tlb類型庫會有這個系列函數(shù),引用tlb后,可直接調(diào)用。
3、數(shù)字類型的缺失。
Vb/vba的數(shù)字類型沒有 ulong,uinteger(Ushort),longlong(64位vba有),Ulonglong。在某些場合下,會帶來很多的不方便。特別是ulong和longlong。雖然有不少方法勉強可以迂回補救,但它確實是不直觀。最糟糕的是,vb/vba的運算符無法重載,簡直是一場災(zāi)難。
4、variant數(shù)據(jù)類型轉(zhuǎn)換
要精細操作variant數(shù)據(jù)類型轉(zhuǎn)換。轉(zhuǎn)入variant,主要使用 oleaut32.dll的系列函數(shù),variant轉(zhuǎn)出,主要使用propsys.dll的系列函數(shù)。但一般我們不怎么需要使用到它。Vb/vba自身的轉(zhuǎn)換函數(shù)足夠用了。
5、vb的數(shù)組(safeArray)和c/c++的數(shù)組。
這種情況應(yīng)該是罕見,但如果遇到了。還是利用variant作為中間橋梁,用propsys.dll里的函數(shù)。
接收用initvariantFrom系列數(shù)組函數(shù) 轉(zhuǎn)成variant,再利用。
傳數(shù)組參數(shù),用variantTo系列數(shù)組函數(shù)。傳c的數(shù)組指針。
或許還有其它更好的方法。
總之,variant雖然缺點也不少,看著都難受。但還是可以作為跨語言傳遞的很好用的中間橋梁。
6、為vba制作提供vb6類的靜態(tài)方法。
我嘗試想為32位的VBE打上這個補丁,可惜并未成功。目前對vba來說,只能通過vb6的類的靜態(tài)方法來為
Vba作一種補充。Vb6創(chuàng)建類的靜態(tài)方法如下:
首先,添加一個類模塊(導(dǎo)入cls文件或者編寫創(chuàng)建一個新的類模塊)
然后,在右側(cè)的屬性窗口,按照如下的表格設(shè)置類的屬性
屬性名 |
屬性值 |
(名稱) |
你的類名稱 |
DataBindingBehavior |
0 - vbNone |
DataSourceBehavior |
0 - vbNone |
Instancing |
6 - GlobalMultiUse |
MTSTransactionMode |
0 - NotAnMTSObject |
Persistable |
0 - NotPersistable |
編譯生成 ****.dll
7、對我個人來說。cdecl能直接調(diào)用,毫無疑問又近一步拉近了vb6與Freebasic之間的距離。畢竟freebasic的runtime也是cdecl方式。
vb6的cdecl補丁下載地址:https://wwi.lanzoup.com/io1JL0o0odzc
|站長郵箱|小黑屋|手機版|Office中國/Access中國
( 粵ICP備10043721號-1 )
GMT+8, 2025-7-13 03:07 , Processed in 0.069553 second(s), 18 queries .
Powered by Discuz! X3.3
© 2001-2017 Comsenz Inc.