簡體   English   中英

.NET Interop:如何從C#中的非托管DLL獲取返回的字符串(非null終止)

[英].NET Interop: How to get returned string (not null terminated) from unmanaged DLL in C#

我在C DLL庫中定義了一個函數。

__declspec(dllexport) void* GetText();

它將返回一個從堆內存動態分配的字符串(並且GlobalAlloc在這里用於分配內存)。 請注意,返回的字符串不是 null終止的


然后在C#端,我嘗試了兩種方法來聲明該函數

[DllImport("D:\\ca\\TextAccessLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
static extern String GetText();

調用上述方法時,應用程序將崩潰而不會引發任何異常。

[DllImport("D:\\ca\\TextAccessLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr GetText();

ptr = GetText();
string text = Marshal.PtrToStringAuto(ptr, 1000);

並調用此方法將返回不正確的字符串。 通過使用Marshal.Copy檢查實際字節,我發現字節值與DLL庫中的值不同。 (我認為這是由虛擬內存引起的,C#進程無法直接訪問DLL的內存空間)

(不要介意字符串的長度,為方便起見,我將其硬編碼為1000)


這是調試時的C ++代碼和字符串的內存值(這是一個控制台應用程序,而不是原始DLL,因為控制台應用程序易於調試。但是DLL代碼與該代碼相同,除了日志記錄部分之外)。 在此處輸入圖片說明 以下是原始的DLL代碼

__declspec(dllexport) char* GetText(){
    VTHDOC hDoc = NULL;
    VTHTEXT hText = VTHDOC_INVALID;
    DAERR da_err = NULL;
    DAERR ta_err = NULL;
    DAERR read_err = NULL;
    char *buf = (char*)GlobalAlloc(GMEM_FIXED, 1000);
    DWORD real_size;


    DAInitEx(SCCOPT_INIT_NOTHREADS, OI_INIT_DEFAULT);
    da_err = DAOpenDocument(&hDoc, 2, "D:\\1TB.doc", 0);
    ta_err = TAOpenText(hDoc, &hText);
    read_err = TAReadFirst(hText, (VTLPBYTE)buf, 1000, &real_size);

    return buf;
}

但是在C#端,字節與C ++端不相同 在此處輸入圖片說明

您可以看到C ++中的第一個字節為0,但對於C#(十進制)為200


需要注意的另一件事:如果我直接在DLL代碼中返回一個const字符串(例如“ AASSDD”),則C#端將獲取正確的字符串

你不能那樣做。 string封送處理僅適用於以null終止的字符串(如果指定了某些選項,則適用於BSTR)。 您可以:

[DllImport("D:\\ca\\TextAccessLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr GetText();

但是從那里開始,尚不清楚C#程序應如何知道字符串的長度。

C#的各種Marshal方法處理BSTR(內部具有其長度)或NUL終止的字符串。

如前所述,它僅適用於以null終止的字符串,其方式如下:

C#部分,聲明:

[DllImport("myDll.dll", EntryPoint = "myString", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
extern private static string myString(out int size);

C#部分,用法:

        int size;
        string s = myString(out size);

C ++部分:

char* myString(int* size)
{
    *size = 20;
    char* strg = (char*)::GlobalAlloc(GMEM_FIXED, *size);
    memset(strg, 0x3f, *size); //preset with a questionmark
    for (int i=0; i < 9; i++)
        strg[i] = 0x40 + i;
    strg[*size -1] = 0; //limit the maximum string length
    return strg;
}

以及獲得的C#字符串:“ @ ABCDEFGH ??????????”,大小值:20

這里可以找到該問題的處理方法

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM