AddJob + SetPrinter: is it possible to set dmCopies and get effect?

1.6k views Asked by At

What I need is to re-print spooled file (not job*) again, setting a new amount of copies.

So far following attempts were tried:

  • OpenPrinter, AddJob, SetJob (with JOB_INFO_2->pDevMode)
  • OpenPrinter, SetPrinter, DocumentProperties, AddJob, SetJob
  • OpenPrinter, StartDocPrinter, StartPagePrinter, WritePrinter

Numerous ClosePrinter combinations and a number of workarounds for SetPrinter..DocumentProperties part - no success.

Changing printers (HP to Brother), restarting spooler and PC - no effect.

It can be seen in the print jobs list, that a number of copies is set. However, what I get out of printer is one copy.

Also, pDevMode->dmFields is set with |= DM_COPIES in all relevant cases.

So now, is there any effective route to set a number of copies, possibly other params (collate) and print a raw PCL/PS document without going GDI or printing the job numerous times?

#include "006_pclblacky_t.h"
#define PNAME L"HP"

t_006pclblacky::t_006pclblacky()
{
        settings.color.set = false;
        settings.copies.set = false;
        settings.ori.set = false;
        settings.paper.set = false;
}


t_006pclblacky::~t_006pclblacky()
{
}

int t_006pclblacky::Run()
{
        int rc = 0;

        rc = subtest_001();
        if (rc != 0) return rc;

        return 0;

}

void t_006pclblacky::defaults() {
}

void t_006pclblacky::GetJobInfo(int JobId)
{
        HANDLE ph;
        DOC_INFO_1 di1;
        DWORD dwRead, dwWritten;
        DWORD x,y,z;
        int rc;
        PRINTER_DEFAULTSW Defaults = { NULL, NULL, PRINTER_ALL_ACCESS};
        OpenPrinter(PNAME, &ph, &Defaults);


        try {
                rc = GetJob(ph, JobId, 1, NULL, 0, &x);
                if (rc != 122 && x < 1) {
                        assert(122 == 0);
                }
        } catch (...) {
                assert(1 == 0);
        }

        JOB_INFO_1 *jg1 = (JOB_INFO_1*)malloc(x);
        try {
                GetJob(ph, JobId, 1, (LPBYTE)jg1, x, &y);
        } catch (...) {
                assert(1 == 0);
        }

        jg1->TotalPages = 2;


        rc = SetJob(ph, JobId, 1, (LPBYTE)jg1, JOB_CONTROL_PAUSE);
        assert (rc > 0);
        rc = GetLastError();

        try {
                if (GetJob(ph, JobId, 2, NULL, 0, &x) != 122 && x < 1) {
                        assert(122 == 0);
                }
        } catch (...) {
                assert(1 == 0);
        }
        //jg1->PagesPrinted = 1;

        JOB_INFO_2 *jg2 = (JOB_INFO_2*)malloc(x);
        try {
                GetJob(ph, JobId, 2, (LPBYTE)jg2, x, &y);
        } catch (...) {
                assert(1 == 0);
        }
}


