English 中文(简体)
Trouble with marsal.PtrToStructure() and char ranges in structure DEVERODE
原标题:Trouble with Marshal.PtrToStructure() and char arrays in structure DEVMODE

我对使用沼泽地有问题。 Ptr ToStructure()从一个点子中提取数据,以建立DEVERODE。 http://msdn.microsoft.com/en-us/library/dd183528v=vs.85%29.aspx” rel=“noreferer”>Here 与DEVERODE结构的MSDN条目链接。

我的C#执行计划如下:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DEVMODE
{
    public const int CCHDEVICENAME = 32;
    public const int CCHFORMNAME = 32;

    public unsafe fixed char dmDeviceName [CCHDEVICENAME];
    public Int16 dmSpecVersion;
    public Int16 dmDriverVersion;
    public Int16 dmSize;
    public Int16 dmDriverExtra;
    public DM_FIELD_TYPE dmFields;

    public Int16 dmOrientation;
    public Int16 dmPaperSize;
    public Int16 dmPaperLength;
    public Int16 dmPaperWidth;
    public Int16 dmScale;
    public Int16 dmCopies;
    public Int16 dmDefaultSource;
    public Int16 dmPrintQuality;

    public POINTL dmPosition;
    public Int32 dmDisplayOrientation;
    public Int32 dmDisplayFixedOutput;

    public short dmColor;
    public short dmDuplex;
    public short dmYResolution;
    public short dmTTOption;
    public short dmCollate;

    public unsafe fixed char dmFormName [CCHFORMNAME];
    public Int16 dmLogPixels;
    public Int32 dmBitsPerPel;
    public Int32 dmPelsWidth;
    public Int32 dmPelsHeight;
    public Int32 dmDisplayFlags;
    public Int32 dmNup;
    public Int32 dmDisplayFrequency;
    public Int32 dmICMMethod;
    public Int32 dmICMIntent;
    public Int32 dmMediaType;
    public Int32 dmDitherType;
    public Int32 dmReserved1;
    public Int32 dmReserved2;
    public Int32 dmPanningWidth;
    public Int32 dmPanningHeight;

    public DEVMODE(byte[] data)
    {
        unsafe
        {
            fixed (byte* packet = &data[0])
            {
                this = *(DEVMODE*)packet;
            }
        }
    }

}

[Flags()]
public enum DM_FIELD_TYPE : int
{
    /* field selection bits */
    DM_ORIENTATION          = 0x00000001,
    DM_PAPERSIZE            = 0x00000002,
    DM_PAPERLENGTH          = 0x00000004,
    DM_PAPERWIDTH           = 0x00000008,
    DM_SCALE                = 0x00000010,
    DM_POSITION             = 0x00000020,
    DM_NUP                  = 0x00000040,
    DM_DISPLAYORIENTATION   = 0x00000080,
    DM_COPIES               = 0x00000100,
    DM_DEFAULTSOURCE        = 0x00000200,
    DM_PRINTQUALITY         = 0x00000400,
    DM_COLOR                = 0x00000800,
    DM_DUPLEX               = 0x00001000,
    DM_YRESOLUTION          = 0x00002000,
    DM_TTOPTION             = 0x00004000,
    DM_COLLATE              = 0x00008000,
    DM_FORMNAME             = 0x00010000,
    DM_LOGPIXELS            = 0x00020000,
    DM_BITSPERPEL           = 0x00040000,
    DM_PELSWIDTH            = 0x00080000,
    DM_PELSHEIGHT           = 0x00100000,
    DM_DISPLAYFLAGS         = 0x00200000,
    DM_DISPLAYFREQUENCY     = 0x00400000,
    DM_ICMMETHOD            = 0x00800000,
    DM_ICMINTENT            = 0x01000000,
    DM_MEDIATYPE            = 0x02000000,
    DM_DITHERTYPE           = 0x04000000,
    DM_PANNINGWIDTH         = 0x08000000,
    DM_PANNINGHEIGHT        = 0x10000000,
    DM_DISPLAYFIXEDOUTPUT   = 0x20000000
}

public struct POINTL
{
    public Int32 x;
    public Int32 y;
}

在这种结构中,有2个特性阵列“dmDeviceName”和“dmFormName”。 两者都是32个长期性的。 问题在于,当我试图从某个点清除DEVERODE的结构时,这些特性阵列并没有得到适当的填补。 例如,dmDeviceName只具有实际装置名称的头等特性。 其余部分将只是。 正在穿透的Im法线如下:

DEVMODE devMode = (DEVMODE)Marshal.PtrToStructure(aData[i].NotifyData.Data.pBuf, typeof(DEVMODE));

“aData[i]。 通知Data.Data.pBuf”是DEVODE结构的一个有效点。 出于两个原因,我知道这一点。

  1. 这一结构是一家名为FindNextPrinterChangeNoification(FindNextPrinterChangeNoification)的打印机驾驶员报送的一组信息。 我利用这一手段获取印刷工作信息,当我掌握印刷工作并利用上述法律来清除DEVERODE的标语时,“影印本”领域总是与该工作印刷的份数完全正确。 因此,在结构中的第12名成员似乎在结构中的某些成员似乎不在场时,如何正确打碎了脚。

  2. I used Marshal.ReadByte() to forcibly read the first 100 bytes that aData[i].NotifyData.Data.pBuf was pointing to, and sure enough, the first collection of bytes were the full exact name of the printer device. So I know the information is there.

