简体   繁体   English

编组结构到单行字符串

[英]Marshaling structure to single line of 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));
}

I can create object from single line of string but I can not do opposite of that. 我可以从字符串的单行创建对象,但不能做相反的事情。

How can I do that operation? 我该怎么做?

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

It throws exception "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." 它将引发异常“尝试读取或写入受保护的内存。这通常表明其他内存已损坏。”

int size = Marshal.SizeOf(comarea);
IntPtr pBuf = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(comarea, pBuf, false);
buffer = Marshal.PtrToStringBSTR(pBuf); //Error
[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;
}

That is laid out as 6 adjacent 16 bit wchar_t character elements. 布局为6个相邻的16位wchar_t字符元素。 So, right off the bat, 所以,马上

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

is wrong. 是错的。 Beyond the fact that you leak a BSTR , your struct is not a BSTR . 除了泄漏BSTR ,您的结构也不是BSTR

You can implement it like this: 您可以这样实现:

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

This is under the assumption that the six characters are the contained the the locations implied by the Substring calls. 这是在假定六个字符包含在Substring调用隐含的位置的假设下的。

In the opposite direction you write: 在相反的方向上,您可以这样写:

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

Note that the struct definition must be wrong however 注意,结构定义一定是错误的

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

The marshaller always adds a null-terminator when using ByValTStr . 使用ByValTStr时,编组器始终添加一个空终止ByValTStr So with SizeConst of 1 , status will always be marshaled as an empty string. 因此,如果SizeConst1 ,则状态将始终封送为空字符串。 Without actually seeing the unmanaged struct definition, I would not care to tell you how to fix this problem. 在没有真正看到非托管结构定义的情况下,我不会在乎告诉您如何解决此问题。

That is how I solved my problem: I used char array and Marshal.PtrToStringAuto(pBuf, size) 那就是我解决问题的方式:我使用了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;
        }
    }
}

It is so useful for IBM CICS communication(For Commarea) 这对于IBM CICS通信非常有用(对于Commarea)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM