How to get files on the whole drive - c++

I have written a code to iterate over the drive to find the file of specific extension and if the file is fount it'll be added to the list box but the code fails its iteration when it finds a directory. The iteration stops with the files not the directories. I want my program to search the file with a given extension even in the directories and sub-directories what shall I do?
here is my code
The variable buffer seen in my code is nothing but the drive string e.g H:\
count = 0;
int Class::countOfDocuments(wchar_t buffer[10])
{
wchar_t driveString[MAX_PATH + 1] = { 0 };
wcsncat_s(driveString,260,buffer,260);
wcsncat_s(driveString, 260, L"*doc", 260);
WIN32_FIND_DATA documents;
HANDLE hFind; bool var = true;
hFind = FindFirstFile(driveString, &documents);
if (INVALID_HANDLE_VALUE == hFind)
{
wchar_t* no = L"No documents found";
SendMessage(list1, LB_ADDSTRING, NULL, (LPARAM)no);
for (int i = 0; i <= 10; i++)
{
SendMessage(cprogress, PBM_SETRANGE, 0, i);
SendMessage(cprogress, PBM_SETSTEP, (WPARAM)1, 0);
SendMessage(cprogress, PBM_STEPIT, 0, 1);
}
return count = -1;
}
else
{
wchar_t* Yes = L"Document found";
perform = true;
SendMessage(list1, LB_ADDSTRING, NULL, (LPARAM)Yes);
while (var = FindNextFile(hFind, &documents) == TRUE)
{
count++;
}
for (int i = 0; i <= count; i++)
{
SendMessage(cprogress, PBM_SETRANGE, 0, i);
SendMessage(cprogress, PBM_SETSTEP, (WPARAM)1, 0);
SendMessage(cprogress, PBM_STEPIT, 0, 1);
wchar_t* doc = L"Document found";
SendMessage(list1, LB_ADDSTRING, NULL, (LPARAM)doc);
}
wchar_t* z = L"search complete";
SendMessage(list1, LB_ADDSTRING, NULL, (LPARAM)z);
}
return count;
}

Related

Multithreading programing in Win32

I use mutex to sync file writing and reading. I create some threads to read file and some threads to write file. But writing Thread sometimes block in WaitForSingleObject(hMutexRW,INFINITE). I'm new to Win32 Threads programming and I don't know what the problem is. I think the mutex is the problem, and I want to know how to solve this problem.
const int nThreadWriting = 5;
const int nThreadReading = 5;
const int nBufSize = 100;
const int maxWritten = 10;
const int timeRange = 3;
HANDLE hMutexRW, hMutexW, hMutexR, hMutexN;
int currentSemaphoreR = 0;
int numberWritten = 0;
unsigned __stdcall ThreadReading(void *pV)
{
HANDLE hFile;
int waitTime, lastTime;
char buf[nBufSize];
int* ptr = (int*)pV;
srand(*ptr);
while (1)
{
WaitForSingleObject(hMutexN, INFINITE);
if (numberWritten >= maxWritten)
{
ReleaseMutex(hMutexN);
return 0;
}
ReleaseMutex(hMutexN);
waitTime = rand() % timeRange+1;
lastTime = rand() % timeRange+1;
WaitForSingleObject(hMutexW, INFINITE);
WaitForSingleObject(hMutexR, INFINITE);
if (currentSemaphoreR == 0)
{
WaitForSingleObject(hMutexRW, INFINITE);
sprintf_s(buf, nBufSize, "%d R GET MUTEX_RW\n", GetCurrentThreadId());
std::cout << buf << std::endl;
}
currentSemaphoreR++;
ReleaseMutex(hMutexR);
ReleaseMutex(hMutexW);
hFile = CreateFile(TEXT("nice.txt"), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
std::cout << "cannot open file" << std::endl;
}
sprintf_s(buf, nBufSize, "%d R %d %d\n", GetCurrentThreadId(), waitTime, lastTime);
std::cout << buf <<std::endl;
CloseHandle(hFile);
WaitForSingleObject(hMutexR, INFINITE);
currentSemaphoreR--;
if (currentSemaphoreR == 0)
ReleaseMutex(hMutexRW);
ReleaseMutex(hMutexR);
}
return 0;
}
unsigned __stdcall ThreadWriting(void *pV)
{
int waitTime, lastTime;
char buf[nBufSize];
int* ptr = (int*)pV;
srand(*ptr);
HANDLE hFile;
while (1)
{
WaitForSingleObject(hMutexN, INFINITE);
if (numberWritten >= maxWritten)
{
ReleaseMutex(hMutexN);
return 0;
}
numberWritten++;
ReleaseMutex(hMutexN);
WaitForSingleObject(hMutexW, INFINITE);
WaitForSingleObject(hMutexRW, INFINITE);
hFile = CreateFile(TEXT("nice.txt"), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
std::cout << "cannot open file" << std::endl;
return 1;
}
SetFilePointer(hFile, 0, NULL, FILE_END);
sprintf_s(buf, nBufSize, "%d W %d %d\n", GetCurrentThreadId(), waitTime, lastTime);
WriteFile(hFile, buf, strlen(buf), NULL, NULL);
CloseHandle(hFile);
ReleaseMutex(hMutexRW);
ReleaseMutex(hMutexW);
}
return 0;
}
int main()
{
HANDLE hFile;
hFile = CreateFile(TEXT("nice.txt"), GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
CloseHandle(hFile);
DWORD IDThread[nThreadWriting+ nThreadReading];
HANDLE hThread[nThreadWriting + nThreadReading];
int num[nThreadWriting + nThreadReading];
for (int i = 0; i < nThreadWriting + nThreadReading; i++)
num[i] = i;
hMutexRW = CreateMutex(NULL, FALSE, NULL);
hMutexR = CreateMutex(NULL, FALSE, NULL);
hMutexW = CreateMutex(NULL, FALSE, NULL);
hMutexN = CreateMutex(NULL, FALSE, NULL);
if (!hMutexRW || !hMutexW || !hMutexR)
return 1;
for (int i = 0; i < nThreadReading; i++)
{
hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadReading, num + i, 0, (unsigned int*)&IDThread[i]);
if (!hThread[i])
ExitProcess(3);
}
for (int i = nThreadReading; i < nThreadWriting + nThreadReading; i++)
{
hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadWriting, num + i, 0, (unsigned int*)&IDThread[i]);
if (!hThread[i])
ExitProcess(3);
}
WaitForMultipleObjects(nThreadWriting + nThreadReading, hThread, TRUE, INFINITE);
for (int i = 0; i < nThreadWriting + nThreadReading; i++)
CloseHandle(hThread[i]);
CloseHandle(hMutexRW);
CloseHandle(hMutexR);
CloseHandle(hMutexW);
CloseHandle(hMutexN);
return 0;
}

