none
VB2005 import VC++ dll file with Pointer RRS feed

  • 問題

  • 大家好
    小弟的問題, 希望大家能幫忙解決....
    最近, 小弟的VB2005程式, 要讀一個由vc++2005 制作的dll 檔
    會call裏面一個function...
    聽落好像不難
    但這個function 有下列特點:
    1. input parameter及output parameter所有都是pointer
    例: abc(string*,List(of T)*,string*, List(of T)*)->小弟不太懂c++..所以這都是vb的syntax...
    因為小弟的程式中有兩個function都由string中形成兩個integer(e.g. string是文章, list 是文章中每句的starting index,及 length) 因為文章的長短都會改變,所以決定以list來儲存
    T為兩個integer的structure
    2. output parameter 都是一個list, 來儲存array的 structure

    小弟固擾了很久, 不知道怎樣去完成
    在網上找到了dllimport, marshal等等的資料....
    但一連繫到input pointer, output pointer...加上pointer of list...
    令小弟痛苦極了.....
    想問各位,誰能幫小弟解決疑難呢....萬分感激....
    2009年3月4日 上午 07:50

解答

  • 如果你 .Net 想宣告為 As xxx() 的話,就要配合 SafeArray ,一般陣列如同前一篇回的,是藉由陣列第一個變數傳址呼叫來處理。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    • 已標示為解答 Eagles.Derek 2009年3月25日 上午 06:02
    2009年3月25日 上午 04:12

