You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从C#向C++ DLL传递结构体?激光设备控制器调用场景

Solution for Passing C++ Struct Array to DLL via C# P/Invoke

Hey there, let's work through this P/Invoke problem step by step to get your SendFrame call working correctly. The core challenge here is matching the C++ struct's memory layout exactly and setting up the DllImport to handle the struct array parameter properly.

Step 1: Define the C# Equivalent of LaserPoint

Since the C++ struct uses #pragma pack(1) to disable automatic memory padding between fields, we need to replicate that strict layout in C#. Each field must map directly to the C++ type:

  • WORD x → C# ushort (16-bit unsigned integer)
  • WORD y → C# ushort
  • byte colors[6] → C# byte[6] (marked as an embedded fixed-size array)

Here's the correct struct definition:

using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct LaserPoint
{
    public ushort x;
    public ushort y;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    public byte[] colors;
}

The MarshalAs attribute for colors ensures the array is embedded directly in the struct (not a reference), just like the C++ fixed-size array.

Step 2: Correctly Import the SendFrame Function

Next, we need to set up the DllImport to handle the struct array parameter. In C++, byte* pData points to an array of LaserPoint structs—C# can automatically marshal a managed array of our LaserPoint structs to this unmanaged pointer if we configure the attributes right.

Full import code:

[DllImport("YourLaserDevice.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int SendFrame(
    uint deviceIndex,
    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] LaserPoint[] pData,
    uint numOfPoints,
    uint scanrate
);
  • CallingConvention.Cdecl: Critical because extern "C" functions default to cdecl (use StdCall instead if your DLL explicitly uses that convention).
  • SizeParamIndex = 2: Tells the marshaler that the numOfPoints parameter (zero-indexed at 2) specifies the length of the pData array—this prevents buffer overflows and ensures correct data marshaling.

Step 3: Call the Function from C#

Once the struct and import are set up, you can create an array of LaserPoint, populate it, and call the DLL function:

// Example usage: Create and populate 5 laser points
var points = new LaserPoint[5];

// Populate first point (red color)
points[0].x = 100;
points[0].y = 200;
points[0].colors = new byte[] { 255, 0, 0, 0, 0, 0 };

// Populate other points as needed...

// Call the DLL function
int result = SendFrame(0, points, (uint)points.Length, 1000);

// Check result (refer to your DLL's documentation for error codes)
if (result != 0)
{
    // Handle error scenario
}

Key Pitfalls to Avoid

  • Never skip Pack = 1: Without this, C# will add padding between struct fields, which will mismatch the C++ struct's layout and cause corrupted data.
  • Match array length to numOfPoints: Always ensure the length of pData exactly matches the value passed to numOfPoints.
  • DLL path: Make sure your DLL is in the application's working directory, or provide the full absolute path in the DllImport string (e.g., @"C:\LaserDevice\YourLaserDevice.dll").

内容的提问来源于stack exchange,提问作者salocinx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:24:09