mciSendString, searching something similar to command "wait"

I´m trying to play a mp3 song after another from a list, the problem is that "wait" command "freeze" all the program until all the songs finish, and what I want is the other functions, as "pause" or "stop", to still work while the song is playing. I don´t have any trouble when I play one song individually.
I read some documentation and it looks like "status" command is the solution, but I don´t understand how to use it.
Here is the code of "case IDC_Play:"
if ((SendDlgItemMessage(hDlg, IDC_CHECK1, BM_GETSTATE, NULL, NULL)) == BST_CHECKED)
{//here goes the code for play only one song}
else {
int cuenta = SendDlgItemMessage(hDlg, IDC_LIST1, LB_GETCOUNT, NULL, NULL);
int indice = 0;
while (indice != cuenta) {
char auxi[10] = "";
UINT index = SendDlgItemMessage(hDlg, IDC_LIST1, LB_GETCURSEL, 0);
SendDlgItemMessage(hDlg, IDC_LIST1, LB_GETTEXT, index, (LPARAM)auxi);
if (strcmp(auxi, "") == 0) {
MessageBox(NULL, "No se selecciono cancion", "ERROR", MB_ICONERROR);
}
else {
char Cnum[10];
aux = inicio;
aux = aux->sig;
do {
_itoa_s(aux->folio, Cnum, 10);
if (strcmp(auxi, Cnum) == 0) {
strcpy_s(szFileName, aux->mptres);
bmp1 = (HBITMAP)SendDlgItemMessage(hDlg, IDC_Imagen1, STM_GETIMAGE, IMAGE_BITMAP, 0);
bmp2 = (HBITMAP)LoadImage(NULL, aux->imagen, IMAGE_BITMAP, 140, 120, LR_LOADFROMFILE);
SendDlgItemMessage(hDlg, IDC_Imagen1, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bmp2);
}
else {
aux = aux->sig;
}
} while (strcmp(auxi, Cnum) == -1 || strcmp(auxi, Cnum) == 1);
ShowWindow(GetDlgItem(hDlg, IDC_Play1), SW_HIDE);
ShowWindow(GetDlgItem(hDlg, IDC_Pause1), SW_SHOW);
char comillas[MAX_PATH] = "\"";
char comillas2[MAX_PATH] = "\"";
strcat_s(comillas, szFileName);
strcat_s(comillas, comillas2);
char musica[MAX_PATH] = "open ";
strcat_s(musica, comillas);
strcat_s(musica, " type mpegvideo");
mciSendString(musica, NULL, 0, 0);
char musica1[MAX_PATH] = "play ";
char esperar[MAX_PATH] = " wait";
strcat_s(musica1, comillas);
strcat_s(musica1, esperar);
mciSendString(musica1, NULL, 0, 0);
char parar[MAX_PATH] = "stop ";
strcat_s(parar, comillas);
mciSendString(parar, NULL, 0, 0);
char cerrar[MAX_PATH] = "close ";
strcat_s(cerrar, comillas);
mciSendString(cerrar, NULL, 0, 0);
index++;
SendDlgItemMessage(hDlg, IDC_LIST1, LB_SETCURSEL, index, NULL);
SendDlgItemMessage(hDlg, IDC_LIST2, LB_SETCURSEL, index, NULL);
SendDlgItemMessage(hDlg, IDC_LIST3, LB_SETCURSEL, index, NULL);
SendDlgItemMessage(hDlg, IDC_LIST4, LB_SETCURSEL, index, NULL);
SendDlgItemMessage(hDlg, IDC_LIST5, LB_SETCURSEL, index, NULL);
indice = index;
} //else
} //while
}//else
Maybe you should use MM_MCINOTIFY flag and callback to avoid the blocking call that freezes the whole application?
Please see an example of using the callback and flag there at CodeProject: http://www.codeproject.com/Articles/17279/Using-mciSendString-to-play-media-files

Working with threads in c++

I need to create two threads, one of which will return even numbers and the other will return odd numbers. What am I doing wrong?
int _tmain(int argc, _TCHAR* argv[])
{
DWORD ID1 = 1, ID2 = 100;
DWORD arr[] = {ID1, ID2};
HANDLE h[1];
for (int i = 0; i < 2; ++i)
{
h[0] = CreateThread(NULL, 0, &f1, arr, 0, &arr[0]);
if (h[0] == NULL)
_tprintf(_T("%d"), GetLastError());
h[1] = CreateThread(NULL, 0, &f2, arr, 0, &arr[1]);
if (h[1] == NULL)
_tprintf(_T("%d"), GetLastError());
}
WaitForMultipleObjects(2, h, TRUE, INFINITE);
for (int i = 0; i < 2; ++i)
CloseHandle(h[i]);
return 0;
}
Change this
HANDLE h[1];
for (int i = 0; i < 2; ++i)
{
h[0] = CreateThread(NULL, 0, &f1, arr, 0, &arr[0]);
if (h[0] == NULL)
_tprintf(_T("%d"), GetLastError());
h[1] = CreateThread(NULL, 0, &f2, arr, 0, &arr[1]);
if (h[1] == NULL)
_tprintf(_T("%d"), GetLastError());
}
To this
HANDLE h[2];
h[0] = CreateThread(NULL, 0, &f1, arr, 0, &arr[0]);
if (h[0] == NULL)
_tprintf(_T("%d"), GetLastError());
h[1] = CreateThread(NULL, 0, &f2, arr, 0, &arr[1]);
if (h[1] == NULL)
_tprintf(_T("%d"), GetLastError());
You are creating 2 threads within the body of a for loop which executes twice (AKA 4 threads when you really meant for 2).
You are attempting to save the handles to these threads into a HANDLE array which can only hold one element.
On the second execution of the loop, you have overwritten the elements of h[] again, so when you later wait for them to finish and attempt to close the handles, you are not even closing the same handle.
You need the HANDLE array to be size 2, and you need to remove the first for loop (you are passing the function pointers separately, so there is no way to do this in a loop unless you put the function pointers into an array of the same length as h[]).

Getting md5 hash code for dll file in c++

Hi guys i am trying to get dll md5 hash but it is returning same value all the time, what i did wrong?
this dll is already loaded when i am trying to getHash
i am getting hash with getHash() method and calculating it with CalcHash
thnks in advanced.
#define BUFSIZE 1024
#define MD5LEN 16
int CalcHash(HANDLE hFile, char *md5sum)
{
BOOL bResult = FALSE;
HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
BYTE rgbFile[BUFSIZE];
DWORD cbRead = 0;
BYTE rgbHash[MD5LEN];
DWORD cbHash = 0;
CHAR rgbDigits[] = "0123456789abcdef";
char byt[3];
int rc, err;
rc = CryptAcquireContext(&hProv, NULL, MS_STRONG_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
if(!rc)
{
err = GetLastError();
if(err==0x80090016)
{
//first time using crypto API, need to create a new keyset
rc=CryptAcquireContext(&hProv, NULL, MS_STRONG_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET);
if(!rc)
{
err=GetLastError();
return 0;
}
}
}
CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);
while(bResult = ReadFile(hFile, rgbFile, BUFSIZE, &cbRead, NULL))
{
if (0 == cbRead)
{
break;
}
CryptHashData(hHash, rgbFile, cbRead, 0);
}
cbHash = MD5LEN;
CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0);
md5sum[0] = 0;
for (DWORD i = 0; i < cbHash; i++)
{
sprintf(byt, "%c%c", rgbDigits[rgbHash[i] >> 4], rgbDigits[rgbHash[i] & 0xf]);
strcat(md5sum, byt);
}
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return 1;
}
char *getHash()
{
CalcHash(L"dsetup.dll", md5sum);
Logger(md5sum);
return md5sum;
}

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

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;
}
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.