VB VC混合編程疑難問題解答

來源:互聯網
上載者:User

VB VC混合編程疑難問題解答

  我們在編寫VisualBasic應用程式的時候常常需要自己動手編寫一些庫函數或ActiveX控制項,而這些函數或者控制項常常採用VC 語言來寫,因而也常為VB和VC兩種語言之間不同參數類型、記憶體空間使用方法等問題為難,怎麼做好呢?本文介紹了在VB和VC混合編程的情況下對這些問題的解決方案。

  一、自訂型別參數向DLL庫函數的傳遞

  用VB,VC 進行混合編程時,通常需要在VB中調用VC 編寫的DLL庫函數,這時,一般都要遇到向庫函數傳遞參數的問題。對於標準類型(如Double,Long等)參數,其傳遞比較簡單,只要保證了VB中對庫函數的聲明和VC 中對庫函數的定義在參數類型、次序和傳遞方式上的一致性,參數就不會被錯誤傳遞。但是,如果需要向庫函數傳遞自訂類型的參數,情況就會變得複雜了。

  情況一:自訂類型的所有成員變數都是同一種類型(例如下面的Pens自訂類型,其成員都為Long型)。

  TypePens

  RedPenNumAsLong

  GreenPenNumAsLong

  B1uePenNumAsLong

  EndType

  這時,只要在VB和VC 中對該結構採用相同的定義,並充分注意到VB和VC 對某些資料類型(如32,位作業系統下,VC 中的int和VB中的Integer)儲存上的差異,就不會發生參數傳遞錯誤。

  情況二:自訂類型中成員變數的類型不完全一致。這時,又要區分兩種情況:

  情況(1)沒有Double型成員變數。

  這時一般也不會出現參數的傳遞錯誤。

  情況(2)含有Double型成員變數。

  這時參數通常就會被誤傳。比如傳遞下面的Person類型的參數到VC 開發的DLL庫函數,Double型成員Height的值就會在傳遞中丟失:

  TypePerson

  AgeAsLong

  HeightAsDouble

  EndType

  造成Height值丟失的原因是由於在VC 中儲存Person型變數時,將自動在Long型成員Age和Double型成員Height之間插入若干位元組的分隔空間,而VB則不會。所以,VC 中儲存一個Person型變數需要的記憶體要多於12位元組,而VB只需要12個。因此,從VB傳入DLL庫函數的Person型變數就不能被正確接收。

  解決這一問題的方法有多種,這裡介紹一種比較簡便和普適的,稱之為“引入補位成員法”:在Person這種自訂類型中引入若干個記憶體補位成員,使得任一個Double型成員之前的所有成員佔用的位元組總數都是單個Double型變數所佔位元組數的整數倍(8的整數倍)。

  仍以Person類型為例,由於Age成員佔用4位元組記憶體,所以要在其後引入一個佔用4位元組的補位成員,不妨引入一個String型的成員Tempst:

  TypePerson

  AgeAsLong

  TempstAsString*4

  HeightAsDouble

  EndType

  於是,Double型成員Height之前的所有成員佔用的記憶體總數變成了8個位元組,是8的整數倍。此時,將DLL庫函數中對Person的定義作同樣的修改後,就可以正確接收從VB傳來的Person型參數了。

  注意:引入補位成員時,不但要合理分配其佔用的位元組數,而且要正確安排其在結構體中的位置,二者缺一不可。上例中,若把補位成員放在Height之後,Doubl型變數Height之前的所有成員佔用的位元組總數仍然是4,不是8的整數倍。

  在自己編寫DLL庫函數時,往往會在函數介面處使用複雜的自訂結構。在VB中調用這種函數時,採用“引入補位成員法”適當修改結構體的定義,就可以有效地避免參數傳遞上的錯誤。

  二、使用在VC 中動態申請的記憶體

  混合語言編程時,有時需要在VB代碼中使用通過VC 動態申請到的記憶體。這時,可以通過下述方法實現:

  1)VC 中申請動態記憶體的DLL庫函數

  char*APIENTRYCreateStringBuffer(longLength)

  {

  char*bufV;//假設需要申請用以存放字元申的動態記憶體

  buf=(char*)::malloc(Length);

  returnbuf;//返回字串指標,其實就是一個long型數

  }

  2)VB中接收動態記憶體指標的代碼

  ......

  DeclareFunctionCreateStringBufferLib"C:DLLTestTest.dll"_

  (ByValLengthAsLong)AsLong

  'Long型變t接收動態記憶體指標

  ......

  DimslBuffer&

  atBuffer=CreateStringBuffer(20)

  '申請一塊可存放20個字元的記憶體,得到指向該記憶體的指標

  ......

  '使用該動態記憶體

  ......

  注意:VB中使用完動態記憶體後,為了避免記憶體流失二要將其指標傳回VC 進行記憶體釋放工作。

  三、自訂型別參數向ActiveX控制項的傳遞

  在編寫VB程式時,如果使用的是標準ActiveX控制項,那麼一般不需要向控制項傳遞自訂類型的參數,因為大多數控制項的大多數屬性都是標準類型(如Double,Long)的。但是,在混合語言編程中,當我們採用VC 中的ATL3.0模板(而不是VB)自行開發ActiveX控制項時,往往希望能夠向控制項的某些屬性或方法傳遞自訂類型的參數,以提高參數的傳遞效率。

  這裡介紹一種向控制項傳遞自訂型別參數的簡便方法。假設要以VB為用戶端開發一個ActiveX控制項AX,它有一個Student屬性,類型是自訂結構Person:

  TypePerson

  AgeAsLong

  HeightAsDouble

  EndType

  第一,正確編寫Student屬性的介面函數(以用ATL3.0模板開發AX為例)。我們將Student屬性存取函數的介面參數類型寫成一個long型的指標,而不再是BSTR。因為ActiveX內部的通訊全部基於Unicode基礎之上,所以,這樣處理會避免由於字元集不匹配而造成的參數誤傳。相關的代碼如下:

  1)AX.idl中對Student屬性的定義

  [propget,id(0),helpstring("propertyStudent")]HRESULT

  Student([out,retval]long*pVal);

  [propput,id(0),helpstring("propertyStudent")]HRESULT

  Student([in]longnewVal);

  2)AX.h中對Student屬性存取函數的定義

  STDMETHOD(get_Student)(/*[out,retval]*/long*pVal);

  STDMETHOD(put_Student)(/*[in]*/longnewVal);

  3)AXcpp中對Student屬性存取函數的實現

  STDMETHODIMPCAX::get_Student(long*pVal)

  {

  //TODD:Addyourimplementationcodehere

  //得到儲存Student屬性的成員變t的指標,賦給*pVal returnS_OK;

  }

  STDMETHODIMPCAX::put_Student(longnewVal)

  {

  //TODD:Addyourimplementationcodehere

  //將儲存Student屬性的成員變址的指標指向newVal所指的記憶體空間,

  //然後通過記憶體拷貝方式拷貝此空間存放的Student的屬性值

  returnS_OK;

  }

  第二,正確編寫VB向AX的Student屬性動態賦值的代碼。在VB中,先聲明一個Person型變數,給該變數賦值後,擷取該變數的記憶體位址並賦給Student屬性即可。代碼如下:

  ......

  DimStudentPropAsPerson

  DimStudentAddrAsLong

  StudentProp.Age=23

  StudentProp.Heigth=1.78

  '得到StudentProp變數的記憶體位址(方法從略),賦給StudentAddr

  AX1.Student=StudentAddr

  ......

  藉助指標完成自訂型別參數向ActiveX控制項的傳遞所依據的是以下事實:不論控制項是.dll還是.ocx,它都是與其客戶同在一個進程內的伺服器。所以,只要AX被編譯成.dll或.ocx,指標的傳遞就是安全可靠的。

  四、中英文混合型字串輸出長度的確定

  中英文混合型字串輸出長度的確定問題在VB編程中經常遇到,而且可以通過VB,VC 混合編程有效解決,所以在此一併給出。

  VB編程中,經常需要得到某個字串在實際輸出時所需要的長度。這時,我們通常會考慮Len()和LenB()這兩個函數。

  我們知道,Len()返回的是字串中字元的個數,對於不含中文字元的字串,其傳回值通常就等於該字串的輸出長度;LenB()返回的則是按照雙位元組字元集(DBCS)計算出的字串所佔用的位元組數,對於純中文字元組成的字串,其傳回值通常也等於該字串的輸出長度。但是,當字串中既有中文又有英文(這裡將數字等視為英文)字元時,二者的傳回值都不等於該字串的輸出長度。比如:“A中國人”這個字串,用Len()函數時將返回4;LenB()則返回8;而實際輸出時(比如向某記錄檔案輸出該字串),它將佔用7個印刷符(每個英文字元佔1個,每個中文字元佔2個)。

  為了計算中英文混合型字串的輸出長度,我們可以用VC 編寫一個完成此計算的DLL庫函數,在VB中直接調用該函數即可。該VC 函數和VB中的調用代碼如下:

  1)VC 6.0中的DLL函數

  longAPIENTRYSizeof_vbString(char*at)

  {

  return(long)(::atrlen(st));

  //::atrlen()返回int值,但在32位作業系統下,

  //VC 中的int類型與VB中Long類型的範圍是相當的

  }

  2)VB6.0中對Sizeof_vbString()的聲明和調用

  ......

  DeclareFunctionSizeof_vbStringLib"C:DLLTest.dll"_

  (ByValstAsString)AsLong

  ......

  ......

  DimstLen&

  stLen=Sizeof_vbString("A中國人")

  stLen=7

  ......

  應該指出:上述方法同樣可以計算純英文或純中文字串的輸入長度。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.