1

これを機能させようとして頭を壁にぶつけているので、ここの誰かが私を助けてくれることを願っています。基本的に、winspool.Drv win32 API を使用して印刷し、未加工のテキスト/PCL コマンドをプリンターに送信する必要があります。これは問題なく動作しますが、プリンター ダイアログ/設定で選択したプリンター オプションはどれも何もしません。

最終的には、ダイアログの PrinterSettings から DEVMODE を取得し、それを生の印刷に使用したいと考えていますが、手動で設定することさえできません。

WritePrinter の直前、または別の Open/Close プリンターで DEVMODE を変更しようとしましたが、DocumentProperties 呼び出しのみを使用して、PRINTER_INFO_8 構造体で GetPrinter/SetPrinter を使用してみましたが、何も固執しません。DEVMODE 構造体は正しく入力されているようで、変更すると正しく変更されたように見えますが、プリンターは常にまったく同じ方法で印刷します。

使用しているコードは次のとおりです。

方法1:

public static bool SetPrinterSettings(PrinterSettings settings, IntPtr hPrinter)
{
    IntPtr hDevMode; // a handle to our current DEVMODE
    IntPtr pDevMode; // a pointer to our current DEVMODE
    String sPrinterName; // normalized printer name
    DEVMODE dm;

    // Setup
    sPrinterName = settings.PrinterName.Normalize();

    // Obtain the current DEVMODE from the PrinterSettings
    hDevMode = settings.GetHdevmode(settings.DefaultPageSettings);

    // Obtain a lock on the handle and get an actual pointer so Windows won't move
    // it around while we're futzing with it
    pDevMode = GlobalLock(hDevMode);

    // test
    dm = (DEVMODE)Marshal.PtrToStructure(pDevMode, typeof(DEVMODE));

    // Our DEVMODE is 188 bytes, but dmSize returns 220, does this matter?
    // This code doesnt seem to work
    //dm.dmSize = (short)Marshal.SizeOf(dm); // Set size to our implementation of DevMode
    //int isize = GlobalSize(pDevMode).ToInt32() - (int)dm.dmSize; // Set the print drivers extra size
    //dm.dmDriverExtra = Convert.ToInt16(isize);

    // Change things
    dm.dmFields = DM_FIELD_TYPE.DM_ORIENTATION;
    dm.dmOrientation = 2;

    // Load the structure back into the buffer
    Marshal.StructureToPtr(dm, pDevMode, true);

    //Tell the printer about the new property
    int ret = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, pDevMode, pDevMode, (DM_IN_BUFFER | DM_OUT_BUFFER));

    if (ret <= 0)
    {
        return false;
    }



    // We're done futzing
    GlobalUnlock(hDevMode);

    // Tell our printer settings to use the one we just overwrote
    //settings.SetHdevmode(hDevMode);

    // It's copied to our printer settings, so we can free the OS-level one
    GlobalFree(hDevMode);

    //test
    dm = (DEVMODE)Marshal.PtrToStructure(pDevMode, typeof(DEVMODE));

    // ^^ this contains correct orientation

    return true;
}

方法 2:

public static bool SetLandscapeMode(PrinterSettings settings, IntPtr hPrinter)
{
    // Setup
    String sPrinterName = settings.PrinterName.Normalize();

    // get current printer settings
    int memNeeded = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, IntPtr.Zero, IntPtr.Zero, 0);
    IntPtr pFullDevMode = Marshal.AllocHGlobal(memNeeded);
    DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, pFullDevMode, IntPtr.Zero, DM_OUT_BUFFER);

    DEVMODE dm = (DEVMODE)Marshal.PtrToStructure(pFullDevMode, typeof(DEVMODE));

    // change the settings
    dm.dmFields = DM_FIELD_TYPE.DM_ORIENTATION;
    dm.dmOrientation = 2;

    Marshal.StructureToPtr(dm, pFullDevMode, true);

    PRINTER_INFO_8 PI8 = new PRINTER_INFO_8();
    PI8.pDevMode = pFullDevMode;

    IntPtr pPI8 = Marshal.AllocHGlobal(Marshal.SizeOf(PI8));

    Marshal.StructureToPtr(PI8, pPI8, true);

    // save the printer settings
    SetPrinter(hPrinter, 9, pPI8, 0);

    Marshal.FreeHGlobal(pPI8);

    return true;
}

印刷をテストするコード:

private void testPrint_Click(object sender, EventArgs e)
{
    IntPtr hPrinter;

    if (printDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
    {
        hPrinter = RawPrint.OpenRAWPrinter(printDialog1.PrinterSettings.PrinterName);

        if (hPrinter == IntPtr.Zero)
        {
            MessageBox.Show("Error opening printer");
            return;
        }

        if (!RawPrint.StartRAWDocument(hPrinter, "Test document"))
        {
            MessageBox.Show("Error starting raw document");
            RawPrint.CloseRAWPrinter(hPrinter);
            return;
        }

        // Start a page.
        if (RawPrint.StartRawPage(hPrinter))
        {
            // Set the printers settings
            //if (!RawPrint.SetPrinterSettings(printDialog1.PrinterSettings, hPrinter))
            if(!RawPrint.SetLandscapeMode(printDialog1.PrinterSettings, hPrinter))
            {
                MessageBox.Show("Error setting printer settings");
                RawPrint.CloseRAWPrinter(hPrinter);
                return;
            }

            String test = "This is \r\n test print data";
            byte[] buf = Encoding.Default.GetBytes(test);

            GCHandle gch = GCHandle.Alloc(buf, GCHandleType.Pinned);
            RawPrint.writeRAW(hPrinter, gch.AddrOfPinnedObject(), buf.Length);
            gch.Free();

            RawPrint.EndRawPage(hPrinter);
        }

        RawPrint.EndRAWDocument(hPrinter);
        RawPrint.CloseRAWPrinter(hPrinter);
    }
    else
    {
        MessageBox.Show("Error starting raw page");
    }
}

唯一の奇妙な点は、Marshal.SizeOf(typeof(DEVMODE)) または Marshal.SizeOf(dm) が 188 に等しいことですが、構造体に返される dmSize は 220 です。コードを出力しますが、エラーが発生するか、機能しないようです。それが問題かどうかはわかりません。

それに加えて、DevModes で返された情報はすべて正しく機能しているようです。印刷ダイアログでオプションを設定し、PrinterSettings devmode で変更を確認できます。これらの関数の最後で、pDevMode を構造体にマーシャリングすると、設定が変更されます。

ただし、これはいずれも印刷に影響を与えるものではないようです。何か足りないものはありますか?

編集: テスト関数の RawPrint 呼び出しは、スプーラー API 呼び出しの単なるラッパーです。ページは正常に印刷されますが、常に縦向きモードで印刷され、オプションは機能しません。

4

1 に答える 1

1

WritePrinter を使用してプリンター ドライバーをバイパスするのではなく、通常どおり印刷ジョブを開始し、ExtEscape() とPASSTHROUGHエスケープを使用して PCL を挿入する必要があります。これにより、すべての PrinterSettings 値をジョブに適用できます。すべてのプリンタ ドライバが PASSTHROUGH をサポートしているわけではありませんが、 QUERYESCSUPPORT を指定して ExtEscape() を呼び出すことで、ドライバのサポートを確認できます

于 2013-03-18T19:59:32.290 に答える