所有回覆

  • 你 VC 產出的 dll 是否有限制?沒限制的話直接用 Managed DLL ,在專案參考拉入這個 dll 即可。

    2009年3月4日 下午 12:58
  • 試試宣告時, 那些 pointer 參數用 byref 的方式宣告看看....
    2009年3月4日 下午 01:30
  • 不太明白有限制的意思呢.....對不起.....
    2009年3月10日 上午 02:56
  • longhairpan:
    謝謝你的提意啊!!
    你的意思是無論input string, integer, 甚至list(of t), 都以byref直接輸入,對嗎?
    那輸出呢?應該怎儲存???

    2009年3月10日 上午 02:58
  • 你 VC 2005 編譯成 dll 時,有沒有被老闆或系統架構師要求做成 函數型dll 、COM DLL ?沒有的話,直接輸出成 Managed DLL ,所有 .Net 的語言都吃這種格式,直接 Imports 到專案就可以用,不用任何宣告。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月10日 上午 05:32
  • 輸出? byref strcture ? 或是 return structure ?
    如果是 return , 看看輸出是對應到什麼 type,
    一般 structure 會用 byref 方式代入, 跟輸入一樣....

    對 dll 而言, 你用 byref 方式代入, 就是把變數的指標代進去,
    dll 內部都拿到指標了, 讀/寫 = 輸入/輸出
    都是 ok 的....

    有一點值得注意....
    要代這些參數前, 注意 GC .....
    2009年3月10日 上午 05:36
  • 其實這個dll不是小弟寫的, 只知道要跟據這個dll 放在我的vb程式裏面進行
    已經加了這句code:
     <DllImport("compare.dll", CharSet:=CharSet.Unicode)> _
        Function Compare(ByVal ref As String, ByVal ref_list As List(Of sen_struct), ByVal test As String, ByVal test_list As List(Of sen_struct)) As Long(對嗎???)

        End Function
    這樣有錯嘛???
    ref_list, test_list就是兩個structure....
    現在,暫時要處理pointer部份都是output...
    在c++的function裏面, 都會輸出一個pointer
    那我在vb call這個dll時, 以甚麼型式 儲存這個output??
    dim o_p As...?? = Compare(....)
    這個時小弟的問題....
    2009年3月10日 上午 06:02
  • 那你確認這個編譯出來的東西是函數型 DLL 嗎?只有函數型 DLL 才用 DllImport 宣告。

    函數型 dll 的記憶體模型跟 .Net Managed 不相容,沒看過 List 的傳遞,此外,Structre 在 .Net 內並非是緊密排列,裡面若有用到 String 或結構中的結構,都會出問題。

    這類專門的說明,在線上手冊有專門章節。
    逐步解說:呼叫 Windows API
    ms-help://MS.MSDNQTR.v90.cht/dv_vbalr/html/9280ca96-7a93-47a3-8d01-6d01be0657cb.htm

    HOW TO:呼叫 Windows API (Visual Basic)
    ms-help://MS.MSDNQTR.v90.cht/dv_vbalr/html/27d75f0a-54ab-4ee1-b91d-43513a19b12d.htm

    你還可以在 http://support.microsoft.com/ 找到相關範例。

    另外要檢討這個函數宣告是否正確,還需要它的原型宣告,當你拿到這個 dll 時,是否有拿到使用這個 dll 的 .h 檔?把裡面的宣告貼出來。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月10日 上午 07:22
  • 要這個嗎?
    using namespace std;
    #include "stdafx.h"
    #define COMPARE_EXPORTS
    #include "Compare.h"


    #ifdef _MANAGED
    #pragma managed(push, off)
    #endif

    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
                         )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
        }
        return TRUE;
    }

    #ifdef _MANAGED
    #pragma managed(pop)
    #endif


    另外,想問一問, c++裏面有vb list(of t)的結構嗎??

    2009年3月10日 上午 08:42
  • ... 沒看到你前面貼 Compare 這個函數的宣告。你應該到 Compare.h 這個檔去找吧?

    看這句你這個 dll 應該是 Managed 的吧?
    using namespace std; 

    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月10日 上午 09:23
  • extern COMPARE_API int nCompare;


    COMPARE_API int *fnCompare(std::string RefTxt, int RefSenIdx[][2], int nRef, std::string TestTxt, int TstSenIdx[][2], int nTest);

    但現在, 有少許改變, 要將兩個int array, 由VB INPUT 兩個List(of T)
    output 都是List(of T).
    這樣怎做????
    2009年3月11日 上午 02:04
  • ...
    你最好用
    C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\Bin\Depends.Exe

    看一下你這個 dll 檔,看看是否能在 Export 中找到 Compare 這個進入點。
    從你貼的宣告來說,進入點是 fnCompare ,所以是不同名稱的函數,除非你另外有設定別名,定義編譯後的 dll Export 的名稱。

    另外這邊型別宣告是整數陣列,就不能用 List 集合物件來取代,陣列跟集合是兩種東西,並非是可替換或互為取代的型別。
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月11日 上午 02:51
  • 多謝閣下的提醒
    讓我再重新說明一次吧
    現在的dll function為fnCompare
    輸入的是(string, list, string, list)
    輪出的也是list
    pointer的....不用了....
    所以小弟的問題是, vc++裏的list (t)是否能與vb的list(of structure) 互通呢?
    因此在vc++的dll function裏都可以define(string, list, string, list)
    那output會是甚麼呢??
    在vb裏,應該是 function fnCompare(string, list, string, list) AS list...對嗎?
    那在c++的function裏, return 那個list, 對不對???
    2009年3月11日 上午 05:58
  • ???
    你前面 dllimport 的宣告是 Compare,不是 fnCompare... 你上面貼的標頭檔是 整數陣列 ,輸出是指標

    看不出來哪裡有 List ...

    你的 VC++ 如果編譯成 Managed DLL (也是 dll) ,則必然與 VBNET 相容,都是基於 .Net 的基礎。

    如果編譯成 COM DLL (也是 dll) ,則理論上可相容,但是否相容仍要測試。呼叫過程是:
    VBNET -> 封裝遞送成 COM 記憶體模型 (Object) -> COM DLL ->
    a. .Net 寫的發布成 DLL 會再轉譯為 .Net 記憶體模型 (這個相容)
    b. 真正的 COM DLL (這個應該不相容)

    如果編譯成 函數型 DLL ,物件本身基本上不會成功,所以這類需求都是傳遞 結構 ,只有結構才能確保記憶體內容與順序。

    你現在到底是哪種 DLL 都沒說清楚,引入檔跟你的宣告、解釋又相異,你不覺得這個問答一直在一開始的地方打轉嗎?
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月11日 上午 06:25
  • 對不起,可能有點混亂了
    現在我的program 作少許改動
    原本是pointer的輸入/出, 改為list
    所以小弟的問題, 都改為c++裏的list...
    因為現在 fnCompare 為 (string, list, string, list)
    而output為 一個list.....
    所以想於c++裏define 好像vb裏的list(of t)
    可以嗎??
    2009年3月11日 上午 07:53
  • 小弟有一個vc++ 2008 制成的 dll,裏面的function會return 一個header pointer of linked list(所有東西已define)
    在vb2005 裏, 成功地"召喚" 這個vc++ dll, 但小弟一懂如何處理這個"頭指標"
    以integer, intptr, long, 或者裏面的class(vb裏的structure) define這個function.都不行...
    頭三者, 只會得到類似pointer address的6 位數字....

    小弟要將整個linkedlist 由vc++ function裏拿出來....有沒有高人指點呢.......痛苦中.......
    感謝....

     <DllImport("xxxxx.dll")> _
         Function testFunction() As ?????<-這個是....甚麼?

        End Function

    這個linked list 裏面的object都是不同長度的integer array來啊....
    • 已合併 璉璉Moderator 2009年3月21日 上午 03:52 同作者相同主題發文
    2009年3月20日 上午 06:48
  • 請貼出標頭檔 (.h) 內的宣告以利判斷

    一般來說 Pointer 就是用 Integer / IntPtr 來宣告。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月20日 上午 07:02
  • 這是小弟的definition
    extern "C" _declspec(dllimport) COMPARE_API classname * testFunction();
    .CPP : _declspec(dllimport) COMPARE_API classname * testFunction()

    這樣可以嗎??
    2009年3月20日 上午 08:28
  • ...
    你相同的問題請合併,例如說跟這篇:
    VB2005 import VC++ dll file with Pointer

    我看你最近在各版換個標題也是問相同的問題,我用我所知道的看法來整理。

    你現在的問題是在於你要把 VC++ unmanaged 的 List 傳給 VB managed 的 List 。

    問題在於:
    1. 兩者的記憶體配置是否相容?微軟並沒有公告 .Net 記憶體配置方式,此外物件記憶體配置也不可預期。
    2. managed Call unmanaged (api / com) ,.Net 會自動做變數封裝遞送,這部分的自動你沒辦法控制,但你可以自己轉成 byte() 去送,可是回到老問題,物件記憶體在 unmanaged 如何配置是不可預期的。

    所以微軟在 API 中,頂多用結構取代一堆變數,沒有看到有物件。同語言、同編譯器的,或許因為物件指標能夠傳遞,但是 .Net 跟 MFC 算不同平台,你傳一個物件指標過去,接收端可能根本不能解讀。

    所以前一篇才會跟你說,用 Managed DLL ,因為記憶體模式相同,就不用擔心丟指標過去對方看不懂。

    如果你堅持要用物件,你可以考慮 COM DLL ,然後做型別程式庫給 .Net 辨識,.Net 會產生 Ax物件名.dll 來做封裝遞送的轉換,注意,這邊的物件內所用的變數要是 oleaut32.dll 裡面定義的 Variant 變數。

    如果你要用函數型 DLL ,那麼用結構或是實值型別的陣列是不錯的考慮,硬要用物件的話,除非你搞清楚記憶體模型,並且你能把 .Net 記憶體模型做正確的轉換。

    物件雖然很方便,但是新舊平台中卻是個大麻煩。

    在 .Net 之前,跨語言是個大工程,因為變數的記憶體模型不同,.Net 下,跨語言變成很容易的事,那也僅限在 .Net 平台下,你硬要把不同時期的平台跟跨語言一起搞,哪除非你夠瞭解中間的記憶體狀態,追著記憶體變化跑,需要花比較長的時間,那就要看哪位網友閒閒有空幫忙,或是你付費找人幫你追,因為物件裡面可能會有多個遠程指標跟實值變數參雜,要先過濾出標記的型別編號或是指標,如果依循 Variant 的規則,那還好解決,型別宣告與常數都有現成的,如果不是,那就要測測看、猜猜看才知道。
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月20日 上午 09:16
  • 謝謝您的回覆
    令我摸不著頭腦的是, 我這個應該是函數型dll吧
    我要傳遞這個指標, 是因為在這個c++的程式中, 會生出不同size的array
    例:
    i_array = {1,2,3,4,5,6}
    j_array = {1,2,3,4}
    vb 裏面call的function, 就是要拿取c++ function 裏面生出來的array
    在下程式能力不夠, 只能想到以linked list 儲存所得出來的array object
    然後傳回class 的指標
    然後在vb 中 拿取一整個linked list...
    就是因為要傳回不同長度的array, 才令小弟頭昏腦漲啊......
    否則是用array傳的方法就可以了.....
    list, arraylist, linked list都是小弟找到的方法
    但都相信是回傳指標吧???
    除了這樣 ...有沒有高人教教小弟怎做啊......
    2009年3月20日 上午 10:06
  • 你看過哪個 API 這樣設計?

    大部分的 API 會設計成:
    參數([in/out]傳址呼叫的陣列, [in/out]傳址長度, [in/out]傳址型別)
    回傳:錯誤代碼

    第一次呼叫 陣列傳入 null ,利用傳址傳回長度、型別
    動態宣告指定型別陣列
    第二次呼叫才把宣告好的陣列放進去,全部傳回



    另一種宣告為結構,或直接採用 Variant SafeArray 這個 16 Byte 變數
    參數([in/out]SafeArray)
    回傳:錯誤代碼 (你也可以回傳 SafeArray,但基本上 API 通常會另外有回傳值)

    若使用 SafeArray ,.Net 可以直接封裝遞送,不然就自己搞類似的結構。
    byte
    [0]: 是否為陣列,值為 8
    [1]: 型別,各變數型別所代表值 詳見 MSDN
    [2 ~ 7]: 不用
    [8 ~ B]: 陣列描述器指標
    [C ~ F]: 不用

    陣列描述器,包含維度描述,詳見 MSDN ,裡面有指標指向實體陣列

    如果不想走 Windows 內建的 Variant SafeArray ,就自己定義一個結構,包含型別描述,讓呼叫端處理完型別後,呼叫 API 來拷貝。

    跨 .Net 和 MFC 時,盡量使用實值型別傳遞,不要偷懶想使用物件,兩個記憶體模型又不同...


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月20日 下午 12:47
  • 合併兩討論緒
    T.L. Cheng
    2009年3月21日 上午 03:53
    版主
  • 對不起, 小弟才疏學淺, 以為直接define variable就可以傳送
    現在, 小弟的input ,為(string, hashtable, string, hashtable), 在c++裏, function都是input hashtable by ref, 我想這樣做到吧....
    關於那個output, 由心冷朋友回覆,相信都應該由safearray 著手, 對吧??
    那要在c++裏及vb裏都實行這個, 就可以將兩著的內容封裝,傳送,對嗎??
    其實最令到弟煩惱的就是那個dynamic size array的傳送.....


    2009年3月23日 上午 01:27
  • 如果你字串用的型態是 Variant String ,只要一個引數。
    若是用 C 本身的宣告做成 DLL,通常 VB 要搭兩個引數:Byval lpString As String, Byval vLength As Integer 來處理 VC 的字串,因為兩者記憶體模型並不相同。

    這部分在線上手冊有範例與說明,你可以翻看。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月23日 上午 01:34
  • function(std::string RefTxt, CStructHashT &RTable, int nRef, std::string TestTxt, CStructHashT &TTable,int nTest)
    這是我在c++裏的function的 definition
    std::string, 在vb 裏,應該只要define By Val RefTxt as String, 然後傳入, 對吧??
    nRef and nTest兩個都是integer, 都應該pass by ref, right?
    hashtable, 在function裏已經是pass by ref, 那我在vb裏都是pass by ref 吧....


    2009年3月23日 上午 01:44
  • 上面寫了:通常 VB 要搭兩個引數:Byval lpString As String, Byval vLength As Integer

    結構是指要搭配一個傳址呼叫的引數即可。

    你需要翻看一些 VC6 時線上手冊關於 mix languages 一節,裡面有談到當 dll 函數庫提供給各種語言呼叫時,所需注意到的細節。

    String, Array 都是其中重中之重,結構則須處理裡面的字串或 Array ,所以意思還是差不多,都是 String 跟 array 的問題。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月23日 上午 01:49
  • 真的對不起...小弟真定不太明白....請原諒小弟的笨...
    是否在function前加extern "C" _declspec(dllimport)
    就表示言個是由c 的呼叫??
    那在c++裏, 即使是以c++ 來編寫, 其string為std::string, 但都要在function裏加上一個variable為string 的length?
    再傳入function內?
    "結構是指要搭配一個傳址呼叫的引數即可。"
    這句小弟也不太明白,您說的是hashtable 的structure, 還是list 內的strucutre?
    c++ function(dll) 內傳出的是一個有dynamic size array的"東西"
    可否簡單給小弟一些指導,關於這個問題的一些可行方法....
    對以上的問題,實在對不起....
    在vb /vc++兩者的結合..令小弟太煩惱了...
    2009年3月23日 上午 02:17
  • 前面說了:因為兩者記憶體模型並不相同。

    前面也說了:String, Array 都是其中重中之重,結構則須處理裡面的字串或 Array ,所以意思還是差不多,都是 String 跟 array 的問題。

    你要給 VB 呼叫的陣列,就要讓 VB 能識別,所以你結構裡面的陣列也要做相同的處置,處置方式前面也說過了。

    你要去看既有的文件,你文件不看的話,這些都是空談。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月23日 上午 02:21
  • 你可以用這個關鍵字來瀏覽 MSDN 上的相關文章 "mixed-language program" site:microsoft.com:
    http://www.google.com.tw/search?hl=zh-TW&q=%22mixed-language+program%22+site%3Amicrosoft.com&meta=&aq=f&oq=
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月23日 上午 02:27
  • 我有看過閣下提供的參考連結
    但好像都找不到關於這個問題的網址啊....
    那閣下的意思是, 小弟要在vb裏define一個結構,裏面的內容跟c++ class的內容一樣, 對嗎?
    從而再進一步透過這個結構, 得到c++ function的輸出, 對嗎??
    string, array的問題...還是要再進一步研究....

    2009年3月23日 上午 03:21
  • 微軟線上手冊只說明記憶體模型與概念,跨平台的問題請自己測試。測試過程應該直接輸出一段記憶體區塊的內容,不是直接用宣告的型態去接。

    前面說過:
    此外,Structre 在 .Net 內並非是緊密排列,裡面若有用到 String 或結構中的結構,都會出問題。
    如果編譯成 函數型 DLL ,物件本身基本上不會成功,所以這類需求都是傳遞 結構 ,只有結構才能確保記憶體內容與順序。

    所以組成結構的要求:
    1. 實值型別
    2. 緊密排列

    對應到 VC 的 struct ,沒說過要去對應 class ,你一直在同一個地方打轉。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月23日 上午 05:45
  • 感謝閣下的提點,
    只是小弟想到的是以linked list來輸入array, 所以會想到c++的class
    再者,小弟對c 並不是太熟習, 所以才問是否以c++寫的dll, 都可以在vb裏面呼叫吧
    那小弟應該要define一個struct, 而以一些方法來先儲存那些dynamic array吧?
    最後在vb 中, define一個相同的structure, 用來接收這個dll function的output
    概念上有沒有錯???

    閣下說傳遞結構,是否這樣的意思??
    2009年3月23日 上午 06:40
  • SafeArray 就是微軟定義的多變數型態動態陣列,定義在 oleaut32.dll ,.Net 封裝遞送後的格式就是這個格式,你需要的是看 MSDN 的說明。
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月23日 上午 08:29
  • 那是否要將那些arrays 以safearray儲存,然後在vb2005 裏define safearray來接收就可以??
    2009年3月23日 上午 09:30
  • ...
    線上手冊:

    陣列的預設封送處理: ms-help://MS.MSDNQTR.v90.cht/dv_fxinterop/html/8a3cca8b-dd94-4e3d-ad9a-9ee7590654bc.htm
    將陣列參數傳遞給 .NET 程式碼

    從 Unmanaged 程式碼中可以將 C-Style 陣列和安全陣列傳遞給 .NET 程式碼,其可做為安全陣列或 C-Style 陣列。下表顯示 Unmanaged 型別值和匯入的型別。

    Unmanaged 型別

    匯入的型別

    SafeArray(類型)

    ELEMENT_TYPE_SZARRAY<ConvertedType>

    陣序規範 = 1,下限 = 0。大小只有包含在 Managed 簽章中時才會知道。不是陣序規範 = 1 或下限 = 0 的安全陣列無法封送處理為 SZARRAY

    類型[]

    ELEMENT_TYPE_SZARRAY<ConvertedType>

    陣序規範 = 1,下限 = 0。大小只有包含在 Managed 簽章中時才會知道。

    安全陣列

    當安全陣列是由型別程式庫匯入至 .NET 組件時,陣列會轉換為已知型別 (如 int) 的一維陣列。套用至參數的相同型別轉換也會套用至陣列元素。例如,BSTR 型別的安全陣列會變成字串的 Managed 陣列,而變數的安全陣列會變成物件的 Managed 陣列。SAFEARRAY 元素型別是從型別程式庫中所擷取的,而且儲存在 UnmanagedType 列舉型別的 SAFEARRAY 值中。

    因為安全陣列的陣序規範和界限無法從型別程式庫中判斷,所以陣序規範會假設為等於 1,而下限會假設為等於 0。陣序規範和界限必須定義在由型別程式庫匯入工具 (Tlbimp.exe) 所產生的 Managed 簽章中。如果傳遞給方法的陣序在執行階段改變,會擲回 SafeArrayRankMismatchException。如果傳遞的陣列型別在執行階段改變的話,會擲回 SafeArrayTypeMismatchException。下列範例顯示 Managed 和 Unmanaged 程式碼中的安全陣列。

    Unmanaged 簽章

    HRESULT New1([in] SAFEARRAY( int ) ar);  
    HRESULT New2([in] SAFEARRAY( DATE ) ar);  
    HRESULT New3([inout] SAFEARRAY( BSTR ) *ar); 

    Managed 簽章

    Sub New1(<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VT_I4)> ar() As Integer)  
    Sub New2(<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VT_DATE)> ar() As DateTime)  
    Sub New3(ByRef <MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VT_BSTR)> ar() As String)  
     
     

    ...

    陣列的預設封送處理: ms-help://MS.MSDNQTR.v90.cht/dv_fxinterop/html/477a411a-f55d-4449-b8c5-6ade44e6c8ff.htm

    建置 COM 元件的互通: ms-help://MS.MSDNQTR.v90.cht/dv_fxinterop/html/7a2c657a-cfef-40f0-bed3-7c2c0ac4abdf.htm

    HOW TO:手動建立包裝函式: ms-help://MS.MSDNQTR.v90.cht/dv_fxinterop/html/cc2a70d8-6a58-4071-a8cf-ce28c018c09b.htm

    HOW TO:封送處理 ADO.NETSAFEARRAY: ms-help://MS.MSDNQTR.v90.cht/dv_vccore/html/1034b9d7-ecf1-40f7-a9ee-53180e87a58c.htm

    從 Managed 程式碼呼叫原生函式: ms-help://MS.MSDNQTR.v90.cht/dv_vccore/html/982cef18-20d9-42b4-8242-a77fa65f2e36.htm

    範例:
    如何將 Visual Basic 的.NET 或 Visual Basic 2005 應用程式和 Visual C ++.NET] 或 [Visual C ++ 2005 函式之間傳遞的陣列: http://support.microsoft.com/kb/841293/zh-tw
    如何將字串的 SafeArray 傳遞的 VARIANT *,Visual C ++ 和 Visual Basic 6.0 之間: http://support.microsoft.com/kb/167668/zh-tw

    更多的資訊請自行蒐尋 MSDN




    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月23日 上午 09:47
  • 對不起....為甚麼小弟找不到閣下給我的連結???
    還有, 如果簡單的在c++function裏return一個array pointer, 然後在vb2005 裏read這個pointer, 從而提取整個array, 真的那麼難嗎???
    都是結構及類型問題???
    2009年3月24日 上午 03:08
  • 如果這麼簡單,就不會有一堆人煩惱了。

    C++ 用指標指的資料結構(不論是什麼),如果要 VB 能夠順利拿取的話,內建的 Interoperability service 的 Marshal 類別有提供許多方法,像是 Marshal.PtrToStructure(), Marshal.PtrToStringANSI()...。

    但是有一點很重要,如果你傳的是像 int, char[], double 這種內建型別是 ok,若是自訂型別或類別,那基本上本來就沒那麼容易跨接。

    以你的函數定義來看:

    function(std::string RefTxt, CStructHashT &RTable, int nRef, std::string TestTxt, CStructHashT &TTable,int nTest)

    轉換成 C# (抱歉,我的慣用語言是 C#,VB 請自己轉一下):

    static extern void function(string RefTxt, ???, int nRef, string TestTxt, ???, int nTest);

    為什麼我會標 ???,表示 .NET 中並沒有一個型別可以直接對應到 CStructHashT,這樣的話,不是改用內建型別傳,就得要自己定義 Marshal 的行為。
    畢竟 .NET 可以做的,只是相容於大多數 API 的呼叫習慣,不可能針對幾個個案(你這種情況就是個案)來開發 Marshal 的模型。
    小人物一枚。
    2009年3月24日 上午 03:21
    版主
  • 小朱, 感謝您的答覆
    小弟嘗試過建立一個簡單的array, 然後再c++裏return那個array pointer.
    結果, 都只是拿取到int array (array 為{1,2,3,4,5,6}) 的"1"....
    不知道怎樣去拿下一個value...
    Dim pointer As IntPtr = IntPtr.Zero
    pointer = Marshal.ReadIntPtr(pointer, 1), 都會生error....
    Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
    所以小弟就問...簡單地在c++ dll的output中拿取一個int array..都那麼難嗎?
    對小弟的case, .net裏的hashtable, 不能傳到dll 裏面嗎???
    2009年3月24日 上午 03:36
  • 你在宣告中使用 int() 也接不到嗎?

    example:

    // in C++
    int[] myArray()
    {
         return {1,2,3,4,5,6}; // 隨便寫一下,自己要改成正確的。
    }

    // in C#
    static extern int[] myArray();

    小人物一枚。
    2009年3月24日 上午 03:50
    版主
  • 好像在c++裏不能直接傳出array, 要以pointer形式, 對吧???
    本人的code:
    c++
    .h
    extern "C"   __declspec (dllexport) COMPARE_API int * __stdcall test_array();
    .cpp
     __declspec (dllexport) int []  __stdcall test_array()
    {
        int i_array[]={2,2,3,4,5,6};
        int * ret =  new int[] = i_array;
        return ret;
       
    }

    vb2005:
    pointer = Marshal.ReadIntPtr(pointer, 0)

            Me.RichTextBox1.Text = pointer.ToString



            pointer = Marshal.ReadIntPtr(pointer, 1)<----這句有error
            Me.RichTextBox1.Text &= pointer.ToString
    2009年3月24日 上午 03:58
  • ms-help 起頭的網址,是你有安裝 MSDN for Visual Studio 線上手冊的位置,相同內容可在 msdn 或 msdn2 搜尋得到。

    MS.MSDNQTR.v90.cht 代表的是 VS2008 繁中的線上手冊,線上手冊也可以在微軟下載中心找到下載。
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月24日 上午 04:00
  • 這裡有 .NET 處理以平台叫用方式呼叫 DLL 中的函數時,陣列的處理方式:
    http://msdn.microsoft.com/zh-tw/library/hk9wyw21(VS.80).aspx
    小人物一枚。
    2009年3月24日 上午 04:05
    版主
  • 謝謝小朱提供的網頁...
    但, 在網頁內的dll裏,都是array內的操作
    並沒有回傳整個array給vb的參考啊...
    當然, 這個網頁亦對將來有幫助,例如放入structure 到dll裏:)



    2009年3月24日 上午 04:18
  • 心冷熱情熄的回覆
    我也知道這是手冊中的連結,
    是不是我沒有vb2008 ,所以找不到啊??
    2009年3月24日 上午 04:22
  • .....
    小人物一枚。
    2009年3月24日 上午 04:24
    版主
  • 小朱, 都感謝你, 你都幫了我很多啊...:)

    2009年3月24日 上午 04:38
  • 現在, 為免太煩複的情況發生
    小弟一個笨笨的方法, 正測試將一個array 回傳到vb...
    應該function都是int * function(){...}吧??
    那回傳到vb之後, 有甚麼比較簡單的方法拿取array??
    vb 的function declare應該是"intptr" 對嗎???

    各位,對不起..小弟程式能力不高...麻煩大家了....
    都在找方法, 但好像都只找到string array的回傳..
    那int array 呢??
    2009年3月24日 上午 05:42
  • 小弟實在太笨...
    看完了心冷熱情熄的回覆, 還是不太明白怎能在vc++裏傳送safearray到vb2005...
    在vc++裏就好像不太難.......對不起....可否再給小弟一些指示...
    2009年3月24日 上午 08:58
  • 先前給的連結:
    如何將 Visual Basic 的.NET 或 Visual Basic 2005 應用程式和 Visual C ++.NET] 或 [Visual C ++ 2005 函式之間傳遞的陣列: http://support.microsoft.com/kb/841293/zh-tw

    裡面有 int() 跟 safearray 的範例,也有 win32 跟 com 的範例。 

    前面說過:
    ms-help 起頭的網址,是你有安裝 MSDN for Visual Studio 線上手冊的位置,相同內容可在 msdn 或 msdn2 搜尋得到。

    這是一張獨立的 DVD ,安裝好要 2GB 的空間。VS2008 / VS2005 都有,不想安裝的話,msdn2 / msdn 有完整內容,只是找起來比較麻煩,你可以把標題丟到 google 去找。
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月24日 上午 09:09
  • 閣下的意思是, 要在vb2005 中拿到整個array, 都需要以safearray的方法來提取嗎???

    我已經安裝了線上手冊了,剛才copy閣下的連結到search裏面找, 忘記了自己的是2005 不是2008...
    還有...小弟的vs是英文版....所以都不能從vs裏面找到
    但谷歌已經看完了

    2009年3月24日 上午 09:38
  • 小弟看完了....
    但這都不是說明傳入array 到c++ dll裏嗎???
    是不是我不太清楚...好像看不到.....怎樣在vb 裏拿取array 的段落....啊.....><
    2009年3月24日 上午 10:08
  • 前面不是都說過了?

    大部分的 API 會設計成:
    參數([in/out]傳址呼叫的陣列, [in/out]傳址長度, [in/out]傳址型別)
    回傳:錯誤代碼

    所以基本上都是利用參數來傳遞陣列。既然使用了傳址呼叫,在 dll 端變更的內容,自然在呼叫端也會參照相同的內容,也是變更後的。看程式碼看懂,

    你可以嘗試用 SafeArray 來傳回陣列,但大部分不會這樣設計,因為這還包括 SafeArray 參照數的調整,以利 SafeArray 在使用完畢時,可以自動釋放記憶體。
    而考慮到呼叫端能妥善完整的維護,會讓呼叫端來宣告,呼叫端來刪除,避免在 dll 宣告而在乎叫端不能刪除。

    你一直執著於要傳回指標,但是這並不是建議的設計方式。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月24日 上午 10:44
  • 這就是我一直煩惱著的問題
    一言驚醒夢中人啊!!! 真的可以傳址地傳入那些變數....
    那我(希望) 的最後問題
    參數([in/out]傳址呼叫的陣列, [in/out]傳址長度, [in/out]傳址型別)
    這是c++那邊的宣告, 而vb 那邊都只要(by ref xxxx as integer(),...) 就可以吧??
    太感謝您的提醒了!!
    2009年3月25日 上午 01:55
  • ?

    所以先前說這篇先看:
    如何將 Visual Basic 的.NET 或 Visual Basic 2005 應用程式和 Visual C ++.NET] 或 [Visual C ++ 2005 函式之間傳遞的陣列: http://support.microsoft.com/kb/841293/zh-tw

    將陣列傳遞至 Win32 DLL 中的函式

    Private Declare Function SearchNum_Win32 Lib "C:\WinDll\MyWinDll\Debug\MyWinDll.dll" _
           (ByRef nums As Integer, ByVal count As Integer, ByVal searchNum As Integer) As Integer


    presult = SearchNum_Win32(nums(0), UBound(nums) + 1, searchNum)

    VB 是把陣列第一個位置傳進去,所以宣告不為 Integer()






    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月25日 上午 04:02
  • 剛踫到的問題, 要pass array 到dll 內,是否一定要safearray的方式傳入?
    剛剛小弟的function 裏, 在vb端傳入一個array, 但經過function後, 只傳回一個size 0 的array......
    2009年3月25日 上午 04:07
  • 如果你 .Net 想宣告為 As xxx() 的話,就要配合 SafeArray ,一般陣列如同前一篇回的,是藉由陣列第一個變數傳址呼叫來處理。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    • 已標示為解答 Eagles.Derek 2009年3月25日 上午 06:02
    2009年3月25日 上午 04:12
  • 果真是高手啊!!!!
    現在小弟可以傳送array到dll, 然後在dll 中跟據這個array 操作了!!!真的感謝啊!!!!!
    因為小弟原本的list都可算是放棄了...用笨笨的方法..將list寫到一個一維array 裏面.....
    要往後再想想以list的傳遞...
    但心冷熱情熄..(不知兄還是姐) 都最少幫了我解決array的問題...
    現在是傳入hashtable和string的測試了....

    • 已標示為解答 Eagles.Derek 2009年3月25日 上午 06:02
    • 已取消標示為解答 Eagles.Derek 2009年3月25日 上午 06:02
    2009年3月25日 上午 04:34
  • 結構的部分,把這篇看一下:
    http://tlcheng.spaces.live.com/blog/cns!145419920BFD55A7!1012.entry


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月25日 上午 06:29
  • 先感謝
    正在找尋string 在dll之間的傳送
    完成後再找結構的東西
    那時再問閣下問題
    萬分感謝啊....
    2009年3月25日 上午 07:28
  • 傳送string都是要一點技巧的嗎???
    為甚麼我在加了std::string, 或者char * 都那個c++ function的是候, build 沒有問題,但到vb 傳召時, 會出這個error??
    Unable to find an entry point named 'functio_nname' in DLL 'check.dll'.
    我嘗試過移除string , 只像之前般傳入array, 切正常啊....
    真迷惘...
    2009年3月25日 上午 07:51
  • string 是最複雜的...

    先看一個簡例,這邊雖然講的是 VB6 升級自動轉換 VBNET 程式碼錯誤,但同時包含 VC / VB6 / VBNET 的部分:
    當 BUG: ByValTStr 屬性不正確時套用至固定長度字串成員您升級至 Visual Basic.NET 專案的 Visual Basic 6.0 專案: http://support.microsoft.com/kb/834056/zh-tw

    再看一個 VBNET 使用 String / StringBuilder 的差別:
    字串,您將傳遞至 Unmanaged Win32 API 在 Visual Studio.NET 或 Visual Studio 2005 中傳回空的: http://support.microsoft.com/kb/321078/zh-tw 

    回頭看線上手冊觀念

    注意哪種字串型別可以兩邊傳,我是覺得這編寫的有點怪,因為基本上是都可以,只是怎樣接、複不複雜、能不能定址、要不要做轉碼等。
    從 Managed 程式碼呼叫原生函式: ms-help://MS.MSDNQTR.v90.cht/dv_vccore/html/982cef18-20d9-42b4-8242-a77fa65f2e36.htm

    升級建議:調整 Win32 API 的資料型別: ms-help://MS.MSDNQTR.v90.cht/dv_vbvers/html/63613537-54a4-4aa7-a789-c1d5ff9cb210.htm
    逐步解說:呼叫 Windows API: ms-help://MS.MSDNQTR.v90.cht/dv_vbalr/html/9280ca96-7a93-47a3-8d01-6d01be0657cb.htm
    互通性的疑難排解: ms-help://MS.MSDNQTR.v90.cht/dv_vbalr/html/b324cc1e-b03c-4f39-aea6-6a6d5bfd0e37.htm
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月25日 上午 08:23
  • 這個的確有難度
    但小弟不太明白, 為甚麼要以string builder define 一個固定長度的" ",. 然後再將一個integer數值放進dll 裏?
    小弟的一個測試case:
    在vb裏: dim abc as string = "gfedcaba"
    應該new一個string builder ,再傳入abc的長度
    然後c++裏, 以std::string 來接收??還是char *???

    2009年3月26日 上午 03:02
  • 前面說過,避免在 DLL 宣告,多在原應用程式宣告。

    用一個長度來定義,就是要處理 Alloc 這塊。

    此外,.Net 在這部分繼承 VB6 使用類似 Vairnat String ,所以記憶體模型跟過去的 VC 都不同,比如說定長度字串已經拿掉了,當在 dll 使用定長度字串時,.Net 這邊就要繞路走。

    此外還要考慮到自動封裝遞送時,是包裝成 ANSI 還是 Unicode ,要正確對應才不會需要轉碼,所以呼叫 API 時,字串在 .Net 中是最難搞的,什麼時候用 String ,什麼時候用 StringBuilder ... 測了才知道,有時是兩個都可以。如果考慮到直接傳輸 unicode ,那就是用 wchar 接,一般可以用 char ,那是不是可以直接用 SysAllocString ,這個我沒試過,除了檔名外,我很少把字串往 dll 送,所以我以前再做的時候,都是簡單的有限長度字串而已。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月26日 上午 03:25
  • 哪您的意思是
    我在c++的function裏不能只define std::string?
    還要在裏面行new/malloc 來預設位置給這個傳入的string, 然後再以這個輪入這個string?
    在vb裏, 需要define function為 function(byref abc as string/stringbuilder, byval len as integer)
    這樣對嗎?
    不知道c++裏以甚麼形式去接收這個vb傳入來的string...
    好像之前的int array pass by ref, 可以嗎??
    2009年3月26日 上午 03:34
  • ...

    這樣搜尋你可以看到很多範例,配合先前的觀念:
    http://www.google.com.tw/search?hl=zh-TW&q=vb+vc+dllexport+dllimport+string&meta=&aq=f&oq=
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年3月26日 上午 08:56