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

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.

Related

Add actual timestamp to mp4 using ffmpeg

I'm using ffmpeg to write an h264 stream to a mp4 file.
Everything is working, but now I need to embed to this file the actual timestamp in milliseconds of each frame.
Is it possible?
This is my code:
void mp4_file_create(mp4_par * par, t_image * img_in)
{
AVCodec * codec = NULL;
AVCodecContext * cc_in;
AVFormatContext * av_fmt_ctx_out;
AVStream * av_stream;
AVPacket av_pkt;
AVFormatContext * ifmt_ctx;
unsigned long long last_frame_ts_utc;
unsigned long long last_frame_ts_absolute;
unsigned long long last_pts;
t_mp4_dict_metadata metadata;
char file_name[1024];
char TSstrdate[128];
av_register_all();
cc_in = NULL;
av_stream = NULL;
if (avformat_alloc_output_context2(&mp4h->av_fmt_ctx_out, NULL, NULL, file_name) < 0) {
trace_error("avformat_alloc_output_context2 failed");
goto FnExit;
}
/* find the H264 RAW encoder */
codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!codec) {
int ret;
AVStream *in_stream = NULL;
if (av_fmt_ctx_in == NULL)
{
trace_error("av_fmt_ctx_in is NULL");
goto FnExit;
}
in_stream = av_fmt_ctx_in->streams[0];
in_stream->codec->width = par.width;
in_stream->codec->height = par.height;
in_stream->codec->coded_width = par.width;
in_stream->codec->coded_height = par.height;
in_stream->codec->bit_rate = 1024;
in_stream->codec->flags = CODEC_FLAG_GLOBAL_HEADER;
in_stream->codec->time_base.num = 1;
in_stream->codec->time_base.den = par.frame_rate;
in_stream->codec->gop_size = par.gop;
in_stream->codec->pix_fmt = AV_PIX_FMT_YUV420P;
av_stream = avformat_new_stream(mp4h->av_fmt_ctx_out, in_stream->codec->codec);
if (!av_stream) {
trace_error("Failed allocating output stream");
goto FnExit;
}
ret = avcodec_copy_context(av_stream->codec, in_stream->codec);
if (ret != 0) {
goto FnExit;
}
}
else {
int ret;
av_stream = avformat_new_stream(mp4h->av_fmt_ctx_out, NULL);
if (!av_stream) {
goto FnExit;
}
cc_in = avcodec_alloc_context3(codec);
if (cc_in == NULL) {
goto FnExit;
}
cc_in->width = par.width;
cc_in->height = par.height;
cc_in->bit_rate = 1024;
cc_in->flags = CODEC_FLAG_GLOBAL_HEADER;
cc_in->time_base.num = 1;
cc_in->time_base.den = par.frame_rate;
cc_in->gop_size = par.gop;
cc_in->pix_fmt = AV_PIX_FMT_YUVJ420P;
cc_in->extradata = (unsigned char*)av_mallocz(sizeof(sample_spspps));
cc_in->extradata_size = sizeof(sample_spspps);
memcpy(cc_in->extradata, sample_spspps, cc_in->extradata_size);
ret = avcodec_copy_context(av_stream->codec, cc_in);
if (ret != 0) {
goto FnExit;
}
}
av_stream->codec->codec_tag = 0;
if (av_fmt_ctx_out->oformat->flags & AVFMT_GLOBALHEADER)
av_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
if (!(av_fmt_ctx_out->flags & AVFMT_NOFILE)) {
int ret = avio_open(&av_fmt_ctx_out->pb, file_name, AVIO_FLAG_READ_WRITE);
if (ret < 0) {
trace_error("Could not open output file '%s'", file_name);
goto FnExit;
}
}
av_fmt_ctx_out->streams[0]->time_base.num = 1;
av_fmt_ctx_out->streams[0]->time_base.den = par.frame_rate;
av_fmt_ctx_out->streams[0]->codec->time_base.num = 1;
av_fmt_ctx_out->streams[0]->codec->time_base.den = par.frame_rate;
AVRational fps;
fps.num = 1;
fps.den = par.frame_rate;
av_stream_set_r_frame_rate(av_fmt_ctx_out->streams[0], fps);
mp4h->av_fmt_ctx_out->streams[0]->first_dts = AV_TIME_BASE;
av_dict_set(&pMetaData, "title", par.guid_video_function, 0);
av_dict_set(&pMetaData, "artist", "Test Artist", 0);
av_dict_set(&pMetaData, "date", TSstrdate, 0);
av_fmt_ctx_out->metadata = pMetaData;
if (avformat_write_header(av_fmt_ctx_out, NULL) < 0) {
goto FnExit;
}
//............. Now for each frame_rate........
av_init_packet(&av_pkt);
if (first_frame)
{
av_pkt.pts = 0;
av_pkt.dts = 0;
}
else
{
av_pkt.pts = last_pts + (long long int)((img->timestamp_absolute - last_frame_ts_absolute) * (unsigned long long)av_stream->time_base.den / 1000000ULL);
av_pkt.dts = last_pts + (long long int)((img->timestamp_absolute - last_frame_ts_absolute) * (unsigned long long)av_stream->time_base.den / 1000000ULL);
}
mp4h->av_pkt.duration = 0;
mp4h->av_pkt.pos = -1;
last_frame_ts_utc = img->timestamp_utc.t;
last_frame_ts_absolute = img->timestamp_absolute.t;
last_pts = av_pkt.pts;
if (img->type == keyframe)
{
av_pkt.flags |= AV_PKT_FLAG_KEY;
}
av_pkt.data = img->ptr;
av_pkt.size = img->size;
av_pkt.stream_index = av_stream->index;
ret = av_interleaved_write_frame(av_fmt_ctx_out, &av_pkt);
if (ret != 0) {
char strE[256];
av_strerror(ret, strE, sizeof(strE));
trace_error("av_write_frame returns %d - %s", ret, strE);
return;
}
//........then I will close the file
FnExit:
if (av_fmt_ctx_out && av_fmt_ctx_out->pb != NULL) {
if (av_write_trailer(mp4h->av_fmt_ctx_out) != 0) {
trace_error("av_write_trailer Error!");
}
}
if (ifmt_ctx)
avformat_close_input(&ifmt_ctx);
avio_closep(&av_fmt_ctx_out->pb);
avcodec_close(av_stream->codec);
avformat_free_context(av_fmt_ctx_out);
}
How can I modify it in order to embed the actual timestamp of each frame?
I tried to add the actual timestamp to the first frame pts instead of setting it to zero, but it didn't work.