void t_006pclblacky::SendFileToPrinter(LPCWSTR fileName, LPWSTR docName)
{

        HANDLE ph;
        DOC_INFO_1 di1;
        DWORD dwRead, dwWritten;


        std::ifstream file(fileName, ios::in | ios::binary | ios::ate);
        std::ifstream::pos_type fileSize;
        char* fileContents;
        int rc;
        PRINTER_DEFAULTSW Defaults = { NULL, NULL, PRINTER_ALL_ACCESS};
        LPDEVMODE devmOld = NULL;
        OpenPrinter(PNAME, &ph, &Defaults);

        di1.pDatatype = L"RAW"; // IsV4Driver("Printer Name") ? "XPS_PASS" : "RAW";
        di1.pDocName = docName;
        di1.pOutputFile = NULL;

        fileSize = file.tellg();
        if (fileSize < 1) {
                return;
        }

        fileContents = new char[fileSize];
        file.seekg(0, ios::beg);
        if (!file.read(fileContents, fileSize))
        {
        assert(0 == 1);
        }

        dwRead = fileSize;

        if (!settings.ori.set && !settings.color.set && !settings.copies.set && !settings.paper.set) {
                StartDocPrinter(ph, 1, (LPBYTE)&di1);

                StartPagePrinter(ph);

                if (file.is_open())
                {
                        WritePrinter(ph, fileContents, dwRead, &dwWritten);
                        file.close();
                }
                else {
                        assert(0 == 1);
                }

                EndPagePrinter(ph);

                EndDocPrinter(ph);
        } else {
                devmOld = GetPrinterParams(ph);
                ClosePrinter(ph);
                Defaults.pDevMode = devmOld;
                OpenPrinter(PNAME, &ph, &Defaults);
                //ClosePrinter(ph);
                //OpenPrinter(PNAME, &ph, &Defaults);
                SetPrinterParams(ph);
                //ClosePrinter(ph);
                //OpenPrinter(PNAME, &ph, &Defaults);

                int tsz = sizeof(ADDJOB_INFO_1)+MAX_PATH+1;
                ADDJOB_INFO_1 *aji = (ADDJOB_INFO_1*)malloc(tsz);
                DWORD d = 0;
                rc = AddJob(ph, 1, (LPBYTE)aji, tsz, &d);
                if (rc == 0) {
                        rc = GetLastError();
                }
                assert (aji->JobId != 0);

                DWORD x,y,z;

                try {
                        rc = GetJob(ph, aji->JobId, 1, NULL, 0, &x);
                        if (rc != 122 && x < 1) {
                                assert(122 == 0);
                        }
                } catch (...) {
                        assert(1 == 0);
                }

                JOB_INFO_1 *jg1 = (JOB_INFO_1*)malloc(x);
                try {
                        GetJob(ph, aji->JobId, 1, (LPBYTE)jg1, x, &y);
                } catch (...) {
                        assert(1 == 0);
                }

                /*JOB_INFO_1 *ji1 = (JOB_INFO_1*)malloc(sizeof(JOB_INFO_1));
                ji1->pDatatype = L"RAW";
                ji1->pPrinterName = jg1->pPrinterName;
                ji1->TotalPages = 2; // test
                ji1->pDocument = jg1->pDocument;
                ji1->pMachineName = jg1->pMachineName;
                ji1->pUserName = jg1->pUserName;*/
                jg1->TotalPages = 1;
                jg1->pDocument = docName;


                rc = SetJob(ph, aji->JobId, 1, (LPBYTE)jg1, JOB_CONTROL_PAUSE);
                assert (rc > 0);
                rc = GetLastError();

                try {
                        if (GetJob(ph, aji->JobId, 2, NULL, 0, &x) != 122 && x < 1) {
                                assert(122 == 0);
                        }
                } catch (...) {
                        assert(1 == 0);
                }
                jg1->PagesPrinted = 2;
                jg1->TotalPages = 2;

                JOB_INFO_2 *jg2 = (JOB_INFO_2*)malloc(x);
                try {
                        GetJob(ph, aji->JobId, 2, (LPBYTE)jg2, x, &y);
                } catch (...) {
                        assert(1 == 0);
                }
                /*JOB_INFO_2 *ji2 = (JOB_INFO_2*)malloc(sizeof(JOB_INFO_2));
                ji2->pDevMode = (PDEVMODE)malloc(sizeof(DEVMODE));
                ji2->pDevMode->dmPaperSize = settings.paper.val;
                ji2->pDatatype = L"RAW";
                ji2->pPrinterName = jg2->pPrinterName;
                ji2->TotalPages = 2;
                */

                DWORD dmf = jg2->pDevMode->dmFields;
                dmf = DM_COLLATE;


                if (settings.copies.set) {
                        if (! jg2->pDevMode->dmFields & DM_COPIES) {
                                jg2->pDevMode->dmFields |= DM_COPIES;
                        }
                        jg2->pDevMode->dmCopies = settings.copies.val;
                }
                if (settings.color.set) {
                        jg2->pDevMode->dmColor = settings.color.val;
                        jg2->pDevMode->dmFields |= DM_COLOR;
                }
                if (settings.ori.set) {
                        jg2->pDevMode->dmOrientation = settings.ori.val;
                        jg2->pDevMode->dmFields |= DM_ORIENTATION;
                }
                if (settings.paper.set) {
                        jg2->pDevMode->dmPaperSize = settings.paper.val;
                        jg2->pDevMode->dmFields |= DM_PAPERSIZE;
                }
                jg2->TotalPages = 2;
                jg2->PagesPrinted = 2;
                // Çàïèñàòü ôàéë çàäàíèÿ
                std::ofstream file2(aji->Path, ios::out | ios::binary | ios::ate);
                file2.write(fileContents, fileSize);
                file2.flush();
                file2.close();

                rc = SetJob(ph, aji->JobId, 2, (LPBYTE)jg2, JOB_CONTROL_RESTART);
                assert(rc > 0);
                rc = GetLastError();
                GetJob(ph, aji->JobId, 2, (LPBYTE)jg2, x, &y);

                ScheduleJob(ph, aji->JobId);
        }

        if (devmOld != NULL) {
                ClosePrinter(ph);
                OpenPrinter(PNAME, &ph, &Defaults);
                RestorePrinterParams(ph, devmOld);
        }

        ClosePrinter(ph);
}

