設(shè)為首頁收藏本站Access中國

Office中國論壇/Access中國論壇

 找回密碼
 注冊

QQ登錄

只需一步,快速開始

tag 標(biāo)簽: Freebasic教程

相關(guān)帖子

版塊 作者 回復(fù)/查看 最后發(fā)表

沒有相關(guān)內(nèi)容

相關(guān)日志

分享 freebasic菜鳥初學(xué)Freebasic基礎(chǔ)教程十二:使用afx庫的數(shù)組、字典和com庫
ganlinlao 2017-5-15 21:00
一、使用safeArray數(shù)組 我很驚訝jose為什么要提供vb數(shù)組safeArray,而且他對提供vb數(shù)組走了極端,分別提供了極其精簡只限wstring類型的CwstrArray,和全功能的variant類型的CvariantArray。但想一想,也許這樣子也有一定的好處,在多線程的模式下,還有比safeArray數(shù)組更好的數(shù)組嗎?畢竟這是線程安全的,而且又易于使用。 提供CwstrArray字符串?dāng)?shù)組,是因?yàn)閟pit函數(shù),必須有一個(gè)字符串?dāng)?shù)組來接收spit分割后字符串。不過在某些情況下,我們也是可以直接使用CwstrArray數(shù)組。如果要有VB交互的話,可以使用CvariantArray數(shù)組,但如果純粹在FB下使用,沒必要使用Variant和variant數(shù)組,那是在找虐。 cWstrArray數(shù)組和vb中使用數(shù)組還是有細(xì)微的差別。 (1)、vb中dim arr(4) as string,其中4表示數(shù)組的ubound是4,這樣的數(shù)組其實(shí)是5個(gè)元素。 但CwstrArray(4)表示這個(gè)數(shù)組是4個(gè)元素,它的Ubound是3 (2) vb可以直接使用 arr(0)="這是一個(gè)測試",但cwstrArray.item(0)="這是一個(gè)測試",這個(gè)item無法省略 (3)在單線程模式下,不必?fù)?dān)心數(shù)組是不是會lock,但在多線程模式下,你要注意數(shù)組加解鎖問題,也就是accessData和UaccessData這兩個(gè)方法最好是明確使用。 (4)字符串聯(lián)接用+號,盡量不使用,如果號,你得注意是**CwstrArray.item(0),2個(gè)*號,這個(gè)同樣適用于Cwstr類中,使用聯(lián)接號必須使用 **cwstr,使用+號沒有任何問題,原因是因?yàn)榉柕孟葟?qiáng)制轉(zhuǎn)換數(shù)據(jù)類型,先cast(),再進(jìn)行拼接。 (5)vb中獲得數(shù)組元素的數(shù)量,是ubound(Arr)-Lbound(Arr),但CwstrArray使用是CwstrArray.count直接返回元素?cái)?shù)量 (6)cWstrArray數(shù)組中可以復(fù)制數(shù)組,可以嵌套數(shù)組,可以使用variant中的數(shù)組vt_Array(僅限于字符串類型數(shù)組) #include once "afx/cwstrArray.inc" #include once "afx/cwindow.inc" dim myArr as cwstrArray=cwstrArray(4) myArr.item(0)="1" myArr.item(1)="2" myArr.item(2)="3" myArr.item(3)="4" myarr.sort(false) 'false是降序,默認(rèn)是true是升序 'afxmsg "one = " myarr.item(0) "two= " myArr.item(1) "Three= " myArr.item(2) "four=" myArr.item(3) afxmsg "one = " + myarr.item(0) + "two= " + myArr.item(1) + "Three= " + myArr.item(2) + "four=" + myArr.item(3) 二、使用字典dictionary afx庫中也分別提供了wstring類型的dictionary和variant類型的dictionary。用法和VB中使用dictionary幾乎一樣。 cwstrDic類比vb的dictionary多了一個(gè)count方法,返回一個(gè)字典元素的數(shù)量。 說實(shí)話,我對afx庫只提供dictionary,其實(shí)是非常失望的。一般最好使用mdtypes這個(gè)泛型的集合類庫。
個(gè)人分類: FreeBasic|4356 次閱讀|0 個(gè)評論
分享 freebasic菜鳥初學(xué)Freebasic基礎(chǔ)教程十一:使用afx庫有關(guān)字符串的函數(shù)和類
ganlinlao 2017-5-12 21:00
freebasic菜鳥初學(xué)Freebasic基礎(chǔ)教程十一:使用afx庫有關(guān)字符串的函數(shù)和類
'冬瓜湯編寫整理 字符串處理,對于大部分語言來說,都是一件麻煩的事,ansi,unicode,utf-8……,我前面已經(jīng)說過了,F(xiàn)B對于unicode支持不是特別的好,也就是wstring只能是指針或固定長度,而不是動態(tài)不定長的字符串,這非常麻煩。雖然wstr()可以快速將string字符串轉(zhuǎn)變成wstring字符串,但其實(shí)很多場合下的使用,還是非常不方便。afx的CWstr類就是專門處理unicode字符串,其實(shí)用它可以處理ansi,unicode,utf-8,Bstr(vbstring),非常方便,不管是網(wǎng)絡(luò)上常用的utf-8,還是com的BSTR,都挺方便的。 一、len(),和sizeof()對字符串的影響 在FB中,len()用來判斷一個(gè)字符串的大小, 對于string和zstring來說,len返回的是字節(jié)大小。對于unicode來說,len()返回的是字符數(shù)。uniocde字符串的字節(jié)大小,是len(unicode)*2 。 而sizeof()是用來判斷一個(gè)變量,對象內(nèi)存占用多少。 這是一個(gè)測試?yán)樱? #include once "afx/cwindow.inc" Dim As String anStr,anStrEN dim anStrU as string dim unStr as wstring*20 '這里直接用固定長度20個(gè)unicode字符 anStrEn = "FB is new basic" unstr = "FB是語言" anstr = "FB是語言" anStrU = wstr(anstr) afxmsg "ansi的Len大。" Len( anstr) chr(13) _ "ansi的sizeof大小:" sizeof(anstr) chr(13) _ "ansi純英文的Len大。" Len( anstrEn) chr(13) _ "ansi純英文的sizeof大小:" sizeof(anstrEn) chr(13) _ "unicode的Len大。" len(unStr) chr(13) _ "uniocde的sizeof大。" sizeof(unStr) chr(13) _ "an轉(zhuǎn)Un的len大小:" len(anStrU) chr(13) _ "an轉(zhuǎn)Un的sizeof大。" sizeof(anStrU) chr(13) _ "wstr()返回值的Len大小:" len(wstr(anstr)) chr(13) _ "wstr()返回值的sizeof大。" sizeof(wstr(anStr)) 在這里我們會發(fā)現(xiàn)sizeof對于string不起作用,總是返回大小12,這我無法解釋,只能把它理解成因?yàn)閟tring是一個(gè)動態(tài)不定長的字符串?dāng)?shù)組,sizeof返回的實(shí)際上是一個(gè)數(shù)組結(jié)構(gòu)的字節(jié)大小。如果用64位編譯,你會發(fā)現(xiàn)sizeof總是返回24。 (2)wstr(string)賦值給一個(gè)string類型的變量,不會發(fā)現(xiàn)任何變化。 (3) sizeof(wstr())總是返回0,估計(jì)是一個(gè)Null值。 所以在實(shí)際使用中如果要預(yù)先分配內(nèi)存的話,千萬要小心不要誤以為sizeof(string)能返回總字節(jié)大小。 '冬瓜湯整理編寫 二、使用afx的字符串函數(shù) #include once "afx/CWSTR.inc" #include once "afx/afxStr.inc" using afx ' 所有的afx庫,都處在同一個(gè)命名空間afx里,F(xiàn)B的命名空間規(guī)則和c#/vb.net是一樣的。 '我不喜歡using這個(gè)關(guān)鍵詞,我更喜歡Imports,但沒辦法 import在FB很早以前就是一個(gè)關(guān)鍵字了。 '判斷是否是數(shù)字 Dim inNumeric As boolean=afxIsNumeric("-1395.43") '同left的用法 Dim As cwstr strLeft=afxstrClipLeft("這是一個(gè)Freebasic測試",9) '同mid的用法 Dim As cwstr strMid=afxstrClipMid("這是一個(gè)Freebasic測試",4,5) '同Right用法 Dim As cwstr strRight=afxstrClipRight("這是一個(gè)Freebasic測試",2) '左右嵌入空格或指定的符號 Dim As cwstr strCset=afxstrCset("單身狗",11,"*") '返回 ****單身狗**** '刪除指定數(shù)量的子字符串 Dim As cwstr strDelete=afxstrDelete("這是一個(gè)Freebasic測試",4,9) '從主字符串提取匹配指定字符的字符串,但不包括指定字符本身 Dim As cwstr strExtract=afxstrExtract(1,"誰是單身狗,不是單身貓","狗") ' Dim As cwstr strExtractAny=afxstrExtractAny(1,"誰是單身狗,不是單身貓","貓狗") '從指定位置插入子字符串 Dim As cwstr strInsert=afxstrInsert("01032547891","—",3) '從第三個(gè)位置之后插入子字符串 '同join用法 Dim cwsa As cwstrArray=cwstrArray(4,1) '建一個(gè)4行1列的數(shù)組 cwsa.Item(1) = "One" cwsa.Item(2) = "Two" cwsa.Item(3) = "Three" cwsa.item(4)="Four" DIM strJoinAS CWSTR = AfxStrJoin(cwsa, ",") '用法和vb的join一樣 '左邊加入指定數(shù)量的空格或指定符號 DIM strLset AS CWSTR = AfxStrLSet("FreeBasic", 20, "#") '解析帶分隔符的字符串,分隔符可以多種混用 DIM cws AS CWSTR = AfxStrParse("one,two,three", 2) ' Returns "two" DIM cws AS CWSTR = AfxStrParseAny("1;2,3", 2, ",;") ' Returns "2" '解析帶分隔符的字符串,并返回?cái)?shù)量 DIM nCount AS LONG = AfxStrParseCount("one,two,three", ",") ' Returns 3 DIM nCount AS LONG = AfxStrParseCountAny("1;2,3", ",;") ' Returns 3 '返回子字符串第一次出現(xiàn)在主字符串位置之前的那部分字符串,可以指定搜索位置從哪里開始,默認(rèn)從1 DIM cws AS CWSTR = AfxStrRemain("Brevity is the soul of wit", "is ") ' Returns "the soul of wit" DIM cws AS CWSTR = AfxStrRemainAny("I think, therefore I am", ",") ' Returns "therefore I am" '從主字符串移除子符串 DIM cws AS CWSTR = AfxStrRemove(" ", "[]") ' Returns "Hello" DIM cws AS CWSTR = AfxStrRemoveAny("abacadabra", "bac") ' Returns "dr" '替換,同Replace() DIM cws AS CWSTR = AfxStrReplace("Hello World", "World", "Earth") ' Returns "Hello Earth" DIM cws AS CWSTR = AfxStrReplaceAny("abacadabra", "bac", "*") ' Returns "*****d**r* '去掉主字符串不匹配指定的子符串的那部分,只返回匹配的子符串或子符串組 DIM cws AS CWSTR = AfxStrRetain("abacadabra","b") ' Returns "bb" DIM cws AS CWSTR = AfxStrRetainAny("1234567890ak;lk;l1234567890", ";/p") ' Returns ";;" '反轉(zhuǎn)字符串 DIM cws AS CWSTR = AfxStrReverse("garden") ' Returns "nedrag" '右邊添加指定數(shù)量的空格或指定符號 DIM cws AS CWSTR = AfxStrRSet("FreeBasic", 20, "*") '將帶各種不規(guī)范分隔符的字符串,整理成一種規(guī)范的字符串 DIM cws AS CWSTR = AfxStrShrink(",,, one , two three, four,", " ,")' Returns "one two three four" '同split DIM cws AS CWSTR = "- This, a sample string." DIM cwsa AS CWstrArray = AfxStrSplit(cws, " ,.-") FOR i AS LONG = cwsa.LBound TO cwsa.UBound PRINT cwsa.Item(i) NEXT '統(tǒng)計(jì)子符串在主子符串出現(xiàn)的次數(shù) DIM nCount AS LONG = AfxStrTally("abacadabra", "ab") ' Returns 2 DIM nCount AS LONG = AfxStrTallyAny("abacadabra", "bac") ' Returns 8 '在開頭和結(jié)尾,刪除成對的字符符號 AfxStrUnWrap("Paul", "", "") results Paul AfxStrUnWrap("'Paul'", "'") results Paul '確定主字符串是否包含指定子符串中任一一個(gè)字符 DIM nCount AS LONG = AfxStrVerify(5, "123.65,22.5", "0123456789") ' Returns 7 '在字符串開頭和結(jié)尾添加 成對的字符 AfxStrWrap('保羅',"", "")結(jié)果保羅 ……還有一些函數(shù),具體看幫助文檔 ########################################################### 三、使用BSTR 為了方便使用,我將Cbstr類和Cwstr類合并在同一個(gè)文件cwstr.inc中 #include once "afx/Cwstr.inc" using afx Dim myBstr as CBSTR myBstr="這是一個(gè)測試" 用 Cbstr類,主要是為了能夠自動釋放vbstring指針。忘記釋放bstr指針,是非常容易犯的錯(cuò)。所以一遇到任何傳進(jìn)來的bstr字符串 就立即用cbstr進(jìn)行接收。
個(gè)人分類: FreeBasic|4301 次閱讀|0 個(gè)評論
分享 Freebasic菜鳥初學(xué)Freebasic基礎(chǔ)教程九:了解com數(shù)據(jù)類型
ganlinlao 2017-5-11 10:34
FB在windows上使用,有兩種東西是無法回避的,一種是api,一種是com,這是幾乎所有在windows上使用的語言都必須用到的。 這是引用自csdn上的博客內(nèi)容: 了解一下com數(shù)據(jù)類型,有助于在FB中使用com。 BSTR、 BSTR到底是什么。 BSTR是COM中的數(shù)據(jù)類型,在COM編程時(shí),接口中定義的字符串類型都是BSTR類型, 而使用BSTR類型是極其容易出錯(cuò)的,同時(shí),一不小心就有可能造成內(nèi)存泄露。所以有如下建議: 在對接口進(jìn)行實(shí)現(xiàn)時(shí),從接口參數(shù)中傳遞過來的BSTR類型的變量,一定要在第一時(shí)刻將BSTR類型轉(zhuǎn)變成_bstr_t類型的變量,就是因?yàn)?BSTR有隱藏的危險(xiǎn) ,同時(shí)當(dāng)使用BSTR出現(xiàn)bug時(shí),而這種bug而不一定好找; 在對接口進(jìn)行實(shí)現(xiàn)時(shí),接口中的BSTR字符串參數(shù)是out時(shí),在接口實(shí)現(xiàn)的內(nèi)部不要定義BSTR類型變量,而是定義_bstr_t類型的變量,進(jìn)行操作,操作完成以后,然后在轉(zhuǎn)為BSTR類型的變量傳出去。 既然是這樣,就有人要問了,那么BSTR存在的必要是什么? 這個(gè)是由COM決定的,由于COM是跨系統(tǒng)及不同開發(fā)語言間實(shí)現(xiàn)互操作的技術(shù),常規(guī)以NULL結(jié)尾的簡單字符串在COM組件間傳遞不太方便。 所以,BSTR就這么出現(xiàn)了。 BSTR作為指針類型,標(biāo)準(zhǔn)的BSTR是一個(gè)有長度前綴和NULL結(jié)束符的OLECHAR數(shù)組。BSTR的前4個(gè)字節(jié)是一個(gè) 表示字符串長度的前綴。BSTR長度域的值是字符串的字節(jié)數(shù),但不包括字符串結(jié)束符。BSTR實(shí)際上包含的是Unicode串, 所以字符數(shù)是字節(jié)數(shù)的一半。 所以,在能不使用BSTR的情況下,就盡量不要使用BSTR類型,而是使用對應(yīng)的_bstr_t類型。為了處理BSTR,Microsoft提供了以下API供使用: BSTR SysAllocString ( const OLECHAR * psz ); INT SysReAllocString ( BSTR * pbstr , const OLECHAR * psz ); BSTR SysAllocStringLen ( const OLECHAR * strIn , UINTui ); INT SysReAllocStringLen ( BSTR * pbstr , constOLECHAR * psz , unsignedintlen ); void SysFreeString ( BSTR bstrString ); UINT SysStringLen ( BSTR ); UINT SysStringByteLen ( BSTR bstr ); BSTR SysAllocStringByteLen ( LPCSTRpsz , UINTlen ); 現(xiàn)在對以上的 API 逐一的進(jìn)行講解和應(yīng)用,大家可以結(jié)合著 MSDN ,看這篇博文,至少 MSDN 講的比我這里更詳細(xì)。 SysAllocString 分配內(nèi)存,并創(chuàng)建 BSTR 字符串; SysReAllocString 重新分配內(nèi)存,并將第二個(gè)參數(shù)指定的 OLECHAR 同時(shí)放入新開辟的的內(nèi)存中; SysAllocStringLen 分配內(nèi)存,將第一個(gè)參數(shù)指定的字符串的前 ui (第二個(gè)參數(shù)指定的字符個(gè)數(shù))個(gè)數(shù)放入開辟的內(nèi)存中; SysReAllocStringLen ,經(jīng)過上面兩個(gè) API 的講解,這個(gè) API 的就不需要更多的講解了; SysFreeString 釋放由以上的 API 函數(shù)開辟的內(nèi)存; SysStringLen 表示的是 BSTR 的字符個(gè)數(shù); SysStringByteLen 獲得 BSTR 字符串表示的字節(jié)數(shù),也就是 BSTR 的前 4 個(gè)字節(jié)表示的內(nèi)容; SysAllocStringByteLen 使用的是 ANSI string 進(jìn)行創(chuàng)建 BSTR 對象,盡量少用該 API 。 VARIANT VARIANT結(jié)構(gòu)體主要是使用在COM(組件對象模型)中用于傳遞參數(shù)使用, 它的存在主要是為了保持一個(gè)在COM參數(shù)傳遞方法的統(tǒng)一性,它幾乎包含了所有普通常用類型的數(shù)據(jù)類型的傳遞, 如整型,浮點(diǎn)型,布爾型等等,以及相應(yīng)類型的指針類型,如整型指針。 它的使用也比較方便。先來看看這個(gè)結(jié)構(gòu)體它的結(jié)構(gòu): typedef struct tagVARIANT { union { struct __tagVARIANT { VARTYPE vt; WORD wReserved1; WORD wReserved2; WORD wReserved3; union { LONGLONG llVal; LONG lVal; BYTE bVal; SHORT iVal; FLOAT fltVal; DOUBLE dblVal; VARIANT_BOOL boolVal; _VARIANT_BOOL bool; SCODE scode; CY cyVal; DATE date; BSTR bstrVal; IUnknown *punkVal; IDispatch *pdispVal; SAFEARRAY *parray; BYTE *pbVal; SHORT *piVal; LONG *plVal; LONGLONG *pllVal; FLOAT *pfltVal; DOUBLE *pdblVal; VARIANT_BOOL *pboolVal; _VARIANT_BOOL *pbool; SCODE *pscode; CY *pcyVal; DATE *pdate; BSTR *pbstrVal; IUnknown **ppunkVal; IDispatch **ppdispVal; SAFEARRAY **pparray; VARIANT *pvarVal; PVOID byref; CHAR cVal; USHORT uiVal; ULONG ulVal; ULONGLONG ullVal; INT intVal; UINT uintVal; DECIMAL *pdecVal; CHAR *pcVal; USHORT *puiVal; ULONG *pulVal; ULONGLONG *pullVal; INT *pintVal; UINT *puintVal; struct __tagBRECORD { PVOID pvRecord; IRecordInfo *pRecInfo; } __VARIANT_NAME_4; } __VARIANT_NAME_3; } __VARIANT_NAME_2; DECIMAL decVal; } __VARIANT_NAME_1; } VARIANT, *LPVARIANT, VARIANTARG, *LPVARIANTARG; 這個(gè)結(jié)構(gòu)體呢,有5個(gè)成員,分別是 VARTYPE vt ,WORD wReserved1,WORD wReserved2,WORD wReserved3,和最后一個(gè)共用體。 其中vt用以指明最后一個(gè)共用體中哪一個(gè)成員有效,wReserved1,wReserved2,wReserved3,這三個(gè)我們使用的時(shí)候不用管,系統(tǒng)保留, 最后一個(gè)共用體根據(jù)vt的提示,對相應(yīng)的成員進(jìn)行值的存儲。我們從兩個(gè)不同的角度來理解,首先是使用VARIANT來存儲參數(shù), 首先是聲明一個(gè)這個(gè)結(jié)構(gòu)體的對象,然后對對象的vt進(jìn)行賦值,它可接受的值是一個(gè)枚舉值,也就說只能在枚舉這個(gè)范圍內(nèi)取值, 比如我要用VARIANT傳遞一個(gè)整數(shù),現(xiàn)在我對vt的賦值為VT_INT,這樣就說明了我要使用這個(gè)結(jié)構(gòu)體中共用體的整型變量, 接著對INT變量進(jìn)行賦值,賦我們要傳遞的值。這樣就完成VARIANT的傳遞。現(xiàn)在我們從另外一個(gè)角度來理解VARIANT, 剛才是我們對VARIANT對象進(jìn)行賦值傳遞,現(xiàn)在我們是這個(gè)VARIANT對象的接收者,我們從參數(shù)中獲得這個(gè)對象之后, 我們首先檢查這個(gè)結(jié)構(gòu)體的vt成員,看它哪個(gè)類型的變量有效,比如就這個(gè)例子而言,檢查到vt的值是VT_INT, 因此,我直接去獲取這個(gè)結(jié)構(gòu)體中VT_INT所對應(yīng)的變量,獲取它的值。這樣,我們從傳遞到使用兩個(gè)角度來理解了VARIANT結(jié)構(gòu)體, 概括起來說,就是vt指明了我要傳遞的變量的類型,結(jié)構(gòu)體中共用體的成員用來存儲vt指明的類型的值。 下面來看看具體VARIANT結(jié)構(gòu)體是如何使用賦值的,首先是第一種方法: 首先我們聲明一個(gè)VARIANT結(jié)構(gòu)體的對象vr1,然后使用VariantInit函數(shù)對其進(jìn)行初始化,它的作用就是對vt賦VT_EMPTY, 對別的變量值附空,否則就是一個(gè)隨機(jī)值,這個(gè)過程和我們聲明一個(gè)int變量一樣,如果聲明的時(shí)候不初始化,就是一個(gè)隨機(jī)值。 編程過程中,不管是指針還是什么變量,都應(yīng)該在聲明之后對其進(jìn)行初始化。接著就是我賦VT_INT給vt, 這里的V_VT就是代表要對vr1結(jié)構(gòu)體中的vt成員進(jìn)行幅值,接著對vr1中的INT成員賦值,這里的V_INT就是表示要對INT賦值, 因此這里有一個(gè)規(guī)律,就是V_,它的后面加成員類型就可以對相應(yīng)的成員賦值,而這里的成員類型有一個(gè)對照表,在文章的最后給出, 比如,我要對BSTR成員賦值,我就用V_BSTR。這時(shí)候,就可以使用vr1了,使用完成之后,我們應(yīng)該調(diào)用VariantClear函數(shù), 這個(gè)函數(shù)的作用就是將vt賦值為VT_EMPTY,以及釋放使用這個(gè)結(jié)構(gòu)體中的內(nèi)存中的內(nèi)容,如果是com對象,該函數(shù)是不會進(jìn)行對象的release操作的, 不管怎么樣,我們都應(yīng)該在使用完了VARIANT結(jié)構(gòu)體之后,調(diào)用這個(gè)函數(shù)。 下面是第二種方法,原理和過程和地中方法類似,有一點(diǎn)微小的區(qū)別, 就是VARIANT結(jié)構(gòu)體的賦值上面來說,有點(diǎn)不同,如下: 接下來是字符串的操作,BSTR,我們不能直接將字符串傳遞一個(gè)VARIANT結(jié)構(gòu)體對象,而是要用到函數(shù)SysAllocString, 它的返回值就是一個(gè)BSTR,由它分配一個(gè)字符串,供VARIANT,對于為什么要這么做,可以自己查看MSDN COM的Automation那部分: 完成之后,我們還應(yīng)該調(diào)用SysFreeString來釋放由SysAllocString分配的內(nèi)存。 另外,我們可以在類型與變量的對照表中發(fā)現(xiàn),同一類型,對應(yīng)了兩種不同的變量,如,INT對應(yīng)了變量有intVal和pintVal,其實(shí)這很簡單,后者是指針性,如果要使用,說明我們賦值的對象是一個(gè)指針,如下: 最后給出類型與變量的對照表,如果是使用地中方法用V_加類型,就直接使用下表中VT_后的名稱就可以了: Member name Description VT_EMPTY Indicates that a value was not specified. VT_NULL Indicates a null value, similar to a null value in SQL. VT_I2 Indicates ashortinteger. VT_I4 Indicates alonginteger. VT_R4 Indicates afloatvalue. VT_R8 Indicates adoublevalue. VT_CY Indicates a currency value. VT_DATE Indicates a DATE value. VT_BSTR Indicates a BSTR string. VT_DISPATCH Indicates anIDispatchpointer. VT_ERROR Indicates an SCODE. VT_BOOL Indicates a Boolean value. VT_VARIANT Indicates a VARIANTfarpointer. VT_UNKNOWN Indicates anIUnknownpointer. VT_DECIMAL Indicates adecimalvalue. VT_I1 Indicates acharvalue. VT_UI1 Indicates abyte. VT_UI2 Indicates anunsignedshort. VT_UI4 Indicates anunsignedlong. VT_I8 Indicates a 64-bit integer. VT_UI8 Indicates an 64-bit unsigned integer. VT_INT Indicates an integer value. VT_UINT Indicates anunsignedinteger value. VT_VOID Indicates a C stylevoid. VT_HRESULT Indicates an HRESULT. VT_PTR Indicates a pointer type. VT_SAFEARRAY Indicates a SAFEARRAY. Not valid in a VARIANT. VT_CARRAY Indicates a C style array. VT_USERDEFINED Indicates a user defined type. VT_LPSTR Indicates a null-terminated string. VT_LPWSTR Indicates a wide string terminated bynullNothingnullptra null reference (Nothing in Visual Basic). VT_RECORD Indicates a user defined type. VT_FILETIME Indicates a FILETIME value. VT_BLOB Indicates length prefixed bytes. VT_STREAM Indicates that the name of a stream follows. VT_STORAGE Indicates that the name of a storage follows. VT_STREAMED_OBJECT Indicates that a stream contains an object. VT_STORED_OBJECT Indicates that a storage contains an object. VT_BLOB_OBJECT Indicates that a blob contains an object. VT_CF Indicates the clipboard format. VT_CLSID Indicates a class ID. VT_VECTOR Indicates a simple, counted array. VT_ARRAY Indicates aSAFEARRAYpointer. VT_BYREF Indicates that a value is a reference. VARIANT使用起來是很簡單的,但是有些問題,我們還必須要去注意: 建立VARIANT變量時(shí),必須使用VariantInit進(jìn)行初始化 ; 對于VT_UI1, VT_I2, VT_I4, VT_R4, VT_R8, VT_BOOL, VT_ERROR, VT_CY, VT_DECIMAL, 和VT_DATE這些類型, 數(shù)據(jù)的值是直接儲存在VARIANT結(jié)構(gòu)中的,當(dāng)VARIANT的類型發(fā)生變化時(shí),指向這些數(shù)據(jù)的指針會變得無效。 例如: VARIANT varParam ; :: VariantInit ( varParam ); short iVal = 20 ; varParam . vt = VT_I2 ; varParam . iVal = iVal ; short * pVal = varParam . iVal ; varParam . vt = VT_I4 ; varParam . lVal = 200 ; 此時(shí),*pVal指向的值與你期望的可能是不一樣的。 對于VT_BYREF | any type數(shù)據(jù)類型,而VARIANT只是擁有這些數(shù)據(jù)指向內(nèi)存的指針,而內(nèi)存的釋放需要由函數(shù)的調(diào)用者負(fù)責(zé)。 例如: VARIANT varParam ; :: VariantInit ( varParam ); int * p = new int ; * p = 10 ; varParam . vt = VT_BYREF | VT_I4 ; varParam . plVal = ( long *) p ; delete p ; // If you donnot delete the memory, this may cause memory leak 對于VT_BSTR類型,在VARIANT中的字符串必須要用SysAllocString進(jìn)行分配內(nèi)存,當(dāng)釋放時(shí),或者VARIANT的類型發(fā)生改變時(shí), 都需要調(diào)用SysFreeString進(jìn)行內(nèi)存釋放,否則就會發(fā)生內(nèi)存泄露; 對于VT_ARRAY | any type類型,這個(gè)規(guī)則和VT_BSTR是類似的,在VARIANT中的數(shù)組必須使用SafeArrayCreate進(jìn)行開辟內(nèi)存空間, 然后必須使用SafeArrayDestroy進(jìn)行內(nèi)存空間的釋放; 對于VT_DISPATCH和VT_UNKNOWN,我們考慮的更多的就是引用計(jì)數(shù)器的增加與減少了, 是的,在進(jìn)行賦值時(shí)需要進(jìn)行引用計(jì)數(shù)的增加,釋放時(shí),則需要對應(yīng)的減少。 SAFEARRAY的使用 SAFEARRAY的主要目的是用于automation中的數(shù)組型參數(shù)的傳遞,我們都知道,在網(wǎng)絡(luò)環(huán)境中,數(shù)組是不能直接傳遞的, 所以我們必須將數(shù)組封裝成SAFEARRAY類型,這樣才能進(jìn)行傳遞,在COM編程時(shí),SAFEARRAY類型是可以存放在VARIANT類型中, 指定vt為VT_ARRAY|*或者VT_BYREF|VT_ARRAY。對于SAFEARRAY,說白了,就是普通的數(shù)組,添加了一些額外的說明, 當(dāng)我第一次遇到這個(gè)類型時(shí),也是有點(diǎn)恐懼的,后來,用慣了,也就無所謂了。SAFEARRAY單獨(dú)用的時(shí)候很少,就像我前面說的, 一般都是搭配著VARIANT一起使用,指定vt類型以后,parray成員就是指向SAFEARRAY的指針。SAFEARRAY中元素的類型可以 是VARIANT能封裝的任何類型,包括VARIANT類型本身。 訪問SAFEARRAY 訪問SAFEARRAY的方法大體上有兩種: 使用SafeArrayAccessData方法; 使用SafeArrayGetElement和SafeArrayPutElement方法。 關(guān)于這兩種方法,在上面的例子中都有涉及。 HRESULT 函數(shù)返回值 每個(gè)人在做程序設(shè)計(jì)的時(shí)候,都有他們各自的哲學(xué)思想。拿函數(shù)返回值來說,就有好多種形式。 函數(shù) 返回值 返回值信息 double sin(double) 浮點(diǎn)數(shù)值 計(jì)算正玄值 BOOL DeleteFile(LPCTSTR) 布爾值 文件刪除是否成功。如失敗,需要GetLastError()才能取得失敗原因 void * malloc(size_t) 內(nèi)存指針 內(nèi)存申請,如果失敗,返回空指針 NULL LONG RegDeleteKey(HKEY,LPCTSTR) 整數(shù) 刪除注冊表項(xiàng)。0表示成功,非0失敗,同時(shí)這個(gè)值就反映了失敗的原因 UINT DragQueryFile(HDROP,UINT,LPTSTR,UINT) 整數(shù) 取得拖放文件信息。以不同的參數(shù)調(diào)用,則返回不同的含義: 一會兒表示文件個(gè)數(shù),一會兒表示文件名長度,一會兒表示字符長度 ...... ...... ... ...... ...... 如此紛繁復(fù)雜的返回值,如此含義多變的返回值,使得大家在學(xué)習(xí)和使用的過程中,增加了額外的困難。好了,COM 的設(shè)計(jì)規(guī)范終于對他們進(jìn)行了統(tǒng)一。組件API及接口指針中,除了IUnknown::AddRef()和IUnknown::Release()兩個(gè)函數(shù)外,其它所有的函數(shù),都以 HRESULT 作為返回值。大家想象一個(gè)組件的接口函數(shù)比如叫Add(),完成2個(gè)整數(shù)的加法運(yùn)算,在 C語言 中,我們可以如下定義: view plain copy print ? long Add( long n1, long n2) { return n1+n2; } 還記得剛才我們說的原則嗎? COM 組件是運(yùn)行在分布式環(huán)境中的 。也就是說,這個(gè)函數(shù)可能運(yùn)行在“地球另一邊”的計(jì)算機(jī)上,既然運(yùn)行在那么遙遠(yuǎn)的地方,就有可能出現(xiàn)服務(wù)器關(guān)機(jī)、網(wǎng)絡(luò)掉線、運(yùn)行超時(shí)、對方不在服務(wù)區(qū)......等異常。于是,這個(gè)加法函數(shù),除了需要返回運(yùn)算結(jié)果以外,還應(yīng)該返回一個(gè)值------函數(shù)是否被正常執(zhí)行了。 view plain copy print ? HRESULT Add( long n1, long n2, long *pSum) { 3*pSum=n1+n2; return S_OK; } 如果函數(shù)正常執(zhí)行,則返回 S_OK,同時(shí)真正的函數(shù)運(yùn)行結(jié)果則通過參數(shù)指針返回。如果遇到了異常情況,則COM系統(tǒng)經(jīng)過判斷,會返回相應(yīng)的錯(cuò)誤值。常見的返回值有: HRESULT 值 含義 S_OK 0x00000000 成功 S_FALSE 0x00000001 函數(shù)成功執(zhí)行完成,但返回時(shí)出現(xiàn)錯(cuò)誤 E_INVALIDARG 0x80070057 參數(shù)有錯(cuò)誤 E_OUTOFMEMORY 0x8007000E 內(nèi)存申請錯(cuò)誤 E_UNEXPECTED 0x8000FFFF 未知的異常 E_NOTIMPL 0x80004001 未實(shí)現(xiàn)功能 E_FAIL 0x80004005 沒有詳細(xì)說明的錯(cuò)誤。一般需要取得 Rich Error 錯(cuò)誤信息(注1) E_POINTER 0x80004003 無效的指針 E_HANDLE 0x80070006 無效的句柄 E_ABORT 0x80004004 終止操作 E_ACCESSDENIED 0x80070005 訪問被拒絕 E_NOINTERFACE 0x80004002 不支持接口 圖一、HRESULT 的結(jié)構(gòu) HRESULT 其實(shí)是一個(gè)雙字節(jié)的值,其最高位(bit)如果是0表示成功,1表示錯(cuò)誤。具體參見 MSDN 之"Structure of COM Error Codes"說明。我們在程序中如果需要判斷返回值,則可以使用比較運(yùn)算符號;switch開關(guān)語句;也可以使用VC提供的宏: view plain copy print ? HRESULT hr=調(diào)用組件函數(shù); if (SUCCEEDED(hr)){...} //如果成功 ...... if (FAILED(hr)){...} //如果失敗 ......
個(gè)人分類: FreeBasic|4226 次閱讀|0 個(gè)評論
分享 Freebasic菜鳥初學(xué)Freebasic基礎(chǔ)教程五:宏參數(shù)的字符串化#和宏參數(shù)的連接##符號
ganlinlao 2017-5-8 18:44
關(guān)于#和## 在C語言的宏中,#的功能是將其后面的宏參數(shù)進(jìn)行字符串化操作(Stringfication),簡單說就是在對它所引用的宏變量 通過替換后在其左右各加上一個(gè)雙引號。比如下面代碼中的宏: #define WARN_IF(EXP) do{ if (EXP) fprintf(stderr, "Warning: " #EXP "/n"); } while(0) 那么實(shí)際使用中會出現(xiàn)下面所示的替換過程: WARN_IF (divider == 0); 被替換為 do { if (divider == 0) fprintf(stderr, "Warning" "divider == 0" "/n"); } while(0); 這樣每次divider(除數(shù))為0的時(shí)候便會在標(biāo)準(zhǔn)錯(cuò)誤流上輸出一個(gè)提示信息。 而##被稱為連接符(concatenator),用來將兩個(gè)Token連接為一個(gè)Token。注意這里連接的對象是Token就行,而不一定 是宏的變量。比如你要做一個(gè)菜單項(xiàng)命令名和函數(shù)指針組成的結(jié)構(gòu)體的數(shù)組,并且希望在函數(shù)名和菜單項(xiàng)命令名之間有直觀的、名字上的關(guān)系。那么下面的代碼就非常實(shí)用: struct command { char * name; void (*function) (void); }; #define COMMAND(NAME) { NAME, NAME ## _command } // 然后你就用一些預(yù)先定義好的命令來方便的初始化一個(gè)command結(jié)構(gòu)的數(shù)組了: struct command commands[] = { COMMAND(quit), COMMAND(help), ... } COMMAND宏在這里充當(dāng)一個(gè)代碼生成器的作用,這樣可以在一定程度上減少代碼密度,間接地也可以減少不留心所造成的錯(cuò)誤。我們還可以n個(gè)##符號連接 n+1個(gè)Token,這個(gè)特性也是#符號所不具備的。比如: #define LINK_MULTIPLE(a,b,c,d) a##_##b##_##c##_##d typedef struct _record_type LINK_MULTIPLE(name,company,position,salary); // 這里這個(gè)語句將展開為: // typedef struct _record_type name_company_position_salary; 關(guān)于...的使用 ...在C宏中稱為Variadic Macro,也就是變參宏。比如: #define myprintf(templt,...) fprintf(stderr,templt,__VA_ARGS__) // 或者 #define myprintf(templt,args...) fprintf(stderr,templt,args) 第一個(gè)宏中由于沒有對變參起名,我們用默認(rèn)的宏__VA_ARGS__來替代它。第二個(gè)宏 中,我們顯式地命名變參為args,那么我們在宏定義中就可以用args來代指變參了。同C語言的stdcall一樣,變參必須作為參數(shù)表的最有一項(xiàng)出 現(xiàn)。當(dāng)上面的宏中我們只能提供第一個(gè)參數(shù)templt時(shí),C標(biāo)準(zhǔn)要求我們必須寫成: myprintf(templt,); 的形式。這時(shí)的替換過程為: myprintf("Error!/n",); 替換為: fprintf(stderr,"Error!/n",); 這是一個(gè)語法錯(cuò)誤,不能正常編譯。這個(gè)問題一般有兩個(gè)解決方法。首先,GNU CPP提供的解決方法允許上面的宏調(diào)用寫成: myprintf(templt); 而它將會被通過替換變成: fprintf(stderr,"Error!/n",); 很明顯,這里仍然會產(chǎn)生編譯錯(cuò)誤(非本例的某些情況下不會產(chǎn)生編譯錯(cuò)誤)。除了這種方式外,c99和GNU CPP都支持下面的宏定義方式: #define myprintf(templt, ...) fprintf(stderr,templt, ##__VAR_ARGS__) 這時(shí),##這個(gè)連接符號充當(dāng)?shù)淖饔镁褪钱?dāng)__VAR_ARGS__為空的時(shí)候,消除前面的那個(gè)逗號。那么此時(shí)的翻譯過程如下: myprintf(templt); 被轉(zhuǎn)化為: fprintf(stderr,templt); 這樣如果templt合法,將不會產(chǎn)生編譯錯(cuò)誤。 這里列出了一些宏使用中容易出錯(cuò)的地方,以及合適的使用方式。 錯(cuò)誤的嵌套-Misnesting 宏的定義不一定要有完整的、配對的括號,但是為了避免出錯(cuò)并且提高可讀性,最好避免這樣使用。 由操作符優(yōu)先級引起的問題-Operator Precedence Problem 由于宏只是簡單的替換,宏的參數(shù)如果是復(fù)合結(jié)構(gòu),那么通過替換之后可能由于各個(gè)參數(shù)之間的操作符優(yōu)先級高于單個(gè)參數(shù)內(nèi)部各部分之間相互作用的操作符優(yōu)先級,如果我們不用括號保護(hù)各個(gè)宏參數(shù),可能會產(chǎn)生預(yù)想不到的情形。比如: #define ceil_div(x, y) (x + y - 1) / y 那么 a = ceil_div( b c, sizeof(int) ); 將被轉(zhuǎn)化為: a = ( b c + sizeof(int) - 1) / sizeof(int); // 由于+/-的優(yōu)先級高于的優(yōu)先級,那么上面式子等同于: a = ( b (c + sizeof(int) - 1)) / sizeof(int); 這顯然不是調(diào)用者的初衷。為了避免這種情況發(fā)生,應(yīng)當(dāng)多寫幾個(gè)括號: #define ceil_div(x, y) (((x) + (y) - 1) / (y)) 消除多余的分號-Semicolon Swallowing 通常情況下,為了使函數(shù)模樣的宏在表面上看起來像一個(gè)通常的C語言調(diào)用一樣,通常情況下我們在宏的后面加上一個(gè)分號,比如下面的帶參宏: MY_MACRO(x); 但是如果是下面的情況: #define MY_MACRO(x) { /* line 1 */ /* line 2 */ /* line 3 */ } //... if (condition()) MY_MACRO(a); else {...} 這樣會由于多出的那個(gè)分號產(chǎn)生編譯錯(cuò)誤。為了避免這種情況出現(xiàn)同時(shí)保持MY_MACRO(x);的這種寫法,我們需要把宏定義為這種形式: #define MY_MACRO(x) do { /* line 1 */ /* line 2 */ /* line 3 */ } while(0) 這樣只要保證總是使用分號,就不會有任何問題。 Duplication of Side Effects 這里的Side Effect是指宏在展開的時(shí)候?qū)ζ鋮?shù)可能進(jìn)行多次Evaluation(也就是取值),但是如果這個(gè)宏參數(shù)是一個(gè)函數(shù),那么就有可能被調(diào)用多次從而達(dá)到不一致的結(jié)果,甚至?xí)l(fā)生更嚴(yán)重的錯(cuò)誤。比如: #define min(X,Y) ((X) (Y) ? (Y) : (X)) //... c = min(a,foo(b)); 這時(shí)foo()函數(shù)就被調(diào)用了兩次。為了解決這個(gè)潛在的問題,我們應(yīng)當(dāng)這樣寫min(X,Y)這個(gè)宏: #define min(X,Y) ({ typeof (X) x_ = (X); typeof (Y) y_ = (Y); (x_ y_) ? x_ : y_; }) ({...})的作用是將內(nèi)部的幾條語句中最后一條的值返回,它也允許在內(nèi)部聲明變量(因?yàn)樗ㄟ^大括號組成了一個(gè)局部Scope)。
個(gè)人分類: FreeBasic|3527 次閱讀|0 個(gè)評論
分享 Freebasic菜鳥初學(xué)Freebasic基礎(chǔ)教程四:了解條件編譯
ganlinlao 2017-5-8 18:25
這種能夠根據(jù)不同情況編譯不同代碼、產(chǎn)生不同目標(biāo)文件的機(jī)制,稱為條件編譯。條件編譯是預(yù)處理程序的功能,不是編譯器的功能。 條件編譯有多種形式,下面一一講解。 #if 命令 #if 命令的完整格式為: #if 整型常量表達(dá)式1 程序段1 #elseif 整型常量表達(dá)式2 程序段2 #elseif 整型常量表達(dá)式3 程序段3 #else 程序段4 #endif 它的意思是:如!氨磉_(dá)式1”的值為真(非0),就對“程序段1”進(jìn)行編譯,否則就計(jì)算“表達(dá)式2”,結(jié)果為真的話就對“程序段2”進(jìn)行編譯,為假的話就繼續(xù)往下匹配,直到遇到值為真的表達(dá)式,或者遇到 #else。這一點(diǎn)和 if else 非常類似。 需要注意的是,#if 命令要求判斷條件為“整型常量表達(dá)式”,也就是說,表達(dá)式中不能包含變量,而且結(jié)果必須是整數(shù);而 if 后面的表達(dá)式?jīng)]有限制,只要符合語法就行。這是 #if 和 if 的一個(gè)重要區(qū)別。 #elseif 和 #else 也可以省略,如下所示: #if __FB_WIN32__ print "This is Windows!\n" #else print("Unknown platform!\n" #endif #if __FB_LINUX__ printf("This is Linux!\n"); #endif #ifdef 命令 #ifdef 命令的格式為: #ifdef 宏名 程序段1 #else 程序段2 #endif 它的意思是,如果當(dāng)前的宏已被定義過,則對“程序段1”進(jìn)行編譯,否則對“程序段2”進(jìn)行編譯。 也可以省略 #else: #ifdef 宏名 程序段 #endif #ifdef __fb_debug__ print "正在使用 Debug 模式編譯程序..." #else print"正在使用 Release 模式編譯程序..." #endif 當(dāng)以 Debug 模式編譯程序時(shí),宏 _DEBUG 會被定義,預(yù)處器會保留第 5 行代碼,刪除第 7 行代碼。反之會刪除第 5 行,保留第 7 行。 #ifndef 命令 #ifndef 命令的格式為: #ifndef 宏名 程序段1 #else 程序段2 #endif 與 #ifdef 相比,僅僅是將 #ifdef 改為了 #ifndef。它的意思是,如果當(dāng)前的宏未被定義,則對“程序段1”進(jìn)行編譯,否則對“程序段2”進(jìn)行編譯,這與 #ifdef 的功能正好相反。 區(qū)別 最后需要注意的是,#if 后面跟的是“整型常量表達(dá)式”,而 #ifdef 和 #ifndef 后面跟的只能是一個(gè)宏名,不能是其他的。 例如,下面的形式只能用于 #if: #define NUM 10 #if NUM = 10 or NUM = 20 print "NUM: " NUM #else print "NUM Error" #EndIf 運(yùn)行結(jié)果: NUM: 10 再如,兩個(gè)宏都存在時(shí)編譯代碼A,否則編譯代碼B: #define NUM1 10 #define NUM2 20 #if Defined(NUM1) And Defined(NUM2) Print "NUM1:" NUM1 Chr(10) "NUM2: " NUM2 #else print "Error" #EndIf sleep 運(yùn)行結(jié)果: NUM1: 10, NUM2: 20 #ifdef 可以認(rèn)為是 #if defined 的縮寫。
個(gè)人分類: FreeBasic|2753 次閱讀|0 個(gè)評論
分享 Freebasic菜鳥初學(xué)Freebasic基礎(chǔ)教程二:宏定義和預(yù)處理命令
ganlinlao 2017-5-8 11:09
'冬瓜湯改編自c語言中文網(wǎng)的c語言基礎(chǔ)入門 宏定義是預(yù)處理命令的一種,它允許用一個(gè)標(biāo)識符來表示一個(gè)字符串。 先看一個(gè)例子: #define N 100 dim sum as long sum=20 +N print Sum 運(yùn)行結(jié)果: 120 該示例中的語句 sum = 20 + N;,N被100代替了。 #define N 100就是宏定義,N為宏名,100是宏的內(nèi)容。 在編譯預(yù)處理時(shí),對程序中所有出現(xiàn)的“宏名”,都用宏定義中的字符串去代換,這稱為“宏代換”或“宏展開”。 宏定義是由源程序中的宏定義命令#define完成的,宏代換是由預(yù)處理程序完成的。 宏定義的一般形式為: #define 宏名 字符串 #表示這是一條預(yù)處理命令,所有的預(yù)處理命令都以#開頭。define是預(yù)處理命令。宏名是標(biāo)識符的一種,命名規(guī)則和標(biāo)識符相同。字符串可以是常數(shù)、表達(dá)式等。 這里所說的字符串是一般意義上的字符序列,不要和FB語言中的字符串等同,它不需要雙引號。 程序中反復(fù)使用的表達(dá)式就可以使用宏定義,例如: #define M (n*n+3*n) 它的作用是指定標(biāo)識符M來代替表達(dá)式(y*y+3*y)。 在編寫源程序時(shí),所有的(y*y+3*y)都可由M代替,而對源程序編譯時(shí),將先由預(yù)處理程序進(jìn)行宏代換, 即用(y*y+3*y)表達(dá)式去替換所有的宏名M,然后再進(jìn)行編譯。 將上面的例子補(bǔ)充完整: 上面的程序中首先進(jìn)行宏定義,定義M來替代表達(dá)式(n*n+3*n),在sum=3*M+4*M+5*M中作了宏調(diào)用。在預(yù)處理時(shí)經(jīng)宏展開后該語句變?yōu)椋?sum=3*(n*n+3*n)+4*(n*n+3*n)+5*(n*n+3*n); 需要注意的是,在宏定義中表達(dá)式(n*n+3*n)兩邊的括號不能少,否則會發(fā)生錯(cuò)誤。 如當(dāng)作以下定義后: #difine M n*n+3*n在宏展開時(shí)將得到下述語句: s=3*n*n+3*n+4*n*n+3*n+5*n*n+3*n;這相當(dāng)于: 3n2+3n+4n2+3n+5n2+3n 這顯然是不正確的。所以進(jìn)行宏定義時(shí)要注意,應(yīng)該保證在宏代換之后不發(fā)生錯(cuò)誤。 對宏定義的幾點(diǎn)說明 1) 宏定義是用宏名來表示一個(gè)字符串,在宏展開時(shí)又以該字符串取代宏名,這只是一種簡單的替換。 字符串中可以含任何字符,可以是常數(shù),也可以是表達(dá)式,預(yù)處理程序?qū)λ蛔魅魏螜z查, 如有錯(cuò)誤,只能在編譯已被宏展開后的源程序時(shí)發(fā)現(xiàn)。 2) 宏定義不是說明或語句,在行末不必加分號,如加上分號則連分號也一起替換。 3) 宏定義必須寫在函數(shù)之外,其作用域?yàn)楹甓x命令起到源程序結(jié)束。如要終止其作用域可使用#undef命令。例如: #define PI 3.14159 Sub main () ' Code return 0 ; end Sub #undef PI Function func () 'Code end Function '========================= 表示PI只在main函數(shù)中有效,在func中無效。 4) 宏名在源程序中若用引號括起來,則預(yù)處理程序不對其作宏代換,例如: #define OK 100 print "OK " 運(yùn)行結(jié)果: OK 該例中定義宏名OK表示100,但在 print 語句中 OK 被引號括起來,因此不作宏代換,而作為字符串處理。 5) 宏定義允許嵌套,在宏定義的字符串中可以使用已經(jīng)定義的宏名,在宏展開時(shí)由預(yù)處理程序?qū)訉哟鷵Q。例如: #define PI 3.1415926 #define S PI*y*y /* PI是已定義的宏名*/ 對語句: print S在宏代換后變?yōu)椋? print 3.1415926*y*y 6) 習(xí)慣上宏名用大寫字母表示,以便于與變量區(qū)別。但也允許用小寫字母。 7) 可用宏定義表示數(shù)據(jù)類型,使書寫方便。例如: #define UINT ULong 在程序中可用UINT作變量說明: dim as uint a, b 應(yīng)注意用宏定義表示數(shù)據(jù)類型和用type…… As定義數(shù)據(jù)說明符的區(qū)別。 宏定義只是簡單的字符串代換,是在預(yù)處理完成的,而type… As是在編譯時(shí)處理的,它不是作簡單的代換,而是對類型說明符重新命名。被命名的標(biāo)識符具有類型定義說明的功能。 宏定義雖然也可表示數(shù)據(jù)類型, 但畢竟是作字符代換。在使用時(shí)要分外小心,以避出錯(cuò)。
個(gè)人分類: FreeBasic|2774 次閱讀|0 個(gè)評論
分享 Freebasic后期綁定調(diào)用excel,word,powerpoint等ole automation軟件
ganlinlao 2017-5-4 18:18
Freebasic后期綁定調(diào)用excel,word,powerpoint等ole automation軟件
在IE死掉以后,ms-office是目前微軟尚存的ole automation軟件,其它的coreal draw和auto cad都紛紛轉(zhuǎn)向。 不管是前期還是后期綁定ole automation,都只能通過idispatch接口,而idispatch只有兩種數(shù)據(jù)類型,一種是hResult(用來處理錯(cuò)誤),另一種是variant。所以不管vba有多少數(shù)據(jù)類型,它調(diào)用office對象,只有一種數(shù)據(jù)類型,那就是variant。 除了vb(vba),不管是c++,c#……都無法做到完全自動轉(zhuǎn)換variant中的類型,F(xiàn)B也不例化,variant絕對是一個(gè)很讓人頭疼的數(shù)據(jù)類型。 idispatch接口,最常用的就是getidofNames和invoke方法。其中為了方便使用,一般把invoke方法進(jìn)行細(xì)分, get 方法用來獲取屬性值和子對象, put 方法用來設(shè)置屬性值, set 用于byref方式設(shè)置屬性值(所以vba中使用set語句用來賦值object對象,呵呵), call 方法用來調(diào)用對象的方法。 FB中處理com和ole的庫不少,有的很強(qiáng)大,有的比較簡單,有的強(qiáng)調(diào)調(diào)用,有的強(qiáng)調(diào)不僅調(diào)用還強(qiáng)調(diào)能寫activeX的dll和ocx。但都或多或少有點(diǎn)瑕疵,因?yàn)閭(gè)人的喜好不同,寫出來的風(fēng)格不太一樣。 在這里,我就介紹其中的一種,這是vbrichclient作者為FB寫的一個(gè)簡單的vbvariant類庫。 寫一個(gè)簡單的例子: '================================== #include "simpleVariant.bi" dim excelapp as vbVariant excelapp=createobject("excel.application") excelapp.put("visible","b","true") excelApp.Get("workbooks").call("open","s","G:\Freebasic\FBtest\test.xls") print "調(diào)用成功" sleep '=================================== vbvariant類,有一個(gè)很遺憾的地方,就是它干脆不自動處理variant的數(shù)據(jù)類型,所以每一個(gè)參數(shù)值,都要指明數(shù)據(jù)類型(b:表示boolean;s:表示string(ansii);w:表示wstring(unicode);c:表示currency;i:表示integer;I:表示long;f:表示single;D:表示double,t:表示datetime,v:表示variant)。 這讓人很不爽,當(dāng)然這是有改進(jìn)的空間的。
個(gè)人分類: FreeBasic|3508 次閱讀|0 個(gè)評論

QQ|站長郵箱|小黑屋|手機(jī)版|Office中國/Access中國 ( 粵ICP備10043721號-1 )  

GMT+8, 2025-7-13 07:41 , Processed in 0.075006 second(s), 19 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

返回頂部