簡體   English   中英

使用C#從IntPtr復制字節數組與Marshal.Copy不起作用

[英]Copying byte array with Marshal.Copy from IntPtr using C# doesn't work

我正在使用一個非托管庫,它可以生成灰度圖像(大約100x200像素,或多或少)。 圖像包含在結構中,在C中如下所示:

typedef struct abs_image {
    ABS_DWORD Width;
    ABS_DWORD Height;
    ABS_DWORD ColorCount;
    ABS_DWORD HorizontalDPI;
    ABS_DWORD VerticalDPI;
    ABS_BYTE ImageData[ABS_VARLEN];
} ABS_IMAGE
typedef unsigned int     ABS_DWORD;
typedef unsigned char     ABS_BYTE;

在這里我的C#包裝器結構:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct ABS_IMAGE {
    public uint Width;
    public uint Height;
    public uint ColorCount;
    public uint HorizontalDPI;
    public uint VerticalDPI;
    public IntPtr ImageData;
}

ABS_IMAGE圖像並對ABS_IMAGE結構進行編組可以正常工作。 在以前的版本中,我嘗試使用固定長度的字節數組用於ImageData,有時會崩潰。 我想這發生了,因為圖像尺寸沒有修復。 現在我嘗試在以后讀取圖像字節數組,之后我可以計算實際的數組長度。 這里有相關代碼:

ABS_Type_Defs.ABS_IMAGE img =
    (ABS_Type_Defs.ABS_IMAGE)Marshal.PtrToStructure(
    pImage,
    typeof(ABS_Type_Defs.ABS_IMAGE));

int length = ((int)img.Height - 1) * ((int)img.Width - 1);
byte[] data = new byte[length];

Marshal.Copy(img.ImageData, data, 0, length);

現在我的問題:每次我想執行Marshal.Copy讀取圖像字節時,我得到一個AccessViolationException

有沒有人有想法?

這就是正在發生的事情。 您的結構是所謂的可變長度結構。 像素數據在結構中包含內聯,從ImageData的偏移量開始。

typedef struct abs_image {
    ABS_DWORD Width;
    ABS_DWORD Height;
    ABS_DWORD ColorCount;
    ABS_DWORD HorizontalDPI;
    ABS_DWORD VerticalDPI;
    ABS_BYTE ImageData[ABS_VARLEN];
} ABS_IMAGE

您的API返回pImage ,它是一個IntPtr ,指向ABS_IMAGE類型的非托管數據。 但是,如果查看本機代碼,則會看到ABS_VARLEN等於1 這是因為必須在編譯時靜態定義struct 實際上,像素數據的長度由高度,寬度和顏色計數字段確定。

您可以繼續使用Marshal.PtrToStructure來獲取大多數字段。 但是你無法以這種方式獲得ImageData字段。 這需要更多的工作。

相反地​​聲明這樣的結構:

[StructLayout(LayoutKind.Sequential)]
public struct ABS_IMAGE {
    public uint Width;
    public uint Height;
    public uint ColorCount;
    public uint HorizontalDPI;
    public uint VerticalDPI;
    public byte ImageData;
}

當您需要獲取圖像數據時,請執行以下操作:

IntPtr ImageData = pImage + Marshal.OffsetOf(typeof(ABS_IMAGE), "ImageData");
Marshal.Copy(ImageData, data, 0, length);

如果您尚未使用.net 4,則需要進行轉換以進行算術編譯:

IntPtr ImageData = (IntPtr) (pImage.ToInt64() + 
    Marshal.OffsetOf(typeof(ABS_IMAGE), "ImageData").ToInt64());

最后,我認為你的計算length不正確。 當然你需要使用Height*Width 你還沒有考慮顏色深度。 例如,32位顏色將是每像素4個字節。

暫無
暫無

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

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