int t_006pclblacky::subtest_001()
{
        defaults();
        SetCopies(2);
        SetOrientation(2);
        SendFileToPrinter(L"test.pcl", L"test.pcl");
}

        return rc;
}

t_006pclblacky* t_006pclblacky::SetOrientation(int i)
{
        this->settings.ori.set = true;
        this->settings.ori.val = i;
        return this;
}
t_006pclblacky* t_006pclblacky::SetColor(int i)
{
        this->settings.color.set = true;
        this->settings.color.val = i;
        return this;
}
t_006pclblacky* t_006pclblacky::SetCopies(int i)
{
        this->settings.copies.set = true;
        this->settings.copies.val = i;
        return this;
}

t_006pclblacky* t_006pclblacky::SetPaperSize(int i)
{
        this->settings.paper.set = true;
        this->settings.paper.val = i;
        return this;
}

void t_006pclblacky::SetPrinterParams(HANDLE ph)
{ // http://www.rsdn.ru/forum/dotnet/4070489.flat
        // http://www.codeproject.com/Articles/132365/Configuring-Printer-Settings-Programmatically

        DWORD dwNeeded, dwNeeded2;
        int rc = GetPrinter(ph, 2, 0, 0, &dwNeeded);
        if (rc != 0 || (rc == 0 && dwNeeded > 0 && dwNeeded < 10240 /* TODO magic? */)) {
                PRINTER_INFO_2 *pi2 = (PRINTER_INFO_2 *)::GlobalAlloc(GPTR,dwNeeded);
                GetPrinter(ph, 2, (LPBYTE)pi2, dwNeeded, &dwNeeded);
         // check that the driver supports the changes

                int x = DocumentProperties(NULL, ph, PNAME, NULL, pi2->pDevMode, DM_OUT_BUFFER);
        //        LPDEVMODE y = (LPDEVMODE)malloc(x);
//
        //        rc = DocumentProperties(NULL, ph, PNAME, NULL, y, DM_OUT_BUFFER);

                AffectDevMode(pi2->pDevMode);
                //pi2->pDevMode = y;
                pi2->pSecurityDescriptor = 0;

                ::DocumentProperties (NULL, ph, PNAME, NULL, pi2->pDevMode, DM_IN_BUFFER);
                rc = SetPrinter(ph, 2, (LPBYTE)pi2, 0);
        }


        rc = GetPrinter(ph, 2, 0, 0, &dwNeeded2);
        if (rc != 0 || (rc == 0 && dwNeeded2 > 0 && dwNeeded2 < 10240 /* TODO magic? */)) {
                PRINTER_INFO_2 *pi3 = (PRINTER_INFO_2 *)::GlobalAlloc(GPTR,dwNeeded2);
                GetPrinter(ph, 2, (LPBYTE)pi3, dwNeeded, &dwNeeded);
                assert(pi3->pDevMode->dmCopies > 1);
        }

}

