Six_Rabbit 2024-11-18 17:27 采纳率: 0%
浏览 26
已结题

将Intptr传入SetHdevmode()将Intptr传入后转换为DEVMODE的值与外部代码不一致

请勿使用AIGC类型回答,鄙人会用AI;AIGC类型回答一律不采纳;不要™用AIGC回答
这个问题已近困扰了我快一个月,每次都是爬虫回答我的问题,搞得我有些愤怒,不要使用ChatGPT回答我的问题,我会用CharGPT;

问题简述:我是用GlobalAlloc()和GlobalLock()进行内存操作之后,在Intptr传入SetHdevmode()之后导致DEVMODE参数与外部的DEVMODE结构体值不同;

目前已经解决,发现SetHdevmode()没有办法有效的修改额外参数的值,打算使用C++写dll提供C#调用

代码如下:

[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
    const int CCHDEVICENAME  = (32 * 2);
    const int CCHFORMNAME = (32 * 2);

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
    public string dmDeviceName;
    public short dmSpecVersion;
    public short dmDriverVersion;
    public short dmSize;
    public short dmDriverExtra;
    public int dmFields;
    public short dmOrientation;
    public short dmPaperSize;
    public short dmPaperLength;
    public short dmPaperWidth;
    public short dmScale;
    public short dmCopies;
    public short dmDefaultSource;
    public short dmPrintQuality;
    public short dmColor;
    public short dmDuplex;
    public short dmYResolution;
    public short dmTTOption;
    public short dmCollate;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)]
    public string dmFormName;
    public short dmUnusedPadding;
    public short dmBitsPerPel;
    public int dmPelsWidth;
    public int dmPelsHeight;
    public int dmDisplayFlags;
    public int dmDisplayFrequency;
    public int dmICMMethod;
    public int dmICMIntent;
    public int dmMediaType;
    public int dmDitherType;
    public int dmICCManufacturer;
    public int dmICCModel;
    public int dmPanningWidth;
    public int dmPanningHeight;

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]
    public int[] ExDevMode;
}

/// <summary>
/// 读取初始配置
/// </summary>
private void GetDevMode()
{
    IntPtr printerSlef = IntPtr.Zero;
    int n = 0;

    // 空默认不使用
    IntPtr temp = new IntPtr();

    try
    {
        
        if (!FunctionClass.OpenPrinter(printName, out printerSlef, 0))
        {
            throw new Exception("Cannot open printer");
        }

        // 正式获取结构体
        GetDevModPtr(out devModePtr, printerSlef);
        GetDevMode(devModePtr, out dm, printerSlef);

        // 获取额外配置项的起始位
        while (true)
        {
            if (dm.ExDevMode[n] == DevModeCode.EX_DEV_SIGN)
            {
                DevModeCode.ExDevTop = n - 1;
                break;
            }
            if (n >= DevModeCode.EX_DEV_SIZE)
            {
                break;
            }
            n++;
        }
    }
    finally
    {
        FunctionClass.ClosePrinter(printerSlef);
    }
}

/// <summary>
/// 设置打印机
/// </summary>
public void SettingPrint(PrinterSet printerSet)
{
    try
    {
        dm = Marshal.PtrToStructure<DEVMODE>(devModePtr);

        // 修改内容
        dm.ExDevMode[DevModeCode.ExDevTop + DevModeCode.ExCut2inch] = printerSet.Cut2inch;

        // 将修改之后dm同步内存
        Marshal.StructureToPtr(dm, devModePtr, true);
        pd.PrinterSettings.SetHdevmode(devModePtr);
    }
    finally
    {
        GCFunction.GlobalFree(devModePtr);
    }
}


/// <summary>
/// 手动获取DEVMOD指针
/// </summary>
/// <param name="devModePtr"> 等待分配的指针 </param>
/// <exception cref="Exception"></exception>
public void GetDevModPtr(out IntPtr devModePtr,IntPtr printerSlef)
{
    
    // 空默认不使用
    IntPtr tempNull = new IntPtr(), hDevMode;
    int devSize;

    devSize = FunctionClass.DocumentProperties(IntPtr.Zero, printerSlef, printName, tempNull, ref tempNull, 0);

    // 是否获取成功
    if (devSize <= 0)
    {
        throw new Exception("Cannot get DevMode Intptr");
    }

    // 分配内存大小
    hDevMode = GCFunction.GlobalAlloc(DevModeCode.GHND, devSize);
    devModePtr = GCFunction.GlobalLock(hDevMode);
}

/// <summary>
/// 手动获取DevMod内容
/// </summary>
/// <param name="devModePtr"> 已被分配内存的指针 </param>
/// <param name="dm"> 回传结构体 </param>
/// <exception cref="Exception"></exception>
public void GetDevMode(IntPtr devModePtr, out DEVMODE dm, IntPtr printerSlef)
{
    IntPtr tempNull = IntPtr.Zero;
    int resultCode;

    // 再次访问获取实际数据
    resultCode = FunctionClass.DocumentProperties(0, printerSlef, printName, devModePtr, ref tempNull, DevModeCode.DM_OUT_BUFFER);
    if (resultCode < 0)
    {
        GCFunction.GlobalFree(devModePtr);
        throw new Exception("Cannot get DevMode"); ;
    }

    dm = Marshal.PtrToStructure<DEVMODE>(devModePtr);
}
  • 写回答

25条回答 默认 最新

  • 阿里嘎多学长 2024-11-18 17:28
    关注

    阿里嘎多学长整理AIGC生成,因移动端显示问题导致当前答案未能完全显示,请使用PC端查看更加详细的解答过程

    问题解决方案

    你的问题是将 IntPtr 传入 SetHdevmode() 方法,但是转换后的结果与外部代码不一致。这可能是由于 IntPtrDEVMODE 结构体之间的类型转换问题。

    在 C# 中,IntPtr 是一个可 unsafe 的指针类型,用于访问未托管代码的指针。在64位操作系统中,IntPtr 是 8 字节长,而 C# 的 DEVMODE 结构体长度为 28 字节。

    为了正确地将 IntPtr 传入 SetHdevmode() 方法,你可以使用 Marshal.PtrToStructure() 方法将 IntPtr 转换为 DEVMODE 结构体:

    DEVMODE devMode = (DEVMODE)Marshal.PtrToStructure(devModePtr, typeof(DEVMODE));
    

    其中,devModePtrIntPtr 类型的变量,包含 DEVMODE 结构体的地址。

    还需要注意的是,在使用 SetHdevmode() 方法时,需要确保相应的头文件和库文件已经被包含和链接。如果你还遇到了问题,可以分享更多代码或系统信息,以便更好地帮助你解决问题。

    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 11月19日
  • 修改了问题 11月19日
  • 修改了问题 11月18日
  • 创建了问题 11月18日