封尾结构为单线串

时间:2014-07-11 12:30:43

标签: c# structure marshalling unmarshalling object-to-string

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class Comarea
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
    public string status;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
    public string operationName;
}

public static void StringToObject(string buffer, out Comarea comarea)
{
    IntPtr pBuf = Marshal.StringToBSTR(buffer);
    comarea = (Comarea)Marshal.PtrToStructure(pBuf, typeof(Comarea));
}

我可以从单行字符串创建对象,但我不能这样做。

我该怎么做?

public static void ObjectToString(out string buffer, Comarea comarea)
{
     ???
}

它抛出异常"尝试读取或写入受保护的内存。这通常表明其他内存已损坏。"

int size = Marshal.SizeOf(comarea);
IntPtr pBuf = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(comarea, pBuf, false);
buffer = Marshal.PtrToStringBSTR(pBuf); //Error

2 个答案:

答案 0 :(得分:1)

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class Comarea
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
    public string status;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
    public string operationName;
}

它被列为6个相邻的16位wchar_t字符元素。所以,马上,

public static void StringToObject(string buffer, out Comarea comarea)
{
    IntPtr pBuf = Marshal.StringToBSTR(buffer);
    comarea = (Comarea)Marshal.PtrToStructure(pBuf, typeof(Comarea));
}

错了。除了泄漏BSTR之外,您的结构不是BSTR

您可以像这样实现:

public static void StringToObject(string buffer, out Comarea comarea)
{
    comarea.status = buffer.Substring(0, 1);
    comarea.operationName = buffer.Substring(1, 5);
}

这是假设六个字符包含Substring次调用隐含的位置。

你写的是相反的方向:

public static void ObjectToString(out string buffer, Comarea comarea)
{
     buffer = comarea.status + comarea.operationName;
}

请注意,结构定义必须是错误的

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
public string status;

使用ByValTStr时,编组程序总是添加一个空终止符。因此,对于SizeConst 1,状态将始终被封送为空字符串。如果没有实际看到非托管结构定义,我不会告诉你如何解决这个问题。

答案 1 :(得分:0)

这就是我解决问题的方法:我使用了char数组和Marshal.PtrToStringAuto(pBuf, size)

public static void ObjectToString(out string buffer, Comarea comarea)
{
    int size = 0;
    IntPtr pBuf = IntPtr.Zero;

    try
    {
        size = Marshal.SizeOf(comarea);
        pBuf = Marshal.AllocHGlobal(size);
        Marshal.StructureToPtr(comarea, pBuf, false);
        buffer = Marshal.PtrToStringAuto(pBuf, size).Substring(0, size/2); // Answer
    }
    catch
    {
        throw;
    }
    finally
    {
        Marshal.FreeHGlobal(pBuf);
    }
}





[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct Comarea
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
    private char[] status;

    public string Status
    {
        get
        {
            return new string(status);
        }

        set
        {
            status = value.ToFixedCharArray(1);
        }
    }

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
    private char[] operationName;

    public string OperationName
    {
        get
        {
            return new string(operationName);
        }

        set
        {
            operationName = value.ToFixedCharArray(5);
        }
    }
}



public static class FormatterExtensions
{
    [DebuggerStepThrough]
    public static char[] ToFixedCharArray(this string inputString, int arrayLength)
    {
        char[] outputArray = new char[arrayLength];
        char[] inputArray = inputString.ToSafeTrim().ToCharArray();

        if (inputArray.Length == arrayLength)
        {
            return inputArray;
        }
        else
        {
            int i = 0;

            while (i < arrayLength)
            {
                if (i < inputArray.Length)
                {
                    outputArray[i] = inputArray[i];
                }
                else
                {
                    break;
                }

                i++;
            }

            return outputArray;
        }
    }
}

它对IBM CICS通信(For Commarea)非常有用