C++ WINAPI Shared memory dynamic arrays

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.

How to detect USB speed on Windows

I use setup API functions to find a USB device then use createfile to communicate with it. i.e. using SetupDiGetClassDevs, SetupDiEnumDeviceInterfaces, SetupDiGetDeviceInterfaceDetail, etc.
I would like to be able to determine if the device is connected at USB2 speeds or USB3 speeds ie. SuperSpeed or not
How can I do this through the Windows APIs?
This is what I ended up going with. It's convoluted. Cant believe there isn't an easier way:
#include "stdafx.h"
#include <Windows.h>
#include <Setupapi.h>
#include <winusb.h>
#undef LowSpeed
#include <Usbioctl.h>
#include <iostream>
#include <string>
#include <memory>
#include <vector>
class Usb_Device
{
private:
std::wstring _driverKey;
char _speed;
public:
Usb_Device(int adapterNumber, std::wstring devicePath, char speed);
virtual char GetSpeed(std::wstring driverKey);
};
class Usb_Hub : public Usb_Device
{
private:
bool _isRootHub;
std::wstring _deviceDescription;
std::wstring _devicePath;
std::vector<std::unique_ptr<Usb_Device>> _devices;
public:
Usb_Hub(std::wstring devicePath, char speed);
virtual char GetSpeed(std::wstring driverKey) override;
};
class Usb_Controller
{
private:
GUID _interfaceClassGuid;
std::wstring _devicePath;
std::wstring _deviceDescription;
std::wstring _driverKey;
std::vector<std::unique_ptr<Usb_Device>> _devices;
public:
Usb_Controller();
char GetSpeed(std::wstring driverKey);
};
static std::unique_ptr<Usb_Device> BuildDevice(int portCount, std::wstring devicePath)
{
std::unique_ptr<Usb_Device> ret;
HANDLE handle = INVALID_HANDLE_VALUE;
DWORD bytes = -1;
DWORD bytesReturned = -1;
BOOL isConnected = FALSE;
char speed;
// Open a handle to the Hub device
handle = CreateFile(devicePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (handle != INVALID_HANDLE_VALUE)
{
bytes = sizeof(USB_NODE_CONNECTION_INFORMATION_EX);
PUSB_NODE_CONNECTION_INFORMATION_EX nodeConnection = (PUSB_NODE_CONNECTION_INFORMATION_EX)(new char[bytes]);
nodeConnection->ConnectionIndex = portCount;
if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, nodeConnection, bytes, nodeConnection, bytes, &bytesReturned, 0))
{
isConnected = nodeConnection->ConnectionStatus == USB_CONNECTION_STATUS::DeviceConnected;
speed = nodeConnection->Speed;
}
if (isConnected)
{
if (nodeConnection->DeviceDescriptor.bDeviceClass == 0x09 /*HubDevice*/)
{
bytes = sizeof(USB_NODE_CONNECTION_NAME);
PUSB_NODE_CONNECTION_NAME nodeConnectionName = (PUSB_NODE_CONNECTION_NAME)(new char[bytes]);
nodeConnectionName->ConnectionIndex = portCount;
if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_NAME, nodeConnectionName, bytes, nodeConnectionName, bytes, &bytesReturned, 0))
{
bytes = nodeConnectionName->ActualLength;
delete[] nodeConnectionName;
nodeConnectionName = (PUSB_NODE_CONNECTION_NAME)(new char[bytes]);
nodeConnectionName->ConnectionIndex = portCount;
if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_NAME, nodeConnectionName, bytes, nodeConnectionName, bytes, &bytesReturned, 0))
{
std::wstring name = std::wstring(L"\\\\?\\") + std::wstring(nodeConnectionName->NodeName);
ret = std::unique_ptr<Usb_Device>(new Usb_Hub(name, speed));
}
}
delete[] nodeConnectionName;
}
else
{
ret = std::unique_ptr<Usb_Device>(new Usb_Device(portCount, devicePath, speed));
}
}
else
{
// Chuck this device
}
delete[] nodeConnection;
CloseHandle(handle);
}
return ret;
}
Usb_Controller::Usb_Controller()
{
BOOL success = TRUE;
for (int index = 0; success; index++)
{
GUID guid;
HRESULT hr = CLSIDFromString(L"{3abf6f2d-71c4-462a-8a92-1e6861e6af27}", (LPCLSID)&guid);
unsigned char* ptr = new unsigned char[2048]; // Should really do two calls, but that's more effort
HDEVINFO deviceInfoHandle = SetupDiGetClassDevs(&guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
// Create a device interface data structure
SP_DEVICE_INTERFACE_DATA deviceInterfaceData = { 0 };
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
// Start the enumeration.
success = SetupDiEnumDeviceInterfaces(deviceInfoHandle, 0, &guid, index, &deviceInterfaceData);
if (success)
{
_interfaceClassGuid = deviceInterfaceData.InterfaceClassGuid;
// Build a DevInfo data structure.
SP_DEVINFO_DATA deviceInfoData = { 0 };
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
// Now we can get some more detailed informations.
DWORD nRequiredSize = 0;
SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterfaceData, 0, 0, &nRequiredSize, 0);
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(new char[nRequiredSize]);
memset(deviceInterfaceDetailData, 0, nRequiredSize);
deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterfaceData, deviceInterfaceDetailData, nRequiredSize, &nRequiredSize, &deviceInfoData))
{
_devicePath = deviceInterfaceDetailData->DevicePath;
// Get the device description and driver key name.
DWORD requiredSize = 0;
DWORD regType = REG_SZ;
if (SetupDiGetDeviceRegistryProperty(deviceInfoHandle, &deviceInfoData, SPDRP_DEVICEDESC, &regType, ptr, 2048, &requiredSize))
{
_deviceDescription = reinterpret_cast<wchar_t*>(ptr);
}
if (SetupDiGetDeviceRegistryProperty(deviceInfoHandle, &deviceInfoData, SPDRP_DRIVER, &regType, ptr, 2048, &requiredSize))
{
_driverKey = reinterpret_cast<wchar_t*>(ptr);
}
}
delete[] deviceInterfaceDetailData;
}
SetupDiDestroyDeviceInfoList(deviceInfoHandle);
std::unique_ptr<Usb_Device> hub(new Usb_Hub(_devicePath, -1));
_devices.push_back(std::move(hub));
}
else
{
success = false;
}
delete[] ptr;
}
}
char Usb_Controller::GetSpeed(std::wstring driverKey)
{
char speed = -1;
for (auto it = _devices.begin(); it != _devices.end() && speed == -1; ++it)
{
if (*it != nullptr)
{
speed = (*it)->GetSpeed(driverKey);
}
}
return speed;
}
Usb_Hub::Usb_Hub(std::wstring devicePath, char speed) :
Usb_Device(-1, devicePath, speed)
{
HANDLE handle1 = INVALID_HANDLE_VALUE;
HANDLE handle2 = INVALID_HANDLE_VALUE;
_deviceDescription = L"Standard-USB-Hub";
_devicePath = devicePath;
DWORD bytesReturned = -1;
DWORD bytes = -1;
BOOL success = TRUE;
// Open a handle to the host controller.
handle1 = CreateFile(devicePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (handle1 != INVALID_HANDLE_VALUE)
{
USB_ROOT_HUB_NAME rootHubName;
memset(&rootHubName, 0, sizeof(USB_ROOT_HUB_NAME));
// Get the root hub name.
if (DeviceIoControl(handle1, IOCTL_USB_GET_ROOT_HUB_NAME, nullptr, 0, &rootHubName, sizeof(USB_ROOT_HUB_NAME), &bytesReturned, 0))
{
if (rootHubName.ActualLength > 0)
{
PUSB_ROOT_HUB_NAME actualRootHubName = (PUSB_ROOT_HUB_NAME)(new char[rootHubName.ActualLength]);
if (DeviceIoControl(handle1, IOCTL_USB_GET_ROOT_HUB_NAME, nullptr, 0, actualRootHubName, rootHubName.ActualLength, &bytesReturned, 0))
{
_isRootHub = true;
_deviceDescription = L"RootHub";
_devicePath = std::wstring(L"\\\\?\\") + std::wstring(actualRootHubName->RootHubName);
}
delete[] actualRootHubName;
}
}
// Now let's open the hub (based upon the hub name we got above).
int PortCount = 0;
handle2 = CreateFile(_devicePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (handle2 != INVALID_HANDLE_VALUE)
{
bytes = sizeof(USB_NODE_INFORMATION);
PUSB_NODE_INFORMATION nodeInfo = (PUSB_NODE_INFORMATION)(new char[bytes]);
memset(nodeInfo, 0, sizeof(USB_NODE_INFORMATION));
nodeInfo->NodeType = USB_HUB_NODE::UsbHub;
// Get the hub information.
if (DeviceIoControl(handle2, IOCTL_USB_GET_NODE_INFORMATION, nodeInfo, bytes, nodeInfo, bytes, &bytesReturned, 0))
{
DWORD d = GetLastError();
PortCount = nodeInfo->u.HubInformation.HubDescriptor.bNumberOfPorts;
}
delete[] nodeInfo;
CloseHandle(handle2);
}
CloseHandle(handle1);
for (int index = 1; index <= PortCount; index++)
{
std::unique_ptr<Usb_Device> device = BuildDevice(index, _devicePath);
_devices.push_back(std::move(device));
}
}
else
{
success = FALSE;
}
}
char Usb_Hub::GetSpeed(std::wstring driverKey)
{
char speed = Usb_Device::GetSpeed(driverKey);
if (speed == -1)
{
for (auto it = _devices.begin(); it != _devices.end() && speed == -1; ++it)
{
if (*it != nullptr)
{
speed = (*it)->GetSpeed(driverKey);
}
}
}
return speed;
}
Usb_Device::Usb_Device(int adapterNumber, std::wstring devicePath, char speed)
{
_speed = speed;
HANDLE handle = CreateFile(devicePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (handle != INVALID_HANDLE_VALUE)
{
// Get the Driver Key Name (usefull in locating a device)
DWORD bytesReturned = -1;
DWORD bytes = sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
PUSB_NODE_CONNECTION_DRIVERKEY_NAME driverKey = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)(new char[bytes]);
driverKey->ConnectionIndex = adapterNumber;
// Use an IOCTL call to request the Driver Key Name
if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, driverKey, bytes, driverKey, bytes, &bytesReturned, 0))
{
bytes = driverKey->ActualLength;
delete[] driverKey;
driverKey = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)(new char[bytes]);
driverKey->ConnectionIndex = adapterNumber;
if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, driverKey, bytes, driverKey, bytes, &bytesReturned, 0))
{
_driverKey = driverKey->DriverKeyName;
}
}
delete[] driverKey;
CloseHandle(handle);
}
}
char Usb_Device::GetSpeed(std::wstring driverKey)
{
return _speed;
}
int main()
{
Usb_Controller controller;
GUID guid;
HRESULT hr = CLSIDFromString(L"{AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA}", (LPCLSID)&guid);
HDEVINFO deviceInfoHandle = SetupDiGetClassDevs(&guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (deviceInfoHandle != INVALID_HANDLE_VALUE)
{
int deviceIndex = 0;
while (true)
{
SP_DEVICE_INTERFACE_DATA deviceInterface = { 0 };
deviceInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if (SetupDiEnumDeviceInterfaces(deviceInfoHandle, 0, &guid, deviceIndex, &deviceInterface))
{
DWORD cbRequired = 0;
SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface, 0, 0, &cbRequired, 0);
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(new char[cbRequired]);
memset(deviceInterfaceDetail, 0, cbRequired);
deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (!SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface, deviceInterfaceDetail, cbRequired, &cbRequired, 0))
{
deviceIndex++;
continue;
}
// Initialize the structure before using it.
memset(deviceInterfaceDetail, 0, cbRequired);
deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
// Call the API a second time to retrieve the actual
// device path string.
BOOL status = SetupDiGetDeviceInterfaceDetail(
deviceInfoHandle, // Handle to device information set
&deviceInterface, // Pointer to current node in devinfo set
deviceInterfaceDetail, // Pointer to buffer to receive device path
cbRequired, // Length of user-allocated buffer
&cbRequired, // Pointer to arg to receive required buffer length
NULL); // Not interested in additional data
BOOL success = TRUE;
for (int i = 0; success; i++)
{
SP_DEVINFO_DATA deviceInterfaceData = { 0 };
deviceInterfaceData.cbSize = sizeof(SP_DEVINFO_DATA);
// Start the enumeration.
success = SetupDiEnumDeviceInfo(deviceInfoHandle, i, &deviceInterfaceData);
DWORD RequiredSize = 0;
DWORD regType = REG_SZ;
unsigned char* ptr = new unsigned char[2048];
if (SetupDiGetDeviceRegistryProperty(deviceInfoHandle, &deviceInterfaceData, SPDRP_DRIVER, &regType, ptr, 2048, &RequiredSize))
{
char speed = controller.GetSpeed(reinterpret_cast<wchar_t*>(ptr));
std::wcout << std::wstring(reinterpret_cast<wchar_t*>(ptr)) << std::endl;
std::wcout << L"Speed: " << (int)speed << std::endl;
}
delete[] ptr;
}
auto hDeviceHandle = CreateFile(
deviceInterfaceDetail->DevicePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
CloseHandle(hDeviceHandle);
delete[] deviceInterfaceDetail;
}
}
else
{
break;
}
++deviceIndex;
}
SetupDiDestroyDeviceInfoList(deviceInfoHandle);
}
return 0;
}
I guess you will have to try WinUSB in the link there's a sample code of detecting the speed of USB. If you want the description of WinUSB you will find it here.