出于任何原因,当我使用沼泽地时。 Ptr ToStructure(PtrToStructure)似乎能够正确填写特征表。 我确信,大多数其他变量是正确的,但我怀疑,因为存在问题。 任何人都知道这里的情况。

--EDIT -- As requested, here is the code that populates the aData[] array:

private PRINTER_NOTIFY_INFO_DATA[] MarshalOutPrinterNotifyInfoDataArray(IntPtr ppPrinterNotifyInfo)
{
    //Dereferencing ppPrinterNotifyInfo and setting NotifyInfoStruct to it.
    PRINTER_NOTIFY_INFO NotifyInfoStruct = (PRINTER_NOTIFY_INFO)Marshal.PtrToStructure(ppPrinterNotifyInfo, typeof(PRINTER_NOTIFY_INFO));

    //Creating a point to point to the PRINTER_NOTIFY_INFO and then moving it to the end of the structure where the
    //aData[] member would begin.
    int paData = (int)ppPrinterNotifyInfo + Marshal.SizeOf(typeof(PRINTER_NOTIFY_INFO));

    //Creating an array to hold all the elements of our aData array.
    PRINTER_NOTIFY_INFO_DATA[] data = new PRINTER_NOTIFY_INFO_DATA[NotifyInfoStruct.Count];

    //looping through all the PRINTER_NOTIFY_INFO_DATA elments in the aData member and adding them to our local array.
    for (uint i = 0; i < NotifyInfoStruct.Count; i++)
    {
        //extracting out a single PRINTER_NOTIFY_INFO_DATA item and storing it in our local array
        data[i] = (PRINTER_NOTIFY_INFO_DATA)Marshal.PtrToStructure((IntPtr)paData, typeof(PRINTER_NOTIFY_INFO_DATA));

        //moving our pointer to the next PRINTER_NOTIFY_INFO_DATA item
        paData += Marshal.SizeOf(typeof(PRINTER_NOTIFY_INFO_DATA));
    }

    return data;
}



private void SomeRoutine()
{
    //////////////////
    /// some code here
    //////////////////

    //retrieving information about the most recent change notification for a change notification object associated with the printer
    FindNextPrinterChangeNotification(m_ManualResetEvent.SafeWaitHandle.DangerousGetHandle(), out pdwChangeFlags, null, out ppPrinterNotifyInfo);

    //Need to extract our PRINTER_NOTIFY_INFO_DATA array out of the PRINTER_NOTIFY_INFO structure
    PRINTER_NOTIFY_INFO_DATA[] aData = MarshalOutPrinterNotifyInfoDataArray(ppPrinterNotifyInfo);

    //////////////////
    /// some code here
    //////////////////
}
最佳回答

Use a string:

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
public string dmDeviceName;

见:。 http://pinvoke.net/default.aspx/Structures/DEVMODE.html

EDIT: I didn t notice when posting my quick response since I was focusing on the strings (and there is one at the very beginning of the struct, meaning that the rest of the struct elements can t affect things), but as others have pointed out you have a big problem with the unions in the DEVMODE structure. Elements in a union do not lie sequentially but rather occupy the same space in memory: only one of the union elements may be used at a time. For example:

union {
    DWORD dmDisplayFlags;
    DWORD dmNup;
};

means that dmDisplayFlags and dmNup are essentially different names for the same block of memory. I.e. dmDisplayFlags and dmNup are both stored at an offset of 116 bytes from the beginning of the structure. Changing dmNup causes the value of dmDisplayFlags to also change, and vice versa. Using C# code like:

public Int32 dmDisplayFlags;
public Int32 dmNup;

means that they get stored sequentially, i.e. at offsets 116 and 120. That upsets the layout of the entire structure. To fix that, you need to use an explicit layout and manually define the field offsets. Look at the link I previously gave at pinvoke.net for an example of how to do that on this particular structure. Notice how dmDisplayFlags and dmNup have the same field offset. Since C# doesn t natively support unions, this is a somewhat-clumsy way to handle unions for those special interop scenarios like this one that require it.

我建议确定你们的工会问题,然后按照原建议,使用ByValTStr的扼杀(概括地说,使用pin子。 如果能取得更好的结果,请见。

其他人则认为这是一个统法协会的问题,但我并不认为是这样。 统法协会没有FindNextPrinterChange 通知。 如果你逐级审查结构,说它不是统法协会,我肯定会相信你。

From the docs:

"ByValTStr: Used for in-line, fixed-length character arrays that appear within a structure. The character type used with ByValTStr is determined by the System.Runtime.InteropServices.CharSet argument of the System.Runtime.InteropServices.StructLayoutAttribute applied to the containing structure. Always use the MarshalAsAttribute.SizeConst field to indicate the size of the array.

。 NET Framework ByVal 施特类在结构内如C型、固定型体内(例如,char[5])。 管理守则中的行为不同于微软视像素基本6行为,但这种行为没有终止(例如,我String As String* 5)。

我很明白,这应该是普遍接受的“正确”做法。

问题回答

暂无回答




相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签