void t_006pclblacky::RestorePrinterParams(HANDLE ph, LPDEVMODE old)
{
        DWORD dwNeeded;
        GetPrinter(ph, 2, 0, 0, &dwNeeded);
        PRINTER_INFO_2 *pi2 = (PRINTER_INFO_2 *)GlobalAlloc(GPTR,dwNeeded);
        GetPrinter(ph, 2, (LPBYTE)pi2, dwNeeded, &dwNeeded);

        if (settings.copies.set) {

                pi2->pDevMode->dmCopies = old->dmCopies;
        }
        if (settings.color.set) {
                pi2->pDevMode->dmColor = old->dmColor;
        }
        if (settings.ori.set) {
                pi2->pDevMode->dmOrientation = old->dmOrientation;
        }
        if (settings.paper.set) {
                pi2->pDevMode->dmPaperSize = old->dmPaperSize;
        }
        //ClosePrinter(ph);
}

void t_006pclblacky::AffectDevMode(LPDEVMODE dm)
{
/* if(dm->dmFields & DM_PAPERSIZE )
{
                // define the page size as A3
dm->dmPaperSize = DMPAPER_A3;
                // define, which field was changed
dm->dmFields |= DM_PAPERSIZE;
        }*/

        if (settings.copies.set) {
                if (! dm->dmFields & DM_COPIES) {
                        dm->dmFields |= DM_COPIES;
                }
                dm->dmCopies = settings.copies.val;
        }
        if (settings.color.set) {
                dm->dmColor = settings.color.val;
                dm->dmFields |= DM_COLOR;
        }
        if (settings.ori.set) {
                dm->dmOrientation = settings.ori.val;
                dm->dmFields |= DM_ORIENTATION;
        }
        if (settings.paper.set) {
                dm->dmPaperSize = settings.paper.val;
                dm->dmFields |= DM_PAPERSIZE;
        }


}

LPDEVMODE t_006pclblacky::GetPrinterParams(HANDLE ph)
{
        LPDEVMODE out;
        DWORD dwNeeded;
        GetPrinter(ph, 2, 0, 0, &dwNeeded);
        PRINTER_INFO_2 *pi2 = (PRINTER_INFO_2 *)GlobalAlloc(GPTR,dwNeeded);
        GetPrinter(ph, 2, (LPBYTE)pi2, dwNeeded, &dwNeeded);

        DWORD lNeeded = pi2->pDevMode->dmSize + pi2->pDevMode->dmDriverExtra;
        out = (LPDEVMODEW) malloc(lNeeded);
        memcpy(out, pi2->pDevMode, lNeeded);

//        ClosePrinter(ph);

        return out;
} 
1

There are 1 answers

0
Carey Gregory On

One fundamental error you're making is confusing TotalPages in the JOB_INFO_1 struct with the number of copies to print. TotalPages is the number of pages in the print job, not the number of copies to print. So, for example, if you print a 10-page document, you should expect to see 10 in this field.

In fact, you can pretty much forget SetJob as a way of accomplishing this. Although it seems like the copy count should be an element of a print job, it is not. It's an element of the document that was printed and is specified in the DEVMODE passed to DocumentProperties. Changing the copy count after the fact can only be accomplished by changing dmCopies in the DEVMODE, which is stored in the spool file. One option would be to parse the spool file and change the value there. You can find the spool file format here.

But the way you're attempting to do it using StartDocPrinter etc. should also work. I believe you must have a bug in your SetPrinterParams function or one of the functions it calls. Step into that code in a debugger and make sure dmCopies is the value you want before calling DocumentProperties, and make sure none of the Win32 functions are failing.