gpt4 book ai didi

c# - 通过引用传递到非托管 C DLL 函数后,结构保持不变

转载 作者:行者123 更新时间:2023-11-30 22:03:59 38 4
gpt4 key购买 nike

我正在用 C# 为非托管 C DLL 编写包装器。在 DLL 中,我有以下方法返回指针结构(帖​​子结尾附近的结构代码):

struct zint_symbol *ZBarcode_Create()
{
struct zint_symbol *symbol = (struct zint_symbol*)calloc(1, sizeof(struct zint_symbol));

if (!symbol) return NULL;

symbol->symbology = BARCODE_CODE128;
strcpy(symbol->fgcolour, "000000");
strcpy(symbol->bgcolour, "ffffff");
strcpy(symbol->outfile, "out.png");
symbol->scale = 1.0;
symbol->option_1 = -1;
symbol->option_3 = 928; // PDF_MAX
symbol->show_hrt = 1; // Show human readable text
return symbol;
}

我使用的外部方法是:

extern struct zint_symbol* ZBarcode_Create(void);
extern int ZBarcode_Encode_and_Buffer(struct zint_symbol *symbol, unsigned char *input, int length, int rotate_angle);
extern int ZBarcode_Encode_and_Print(struct zint_symbol *symbol, unsigned char *input, int length, int rotate_angle);

ZBarcode_Encode_and_Buffer 渲染图像并将位图保存在我的结构中名为 bitmap 的变量中。ZBarcode_Encode_and_Print 呈现图像并将其保存到文件系统。它们都在成功时返回 0,在失败时返回 1-8 之间的数字。每次对我来说,他们都返回 0。

我的 C# 如下所示:

[DllImport("zint.dll", EntryPoint = "ZBarcode_Create", CallingConvention = CallingConvention.Cdecl)]
public extern static IntPtr Create();

[DllImport("zint.dll", EntryPoint = "ZBarcode_Encode_and_Buffer", CallingConvention = CallingConvention.Cdecl)]
public extern static int EncodeAndBuffer(
ref zint_symbol symbol,
string input,
int length,
int rotate_angle);

[DllImport("zint.dll", EntryPoint = "ZBarcode_Encode_and_Print", CallingConvention = CallingConvention.Cdecl)]
public extern static int EncodeAndPrint(
ref zint_symbol symbol,
string input,
int length,
int rotate_angle);

public static void Render()
{
// call DLL function to generate pointer to initialized struct
zint_symbol s = (zint_symbol)

// generate managed counterpart of struct
Marshal.PtrToStructure(ZintLib.Create(), typeof(zint_symbol));

// change some settings
s.symbology = 71;
s.outfile = "baro.png";
s.text = "12345";

String str = "12345";

// DLL function call to generate output file using changed settings -- DOES NOT WORK --
System.Console.WriteLine(ZintLib.EncodeAndBuffer(ref s, str, str.Length, 0));

// DLL function call to generate output file using changed settings -- WORKS --
System.Console.WriteLine(ZintLib.EncodeAndPrint(ref s, str, str.Length, 0));

// notice that these variables are set in ZBarcode_Create()?
Console.WriteLine("bgcolor=" + s.bgcolour + ", fgcolor=" + s.fgcolour + ", outfile=" + s.outfile);

// these variables maintain the same values as when they were written to in ZBarcode_Create().
if (s.errtxt != null)
Console.WriteLine("Error: " + s.errtxt);
else
Console.WriteLine("Image size rendered: " + s.bitmap_width + " x " + s.bitmap_height);
}

s 中的所有变量保持不变,即使 DLL 应该更改其中的一些变量,例如 bitmapbitmap_width, bitmap_height

我怀疑内存中有两份zint_symbol;一个是我的 C# 代码(由 ZintLib.Create() 创建)和DLL 正在写入的另一个。不过,我确定该库可以正常工作。

C 结构体:

struct zint_symbol {
int symbology;
int height;
int whitespace_width;
int border_width;
int output_options;
#define ZINT_COLOUR_SIZE 10
char fgcolour[ZINT_COLOUR_SIZE];
char bgcolour[ZINT_COLOUR_SIZE];
char outfile[FILENAME_MAX];
float scale;
int option_1;
int option_2;
int option_3;
int show_hrt;
int input_mode;
#define ZINT_TEXT_SIZE 128
unsigned char text[ZINT_TEXT_SIZE];
int rows;
int width;
#define ZINT_PRIMARY_SIZE 128
char primary[ZINT_PRIMARY_SIZE];
#define ZINT_ROWS_MAX 178
#define ZINT_COLS_MAX 178
unsigned char encoded_data[ZINT_ROWS_MAX][ZINT_COLS_MAX];
int row_height[ZINT_ROWS_MAX]; /* Largest symbol is 177x177 QR Code */
#define ZINT_ERR_SIZE 100
char errtxt[ZINT_ERR_SIZE];
char *bitmap;
int bitmap_width;
int bitmap_height;
struct zint_render *rendered;
};

C# 结构:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct zint_symbol
{
public int symbology;
public int height;
public int whitespace_width;
public int border_width;
public int output_options;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public String fgcolour;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public String bgcolour;


[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string errtxt;

public float scale;

public int option_1;
public int option_2;
public int option_3;
public int show_hrt;
public int input_mode;
public int rows;
public int width;
public int bitmap_width;
public int bitmap_height;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string text;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string primary;

[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 31684)]
public byte[] encoded_data;

[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I4, SizeConst = 178)]
public int[] row_height;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string outfile;

public IntPtr bitmap;
public IntPtr rendered;
}

我写了一个小Windows forms example (DLL 和 available here 都在里面。库文档(第 18/61 页解释了结构变量)is available here 和整个 C 源代码可用 here (zint-2.4.3.tar.gz)。特别感兴趣的文件是 zint.h,库.c 和datamatrix.c。C 源代码是相同版本的DLL。

编辑

结构布局似乎不匹配。 C# 中的 sizeof(zint_symbol) != C# 中的 sizeof(zint_symbol)。

最佳答案

你在这里犯了一个奇怪的错误:

[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 25454)]
public byte[] encoded_data;

.h 文件中的内容是:

#define ZINT_ROWS_MAX 178
#define ZINT_COLS_MAX 178
uint8_t encoded_data[ZINT_ROWS_MAX][ZINT_COLS_MAX];

以同样的方式声明即可:

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 178 * 178)]
public byte[] encoded_data;

还有一个错误,FILENAME_MAX 是 260:

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string outfile;

现在你应该得到一个正确的匹配:

static void Main(string[] args) {
var len = Marshal.SizeOf(typeof(zint_symbol)); // 33100
var offs = Marshal.OffsetOf(typeof(zint_symbol), "errtxt"); // 32984
}

在C测试程序中:

#include <stddef.h>
//...
int main()
{
size_t len = sizeof(zint_symbol); // 33100
size_t offs = offsetof(zint_symbol, errtxt); // 32984
return 0;
}

关于c# - 通过引用传递到非托管 C DLL 函数后,结构保持不变,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25586914/

38 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com