Thread not completing properly, preventing application close

I'm writing a win32 form application and drawing it with Direct2D. I have a few cross threaded functions to do animations on it and I'm doing web requests with WinHTTP. The issue is, when I use any WinHttp functions (even just opening an HINTERNET session), it will cause the thread not to terminate properly. After I run the 'login' process once, the program cannot exit calmly. I've posted the relevant code below:
//the login process
void __cdecl processloginasync(void* arg)
{
//getting text from textboxes, etc.
if(usernamestr.find(L'#') != wstring::npos && usernamestr.find(L".") != wstring::npos) {
swapdrawmode(1);
_beginthread(loadwheel,NULL,arg);
void* result = NULL;
unsigned sz = 0;
int rescode = web_request(L"appurl.mywebsite.com/func.php",ss.str().c_str(),result,sz);
//other code to handle the reply...
swapdrawmode(0);
}
else {
error_str = L"Invalid email address.";
err = TRUE;
}
if(err == TRUE) {
textopacity = 0;
animatemode = 0;
_beginthread(animatetext,NULL,arg);
}
//I realize I haven't called 'free' on result, I'll fix that.
}
//the web_request function
int web_request (const wchar_t* server, const wchar_t* object, void*& dest, unsigned& size)
{
vector<void*> retval;
vector<unsigned> szs;
HINTERNET hSess = NULL, hConn = NULL, hReq = NULL;
int res = 0;
DWORD dwDownloaded = 0;
DWORD dwSize = 0;
DWORD retcode = NULL;
short err = FALSE;
const wchar_t* accepted_types[] = {
L"image/*",
L"text/*",
NULL
};
hSess = WinHttpOpen(L"smartCARS2 Web/1.1",WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if(hSess)
hConn = WinHttpConnect(hSess,server,INTERNET_DEFAULT_HTTP_PORT, NULL);
else {
err = TRUE;
retcode = HTTP_OPEN_FAILED;
}
if(hConn)
hReq = WinHttpOpenRequest(hConn, NULL, object, NULL, WINHTTP_NO_REFERER,accepted_types,NULL);
else {
err = TRUE;
retcode = HTTP_CONN_FAILED;
}
if(hReq)
res = WinHttpSendRequest(hReq, WINHTTP_NO_ADDITIONAL_HEADERS, NULL, WINHTTP_NO_REQUEST_DATA, NULL, NULL, NULL);
else {
err = TRUE;
retcode = HTTP_OPENREQ_FAILED;
}
if(res)
res = WinHttpReceiveResponse(hReq, NULL);
else {
err = TRUE;
retcode = HTTP_SEND_REQ_FAILED;
}
DWORD tsize = 0;
if(res) {
do {
dwSize = 0;
if(!WinHttpQueryDataAvailable(hReq, &dwSize)) {
retcode = HTTP_COULD_NOT_QUERY_SIZE;
err = TRUE;
break;
}
if(!dwSize)
break;
tsize += dwSize;
void* rets = malloc(dwSize + 1);
if(!rets) {
break;
}
if(!WinHttpReadData(hReq, (void*)rets, dwSize, &dwDownloaded)) {
retcode = HTTP_COULD_NOT_READ_DATA;
err = TRUE;
break;
}
if(!dwDownloaded) {
retcode = HTTP_COULD_NOT_DOWNLOAD;
err = TRUE;
break;
}
szs.push_back(dwSize);
retval.push_back(rets);
} while(dwSize > 0);
}
size = tsize;
unsigned int sz = retval.size();
dest = malloc(tsize);
tsize = 0;
for(unsigned i = 0; i < sz; i++) {
memcpy((BYTE*)dest + tsize,retval[i],szs[i]);
free(retval[i]);
tsize += szs[i];
}
if(hSess)
WinHttpCloseHandle(hSess);
if(hConn)
WinHttpCloseHandle(hConn);
if(hReq)
WinHttpCloseHandle(hReq);
if(err == TRUE)
return retcode;
return 0;
}
As far as I know, as soon as the main thread terminates, the others are not waited for. So the problem is probably in your main thread. You just need to attach a debugger if not already being debugged (Debug | Attach to process in VS) to a zombie process and press "Break all", then use "Threads" and "Call stack" windows to figure what's happening.

Change Mac address by adapter description

I'm using the excellent tool provided by Nate True # http://devices.natetrue.com/macshift/
It changes the Mac address by the adapter name. This is the source code:
const int versionMajor = 1;
const int versionMinor = 1;
#include <windows.h>
#include <objbase.h>
#include <netcon.h>
#include <stdio.h>
#include "validmacs.h"
void SetMAC(char * AdapterName, char * NewMAC) {
HKEY hListKey = NULL;
HKEY hKey = NULL;
RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}",
0, KEY_READ, &hListKey);
if (!hListKey) {
printf("Failed to open adapter list key\n");
return;
}
FILETIME writtenTime;
char keyNameBuf[512], keyNameBuf2[512];
DWORD keyNameBufSiz = 512;
DWORD crap;
int i = 0;
bool found = false;
while (RegEnumKeyEx(hListKey, i++, keyNameBuf, &keyNameBufSiz, 0, NULL, NULL, &writtenTime)
== ERROR_SUCCESS) {
_snprintf(keyNameBuf2, 512, "%s\\Connection", keyNameBuf);
hKey = NULL;
RegOpenKeyEx(hListKey, keyNameBuf2, 0, KEY_READ, &hKey);
if (hKey) {
keyNameBufSiz = 512;
if (RegQueryValueEx(hKey, "Name", 0, &crap, (LPBYTE)keyNameBuf2, &keyNameBufSiz)
== ERROR_SUCCESS && strcmp(keyNameBuf2, AdapterName) == 0) {
printf("Adapter ID is %s\n", keyNameBuf);
found = true;
break;
}
RegCloseKey(hKey);
}
keyNameBufSiz = 512;
}
RegCloseKey(hListKey);
if (!found) {
printf("Could not find adapter name '%s'.\nPlease make sure this is the name you gave it in Network Connections.\n", AdapterName);
return;
}
RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}",
0, KEY_READ, &hListKey);
if (!hListKey) {
printf("Failed to open adapter list key in Phase 2\n");
return;
}
i = 0;
char buf[512];
while (RegEnumKeyEx(hListKey, i++, keyNameBuf2, &keyNameBufSiz, 0, NULL, NULL, &writtenTime)
== ERROR_SUCCESS) {
hKey = NULL;
RegOpenKeyEx(hListKey, keyNameBuf2, 0, KEY_READ | KEY_SET_VALUE, &hKey);
if (hKey) {
keyNameBufSiz = 512;
if ((RegQueryValueEx(hKey, "NetCfgInstanceId", 0, &crap, (LPBYTE)buf, &keyNameBufSiz)
== ERROR_SUCCESS) && (strcmp(buf, keyNameBuf) == 0)) {
RegSetValueEx(hKey, "NetworkAddress", 0, REG_SZ, (LPBYTE)NewMAC, strlen(NewMAC) + 1);
//printf("Updating adapter index %s (%s=%s)\n", keyNameBuf2, buf, keyNameBuf);
//break;
}
RegCloseKey(hKey);
}
keyNameBufSiz = 512;
}
RegCloseKey(hListKey);
}
void ResetAdapter(char * AdapterName) {
struct _GUID guid = {0xBA126AD1,0x2166,0x11D1,0};
memcpy(guid.Data4, "\xB1\xD0\x00\x80\x5F\xC1\x27\x0E", 8);
unsigned short * buf = new unsigned short[strlen(AdapterName)+1];
void (__stdcall *NcFreeNetConProperties) (NETCON_PROPERTIES *);
HMODULE NetShell_Dll = LoadLibrary("Netshell.dll");
if (!NetShell_Dll) {
printf("Couldn't load Netshell.dll\n");
return;
}
NcFreeNetConProperties = (void (__stdcall *)(struct tagNETCON_PROPERTIES *))GetProcAddress(NetShell_Dll, "NcFreeNetconProperties");
if (!NcFreeNetConProperties) {
printf("Couldn't load required DLL function\n");
return;
}
for (unsigned int i = 0; i <= strlen(AdapterName); i++) {
buf[i] = AdapterName[i];
}
CoInitialize(0);
INetConnectionManager * pNCM = NULL;
HRESULT hr = ::CoCreateInstance(guid,
NULL,
CLSCTX_ALL,
__uuidof(INetConnectionManager),
(void**)&pNCM);
if (!pNCM)
printf("Failed to instantiate required object\n");
else {
IEnumNetConnection * pENC;
pNCM->EnumConnections(NCME_DEFAULT, &pENC);
if (!pENC) {
printf("Could not enumerate Network Connections\n");
}
else {
INetConnection * pNC;
ULONG fetched;
NETCON_PROPERTIES * pNCP;
do {
pENC->Next(1, &pNC, &fetched);
if (fetched && pNC) {
pNC->GetProperties(&pNCP);
if (pNCP) {
if (wcscmp(pNCP->pszwName, buf) == 0) {
pNC->Disconnect();
pNC->Connect();
}
NcFreeNetConProperties(pNCP);
}
}
} while (fetched);
pENC->Release();
}
pNCM->Release();
}
FreeLibrary(NetShell_Dll);
CoUninitialize ();
}
bool IsValidMAC(char * str) {
if (strlen(str) != 12) return false;
for (int i = 0; i < 12; i++) {
if ((str[i] < '0' || str[i] > '9')
&& (str[i] < 'a' || str[i] > 'f')
&& (str[i] < 'A' || str[i] > 'F')) {
return false;
}
}
return true;
}
void ShowHelp() {
printf("Usage: macshift [options] [mac-address]\n\n");
printf("Options:\n");
printf("\t-i [adapter-name] The adapter name from Network Connections.\n");
printf("\t-r Uses a random MAC address. This is the default.\n");
printf("\t-d Restores the original MAC address.\n");
printf("\t--help Shows this screen.\n\n");
printf("Macshift uses special undocumented functions in the Windows COM Interface that\n");
printf(" allow you to change an adapter's MAC address without needing to restart.\n");
printf("When you change a MAC address, all your connections are closed automatically\n");
printf(" and your adapter is reset.\n");
}
//Generates a random MAC that is actually plausible
void RandomizeMAC(char * newmac) {
_snprintf(newmac, 6, "%06X", rand() % numMacs);
for (int i = 3; i < 6; i++) {
_snprintf(&newmac[i*2], 2, "%02X", rand() & 0xFF);
}
newmac[12] = 0;
}
int main(int argc, char * * argv) {
printf("Macshift v%i.%i, MAC Changing Utility by Nathan True, macshift#natetrue.com\n\n", versionMajor, versionMinor);
//Parse commandline arguments
char * adapter = "Wireless";
char newmac[13];
int i;
if (argc == 1) {
ShowHelp();
return 0;
}
//Start out with a random MAC
srand(GetTickCount());
RandomizeMAC(newmac);
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
switch (argv[i][1]) {
case '-': //Extended argument
if (strcmp(argv[i]+2, "help") == 0) {
ShowHelp();
return 0;
}
break;
case 'r': //Random setting, this is the default
break;
case 'i': //Adapter name follows
if (argc > i + 1) adapter = argv[++i];
break;
case 'd': //Reset the MAC address
newmac[0] = 0;
}
}
else {
if (IsValidMAC(argv[i])) strncpy(newmac, argv[i], 13);
else printf("MAC String %s is not valid. MAC addresses must m/^[0-9a-fA-F]{12}$/.\n", argv[i]);
}
}
printf("Setting MAC on adapter '%s' to %s...\n", adapter, newmac[0] ? newmac : "original MAC");
SetMAC(adapter, newmac);
printf("Resetting adapter...\n");
fflush(stdout);
ResetAdapter(adapter);
printf("Done\n");
return 0;
}
I would like to change the Mac address by the description of an adapter, in addition to the name. So I need to modify this code so that if a matching name is not found, it falls back to changing the mac based on the description.
This is an example adapter:
name: Local Area Connection
description: Marvell Yukon 88E8055 PCI-E Gigabit Ethernet Controller
Unfortunately, being a Java developer I have limited experience with C++, so any help would be greatly appreciated.
Here's a C sample of GetAdaptersInfo, it prints out each adapters name and description (you can easily adapt it for your code by calling SetMAC on a match):
VOID EnumerateNetworkAdapters(VOID)
{
ULONG len = 0;
if (ERROR_BUFFER_OVERFLOW == GetAdaptersInfo(NULL, &len))
{
IP_ADAPTER_INFO *ipai;
ipai = malloc(len);
if (NO_ERROR == GetAdaptersInfo(ipai, &len))
{
IP_ADAPTER_INFO *p = ipai;
do
{
printf("name=%s description=%s\n", p->AdapterName, p->Description);
}
while (p = p->Next);
}
free(ipai);
}
}
Link against "Iphlpapi.lib".
Use GetAdaptersAddresses to get the adapter name(PIP_ADAPTER_ADDRESSES::FriendlyName) by comparing the description(PIP_ADAPTER_ADDRESSES::Description) before the call to SetMAC(). Example can be found in above MSDN link.