I'm trying to share an array of structs containing 2 dynamic arrays using shared memory to use the structs in another process. So far I can share an array of structs but these do not contain dynamic arrays yet. Any help on completing this problem would be great.
Expected:
typedef struct {
int id;
int type;
int count;
int[] values;
int[] settings;
} Entry;
Current code:
typedef struct {
int id;
int type;
int count;
} Entry;
BOOL DumpEntries(TCHAR* memName) {
int size = entries.size() * sizeof(Entry) + sizeof(DWORD);
::hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, memName);
if (::hMapObject == NULL) {
return FALSE;
}
::vMapData = MapViewOfFile(::hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, size);
if (::vMapData == NULL) {
CloseHandle(::hMapObject);
return FALSE;
}
(*(DWORD*)::vMapData) = entries.size();
Entry* eArray = (Entry*)(((DWORD*)::vMapData) + 1);
for(int i = entries.size() - 1; i >= 0; i--) eArray[i] = entries.at(i);
UnmapViewOfFile(::vMapData);
return TRUE;
}
BOOL ReadEntries(TCHAR* memName, Entry** entries, DWORD &number_of_entries) {
HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, memName);
if (hMapFile == NULL) {
return FALSE;
}
DWORD *num_entries = (DWORD*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (num_entries == NULL) {
CloseHandle(hMapFile);
return FALSE;
}
number_of_entries = *num_entries;
if(number_of_entries == 0)
{
// special case: when no entries was found in buffer
*entries = NULL;
return true;
}
Entry* tmpEntries = (Entry*)(num_entries + 1);
*entries = new Entry[*num_entries];
for (UINT i = 0; i < *num_entries; i++) {
(*entries)[i] = tmpEntries[i];
}
UnmapViewOfFile(num_entries);
CloseHandle(hMapFile);
return TRUE;
}
You can't pass pointers across process boundaries, so you can't store pointers inside the struct items that you put in the shared memory. What you can do is allocate the shared memory block itself to be large enough to hold all of the array data, and then use offsets to access the various arrays as needed, eg:
typedef struct
{
int id;
int type;
int count;
int *values;
int *settings;
} Entry;
#pragma pack(push, 1)
typedef struct
{
int id;
int type;
int count;
DWORD values_offset;
DWORD values_count; // if different than 'int count'
DWORD settings_offset;
DWORD settings_count; // if different than 'int count'
} SharedMemEntry;
#pragma pack(pop)
BOOL DumpEntries(TCHAR* memName)
{
DWORD NumValues = 0;
DWORD NumSettings = 0;
// or whatever your container actually is...
for(std::vector<Entry>::reverse_iterator iter = entries.rbegin();
iter != entries.rend(); ++iter)
{
Entry &e = *iter;
// or whatever you have to do to calculate how many
// integers are in the values[] and settings[] arrays...
//
NumValues += e.count;
NumSettings += e.count;
}
DWORD memsize = sizeof(DWORD) +
(entries.size() * sizeof(SharedMemEntry)) +
(sizeof(int) * NumValues) +
(sizeof(int) * NumSettings);
if (hMapObject != NULL)
CloseHandle(hMapObject);
hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, memsize, memName);
if (hMapObject == NULL) {
return FALSE;
}
BYTE *vMapData = (BYTE*) MapViewOfFile(hMapObject, FILE_MAP_WRITE, 0, 0, memsize);
if (vMapData == NULL) {
CloseHandle(hMapObject);
hMapObject = NULL;
return FALSE;
}
DWORD *pEntryCount = (DWORD*) vMapData;
*pEntryCount = entries.size();
SharedMemEntry* pEntries = (SharedMemEntry*) (pEntryCount + 1);
int *pValues = (int*) (pEntries + entries.size());
int *pSettings = (int*) (pValues + NumValues);
// or whatever your container actually is...
for(std::vector<Entry>::reverse_iterator iter = entries.rbegin();
iter != entries.rend(); ++iter)
{
Entry &e = *iter;
SharedMemEntry &eEntry = *pEntries++;
eEntry.id = e.id;
eEntry.type = e.type;
eEntry.count = e.count;
eEntry.values_offset = ((BYTE*)pValues - vMapData);
eEntry.values_count = e.count; // or whatever you need...
for(DWORD k = 0; k < eEntry.values_count; ++k) {
*pValues++ = e.values[k];
}
eEntry.settings_offset = ((BYTE*)pSettings - vMapData);
eEntry.settings_count = e.count; // or whatever you need...
for(DWORD k = 0; k < eEntry.settings_count; ++k) {
*pSettings++ = e.settings[k];
}
}
UnmapViewOfFile(vMapData);
return TRUE;
}
BOOL ReadEntries(TCHAR* memName, Entry** entries, DWORD &num_entries)
{
HANDLE hMapFile = OpenFileMapping(FILE_MAP_READ, FALSE, memName);
if (hMapFile == NULL) {
return FALSE;
}
BYTE *vMapData = (BYTE*) MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
if (vMapData == NULL) {
CloseHandle(hMapFile);
return FALSE;
}
DWORD *pEntryCount = (DWORD*) vMapData;
num_entries = *pEntryCount;
if (num_entries == 0)
{
// special case: when no entries was found in buffer
*entries = NULL;
}
else
{
SharedMemEntry *pEntries = (SharedMemEntry*) (pEntryCount + 1);
*entries = new Entry[num_entries];
for (DWORD i = 0; i < num_entries; ++i)
{
Entry &e = (*entries)[i];
SharedMemEntry &eEntry = pEntries[i];
e.id = eEntry.id;
e.type = eEntry.type;
e.count = eEntry.count;
e.values = new int[eEntry.values_count];
e.settings = new int[eEntry.settings_count];
int *pValues = (int*) (vMapData + eEntry.values_offset);
for(DWORD j = 0; j < eEntry.values_count; ++j) {
e.values[j] = pValues[j];
}
int *pSettings = (int*) (vMapData + eEntry.settings_offset);
for(DWORD j = 0; j < eEntry.settings_count; ++j) {
e.settings[j] = pSettings[j];
}
}
}
UnmapViewOfFile(vMapData);
CloseHandle(hMapFile);
return TRUE;
}
Alternatively, you should consider automating the memory management and loops instead of doing everything manually:
typedef struct
{
int id;
int type;
int count;
std::vector<int> values;
std::vector<int> settings;
} Entry;
#pragma pack(push, 1)
typedef struct
{
int id;
int type;
int count;
DWORD values_offset;
DWORD values_count; // if different than 'int count'
DWORD settings_offset;
DWORD settings_count; // if different than 'int count'
} SharedMemEntry;
#pragma pack(pop)
BOOL DumpEntries(TCHAR* memName)
{
DWORD NumValues = 0;
DWORD NumSettings = 0;
// or whatever your container actually is...
for(std::vector<Entry>::reverse_iterator iter = entries.rbegin();
iter != entries.rend(); ++iter)
{
Entry &e = *iter;
NumValues += e.values.size();
NumSettings += e.settings.size();
}
DWORD memsize = sizeof(DWORD) +
(entries.size() * sizeof(SharedMemEntry)) +
(sizeof(int) * NumValues) +
(sizeof(int) * NumSettings);
if (hMapObject != NULL)
CloseHandle(hMapObject);
hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, memsize, memName);
if (!hMapObject) {
return FALSE;
}
std::unique_ptr<void, decltype(&UnmapViewOfFile)> uMapData( MapViewOfFile(hMapObject, FILE_MAP_WRITE, 0, 0, memsize), &UnmapViewOfFile );
BYTE *vMapData = (BYTE*) uMapData.get();
if (!vMapData) {
CloseHandle(hMapObject);
hMapObject = NULL;
return FALSE;
}
DWORD *pEntryCount = (DWORD*) vMapData;
*pEntryCount = entries.size();
SharedMemEntry* pEntries = (SharedMemEntry*) (pEntryCount + 1);
int *pValues = (int*) (pEntries + entries.size());
int *pSettings = (int*) (pValues + NumValues);
// or whatever your container actually is...
for(std::vector<Entry>::reverse_iterator iter = entries.rbegin();
iter != entries.rend(); ++iter)
{
Entry &e = *iter;
SharedMemEntry &eEntry = *pEntries++;
eEntry.id = e.id;
eEntry.type = e.type;
eEntry.count = e.count;
eEntry.values_offset = ((BYTE*)pValues - vMapData);
eEntry.values_count = e.values.size();
pValues = std::copy(e.values.begin(), e.values.end(), pValues);
eEntry.settings_offset = ((BYTE*)pSettings - vMapData);
eEntry.settings_count = e.settings.size();
pSettings = std::copy(e.settings.begin(), e.settings.end(), pSettings);
}
return TRUE;
}
// or whatever container type you want...
BOOL ReadEntries(TCHAR* memName, std::vector<Entry> &entries)
{
entries.clear();
std::unique_ptr<std::remove_pointer<HANDLE>::type, decltype(&CloseHandle)> uMapFile( OpenFileMapping(FILE_MAP_READ, FALSE, memName), &CloseHandle );
HANDLE hMapFile = uMapFile.get();
if (!hMapFile) {
return FALSE;
}
std::unique_ptr<void, decltype(&UnmapViewOfFile)> uMapData( MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0), &UnmapViewOfFile );
BYTE *vMapData = (BYTE*) uMapData.get();
if (!vMapData) {
return FALSE;
}
DWORD *pEntryCount = (DWORD*) vMapData;
DWORD num_entries = *pEntryCount;
if (num_entries != 0)
{
entries.resize(num_entries);
SharedMemEntry *pEntries = (SharedMemEntry*) (pEntryCount + 1);
for (DWORD i = 0; i < num_entries; ++i)
{
Entry &e = entries[i];
SharedMemEntry &eEntry = pEntries[i];
e.id = eEntry.id;
e.type = eEntry.type;
e.count = eEntry.count;
e.values.reserve(eEntry.values_count);
e.settings.reserve(eEntry.settings_count);
int *pValues = (int*) (vMapData + eEntry.values_offset);
std::copy(pValues, pValues + eEntry.values_count, std::back_inserter(e.values));
int *pSettings = (int*) (vMapData + eEntry.settings_offset);
std::copy(pSettings, pSettings + eEntry.settings_count, std::back_inserter(e.settings));
}
}
return TRUE;
}
Either way, make sure you provide some kind of synchronization between DumpEntries() and ReadEntries(), such as with shared events from CreateEvent(), so that ReadEntries() does not try to read from the memory while DumpEntries() is still writing to it, and vice versa.
Related
I use the following function to get the name of the connected WiFi connection. The function is called repeatedly every 4 seconds to monitor connection changes. But after a while, the function no longer works as before, and fails returning false.
bool GetConnectedConnectionsName(wstring connection_names[50], int& number)
{
HANDLE h_client = NULL;
DWORD dwMaxClient = 2;
DWORD dwCurVersion = 0;
DWORD result = 0;
DWORD dwRetVal = 0;
int iRet = 0;
WCHAR GuidString[39] = { 0 };
unsigned int i, j, k;
PWLAN_INTERFACE_INFO_LIST p_if_list = NULL;
PWLAN_INTERFACE_INFO p_if_info = NULL;
PWLAN_AVAILABLE_NETWORK_LIST p_bss_list = NULL;
PWLAN_AVAILABLE_NETWORK p_bss_entry = NULL;
int iRSSI = 0;
result = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &h_client);
if (result != ERROR_SUCCESS)
{
if (p_bss_list != NULL)
WlanFreeMemory(p_bss_list);
if (p_if_list != NULL)
WlanFreeMemory(p_if_list);
return false;
}
result = WlanEnumInterfaces(h_client, NULL, &p_if_list);
if (result != ERROR_SUCCESS)
{
if (p_bss_list != NULL)
WlanFreeMemory(p_bss_list);
if (p_if_list != NULL)
WlanFreeMemory(p_if_list);
return false;
}
for (i = 0; i < (int)p_if_list->dwNumberOfItems; i++)
{
p_if_info = (WLAN_INTERFACE_INFO*)&p_if_list->InterfaceInfo[i];
result = WlanGetAvailableNetworkList(h_client,
&p_if_info->InterfaceGuid,
0,
NULL,
&p_bss_list);
if (result != ERROR_SUCCESS)
{
if (p_bss_list != NULL)
WlanFreeMemory(p_bss_list);
if (p_if_list != NULL)
WlanFreeMemory(p_if_list);
return false;
}
else
{
number = 0;
for (j = 0; j < p_bss_list->dwNumberOfItems; j++)
{
p_bss_entry = (WLAN_AVAILABLE_NETWORK*)&p_bss_list->Network[j];
if (p_bss_entry->dwFlags && (p_bss_entry->dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED))
{
connection_names[number] = wstring(p_bss_entry->strProfileName);
number++;
}
}
}
}
if (p_bss_list != NULL)
WlanFreeMemory(p_bss_list);
if (p_if_list != NULL)
WlanFreeMemory(p_if_list);
return true;
}
What's wrong, and how can I solve the problem?
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.
I am running into memory errors when I try to run my C++ program in Visual Studio 2012. I am thinking that this code is the cause (since when I remove it, it runs fine):
void GetMachineHash(CString &strHashHex) {
CMD5 cMD5;
BYTE *szHash = (BYTE*)malloc(48);
LPBYTE szMachineNameHash, szNetworkAddressHash, szVolumeIdHash;
TCHAR szMachineId[100];
DWORD nMachineIdLen = 100;
TCHAR szNetworkAddress[13];
IP_ADAPTER_INFO *pAdapterInfo, *pAdapter = NULL;
DWORD dwRetVal = 0;
ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
TCHAR szVolumeId[20];
TCHAR szVolumeName[MAX_PATH];
TCHAR szFileSystemName[MAX_PATH];
DWORD dwSerialNumber = 0;
DWORD dwMaxComponentLen = 0;
DWORD dwFileSystemFlags = 0;
ZeroMemory(szHash, 48);
ZeroMemory(szMachineId, 100);
ZeroMemory(szVolumeId, 20);
ZeroMemory(szVolumeName, MAX_PATH);
ZeroMemory(szFileSystemName, MAX_PATH);
ZeroMemory(szNetworkAddress, 13);
GetComputerName(szMachineId, &nMachineIdLen);
cMD5.Calculate(szMachineId);
szMachineNameHash = cMD5.Hash();
pAdapterInfo = (IP_ADAPTER_INFO *) malloc(sizeof(IP_ADAPTER_INFO));
if (pAdapterInfo == NULL) {
TRACE(_T("Error allocating memory needed to call GetAdaptersinfo()"));
szNetworkAddressHash = NULL;
}
// Make an initial call to GetAdaptersInfo to get the necessary size into the ulOutBufLen variable
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
free(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
if (pAdapterInfo == NULL) {
TRACE(_T("Error allocating memory needed to call GetAdaptersinfo()"));
szNetworkAddressHash = NULL;
}
}
if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
pAdapter = pAdapterInfo;
while (pAdapter) {
if (pAdapter->Type != MIB_IF_TYPE_LOOPBACK) {
_stprintf_s(szNetworkAddress, 13, _T("%.2X%.2X%.2X%.2X%.2X%.2X"),
pAdapter->Address[0],
pAdapter->Address[1],
pAdapter->Address[2],
pAdapter->Address[3],
pAdapter->Address[4],
pAdapter->Address[5]
);
break;
}
pAdapter = pAdapter->Next;
}
} else {
TRACE(_T("GetAdaptersInfo() call failed"));
szNetworkAddressHash = NULL;
}
cMD5.Calculate(szNetworkAddress);
szNetworkAddressHash = cMD5.Hash();
if (GetVolumeInformation(
NULL,
szVolumeName,
sizeof(szVolumeName),
&dwSerialNumber,
&dwMaxComponentLen,
&dwFileSystemFlags,
szFileSystemName,
sizeof(szFileSystemName))) {
_stprintf_s(szVolumeId, 20, _T("%lu"), dwSerialNumber);
}
cMD5.Calculate(szVolumeId);
szVolumeIdHash = cMD5.Hash();
// Calculate hash from hashes
memcpy(szHash, szMachineNameHash, 16);
memcpy(szHash+16, szNetworkAddressHash, 16);
memcpy(szHash+32, szVolumeIdHash, 16);
cMD5.Calculate(szHash, 48);
strHashHex.Preallocate(33);
strHashHex = cMD5.HexHash();
free(szHash);
free(pAdapterInfo);
return;
}
And then if I leave the function and just remove this code:
strHashHex.Preallocate(33);
strHashHex = cMD5.HexHash();
Then it will work fine as well. So I am wondering if that is the code that's causing the memory problems, and if it is, how can I fix it?
Here's the CMD5 class (which utilizes the Windows API to generate a MD5 sum):
class CMD5
{
public:
CMD5() {
if(CryptAcquireContext(&m_hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET) == 0){
if(GetLastError() == NTE_EXISTS){
CryptAcquireContext(&m_hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0);
}
}
}
~CMD5() {
if(m_hCryptProv)
CryptReleaseContext(m_hCryptProv, 0);
m_hCryptProv = NULL;
free(m_szHash);
}
bool Calculate(LPCTSTR szText) {
DWORD dwLen = sizeof(TCHAR) * _tcslen(szText);
DWORD dwHashLen;
DWORD dwHashLenSize = sizeof(DWORD);
if (CryptCreateHash(m_hCryptProv, CALG_MD5, 0, 0, &m_hHash)) {
if (CryptHashData(m_hHash, (const BYTE*)szText, dwLen, 0)) {
if (CryptGetHashParam(m_hHash, HP_HASHSIZE, (BYTE *)&dwHashLen, &dwHashLenSize, 0)) {
if(m_szHash = (BYTE*)malloc(dwHashLen)) {
if (CryptGetHashParam(m_hHash, HP_HASHVAL, (BYTE*)m_szHash, &dwHashLen, 0)) {
CryptDestroyHash(m_hHash);
}
}
}
}
}
return false;
}
bool Calculate(const LPBYTE szText, DWORD dwLen) {
DWORD dwHashLen;
DWORD dwHashLenSize = sizeof(DWORD);
if (CryptCreateHash(m_hCryptProv, CALG_MD5, 0, 0, &m_hHash)) {
if (CryptHashData(m_hHash, (const BYTE*)szText, dwLen, 0)) {
if (CryptGetHashParam(m_hHash, HP_HASHSIZE, (BYTE *)&dwHashLen, &dwHashLenSize, 0)) {
if(m_szHash = (BYTE*)malloc(dwHashLen)) {
if (CryptGetHashParam(m_hHash, HP_HASHVAL, (BYTE*)m_szHash, &dwHashLen, 0)) {
CryptDestroyHash(m_hHash);
}
}
}
}
}
return false;
}
LPBYTE Hash() const {
LPBYTE szHash = new BYTE[16];
ZeroMemory(szHash, 16);
memcpy(szHash, m_szHash, 16);
return szHash;
}
LPTSTR HexHash() const {
LPTSTR szBuf = new TCHAR[33];
ZeroMemory(szBuf, 33);
for (int i=0; i<16; i++)
_stprintf_s(szBuf+i*2, 33, _T("%02X"), m_szHash[i]);
szBuf[32]=0;
return szBuf;
}
private:
BYTE *m_szHash;
DWORD m_hHash;
HCRYPTPROV m_hCryptProv;
};
Also, the error I get from VS2012 is Critical error detected c0000374 and the call stack ends with a call to HeapAlloc() from _heap_alloc. Not sure if it matters but this code is being called in a DLL.
It looks like I was able to solve the memory allocation problems by changing the CMD5::HexHash() function to
void HexHash(CString &strHash) {
for (int i=0; i<16; i++)
strHash += StringFormat(_T("%02X"), m_szHash[i]);
return;
}
and call it via cMD5.HexHash(strHashHex);
I have a foreign process (exe-file DllProj.exe is running), that has SampleDll.dll linked to it (implicit linking). I can find the base address of the linked dll with the help of my function imageBase(), but not the base address of the process itself! What is the difference and why it's not working as is?
I mean, this code returns pBase with correct DOS/NT-headers:
LPVOID pBase = imageBase("DllProj.exe", "SampleDll.dll");
if (!pBase)
return false;
PIMAGE_DOS_HEADER pDosHeader = PIMAGE_DOS_HEADER((HMODULE)pBase);
if (::IsBadReadPtr(pDosHeader, sizeof(IMAGE_DOS_HEADER)) ||
IMAGE_DOS_SIGNATURE != pDosHeader->e_magic)
return false;
but this code return is FALSE:
LPVOID pBase = imageBase("DllProj.exe", "DllProj.exe");
//and so on...
Here is my procedure:
LPVOID imageBase(LPSTR szVictimProcess, LPSTR szVictim)
{
//находим процесс szVictimProcess
DWORD aProcesses[1024], cbNeeded, nProcesses;
unsigned int i;
if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
return NULL;
nProcesses = cbNeeded / sizeof(DWORD);
HANDLE ProcHandle = 0;
TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
for (i = 0; i < nProcesses; i++)
{
ProcHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, aProcesses[i]);
if (NULL != ProcHandle)
{
HMODULE hMod[1024];
if ( EnumProcessModules(ProcHandle, hMod, sizeof(hMod), &cbNeeded) )
{
GetModuleBaseName(ProcHandle, hMod[0], szProcessName, sizeof(szProcessName)/sizeof(TCHAR)); // Get the process name
if (0 == lstrcmpiA(szVictimProcess, szProcessName))
{
//находим модуль szVictim
DWORD nModules = cbNeeded / sizeof(HMODULE);
char szModName[MAX_PATH];
for (unsigned int j = 0; j < nModules; j++)
{
if (GetModuleFileNameEx(ProcHandle, hMod[j], szModName, sizeof(szModName))) // Get the module name
{
shortName(szModName);
if (0 == lstrcmpiA(szModName, szVictim))
{
MODULEINFO info;
GetModuleInformation(ProcHandle, hMod[j], &info, sizeof(info));
return info.lpBaseOfDll;
//Equal To:
//return hMod[j];
//Debug:
//LPSTR string = new char[256];
//wsprintf(string,"\t%s (0x%08X)\n", szModName, hMod[j]);
}
}
}
break;
}
}
}
CloseHandle(ProcHandle);
}
return NULL;
}
P.S.: My next goal is to get import-table of DllProj.exe (where Sample.dll is) and hiijack dll's function call
What about using this:
#pragma comment( lib, "psapi" )
DWORD GetModuleBase(HANDLE hProc, string &sModuleName)
{
HMODULE *hModules;
char szBuf[50];
DWORD cModules;
DWORD dwBase = -1;
//------
EnumProcessModules(hProc, hModules, 0, &cModules);
hModules = new HMODULE[cModules/sizeof(HMODULE)];
if(EnumProcessModules(hProc, hModules, cModules/sizeof(HMODULE), &cModules)) {
for(int i = 0; i < cModules/sizeof(HMODULE); i++) {
if(GetModuleBaseName(hProc, hModules[i], szBuf, sizeof(szBuf))) {
if(sModuleName.compare(szBuf) == 0) {
dwBase = (DWORD)hModules[i];
break;
}
}
}
}
delete[] hModules;
return dwBase;
}
Credit to answer here
There is nothing wrong with your code, I compiled your code and it works fine and outputs the correct address to console. Make sure you run as administrator. This is the project using your code which I tested working:
#include <windows.h>
#include <iostream>
#include <psapi.h>
#include <string>
void shortName(LPSTR strToChange)
{
std::string path(strToChange);
std::string filename;
size_t pos = path.find_last_of("\\");
if (pos != std::string::npos)
filename.assign(path.begin() + pos + 1, path.end());
else
filename = path;
lstrcpy(strToChange, filename.data());
}
LPVOID imageBase(LPSTR szVictimProcess, LPSTR szVictim)
{
DWORD aProcesses[1024], cbNeeded, nProcesses;
unsigned int i;
if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
return NULL;
nProcesses = cbNeeded / sizeof(DWORD);
HANDLE ProcHandle = 0;
TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
for (i = 0; i < nProcesses; i++)
{
ProcHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, aProcesses[i]);
if (NULL != ProcHandle)
{
HMODULE hMod[1024];
if (EnumProcessModules(ProcHandle, hMod, sizeof(hMod), &cbNeeded))
{
GetModuleBaseName(ProcHandle, hMod[0], szProcessName, sizeof(szProcessName) / sizeof(TCHAR)); // Get the process name
if (0 == lstrcmpiA(szVictimProcess, szProcessName))
{
DWORD nModules = cbNeeded / sizeof(HMODULE);
char szModName[MAX_PATH];
for (unsigned int j = 0; j < nModules; j++)
{
if (GetModuleFileNameEx(ProcHandle, hMod[j], szModName, sizeof(szModName))) // Get the module name
{
shortName(szModName);
if (0 == lstrcmpiA(szModName, szVictim))
{
MODULEINFO info;
GetModuleInformation(ProcHandle, hMod[j], &info, sizeof(info));
return info.lpBaseOfDll;
}
}
}
break;
}
}
}
CloseHandle(ProcHandle);
}
return NULL;
}
int main(void)
{
void* base = imageBase((char*)"ac_client.exe", (char*)"ac_client.exe");
std::cout << "0x" << std::hex << base;
}
I know that in c# I can do:
Process currentProcess = System.Diagnostics.Process.GetCurrentProcess();
currentProcess.Modules[0].BaseAddress
currentProcess.Modules[0].EntryPointAddress
How would I get this information in C++?
Taking a look I have:
void
get_module_name_for_address(LPVOID address,
TCHAR *buf, int buf_size)
{
HANDLE process;
HMODULE modules[256];
DWORD bytes_needed, num_modules;
unsigned int i;
buf[0] = '\0';
process = GetCurrentProcess();
if (EnumProcessModules(process, (HMODULE *) &modules,
sizeof(modules), &bytes_needed) == 0)
{
return;
}
if (bytes_needed > sizeof(modules))
bytes_needed = sizeof(modules);
num_modules = bytes_needed / sizeof(HMODULE);
for (i = 0; i < num_modules; i++)
{
MODULEINFO mi;
if (GetModuleInformation(process, modules[i], &mi, sizeof(mi)) != 0)
{
LPVOID start, end;
start = mi.lpBaseOfDll;
end = (char *) start + mi.SizeOfImage;
if (address >= start && address <= end)
{
GetModuleBaseName(process, modules[i], buf, buf_size);
return;
}
}
}
}
GetModuleInformation() in unmanaged code: http://msdn.microsoft.com/en-us/library/ms683201%28v=VS.85%29.aspx