I have some trouble with ESC/POS commands. The code below prints well regular text, but when it comes down the ESC/POS commands the printer does nothing. I have tried many different ways how to pass on the data (see cData1 & cData2). Can anyone help with pointing out the correct way how to pass the command? Thanks, Oliver.
HANDLE CreateFileResult;
BOOL bResult;
PSP_INTERFACE_DEVICE_DETAIL_DATA dummy = GetDevices();
if (dummy != 0)
{
CreateFileResult = CreateFile(dummy->DevicePath,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if (INVALID_HANDLE_VALUE == CreateFileResult)
{
std::cout << "Handle Failed " << std::endl;
}
else
{
char cData1[] = { (CHAR)27, (CHAR)112 , CHAR(0), CHAR(255), CHAR(0) };
char cData2[] = { 0x1b, 0x70 ,0x00 ,0xFF ,0x00 };
DWORD dwBytesToWrite = (DWORD)strlen(cData2);
DWORD bytesWritten;
OVERLAPPED osWrite = { 0,0,0 };
WriteFile(CreateFileResult, cData2, dwBytesToWrite, &bytesWritten, &osWrite);
}
So after hours of debugging I found out there are 2 problems with my code:
1) For some reason the ESC/POS command that works with C# + Windows.Devices.USB namespace doesn't work with the current WriteFile approach. My guess is that Windows.Devices.USB does a lot more behind the scenes and somehow manages to make it work. The command that works with simply writefile is 0x1B, 0x70, 0x00, 0x98, 0x00.
2) As written by #JohnnyMopp & #MarkRanson the way how I was measuring buffer size was wrong. Thank you very much for helping out.
Related
I have been able to modify such that the MBR is overwritten with 0 values. However, is it possible to make it such that I only overwrite the last 2 bytes (55h AAh) of the MBR (Boot Signature) to become 00h 00h ?
My code is:
char dataWrite[3] = "\x00\x00";
// Create file of physical drive
HANDLE MasterBootRecord = CreateFile("\\\\.\\PhysicalDrive0"
, GENERIC_ALL, FILE_SHARE_READ | FILE_SHARE_WRITE
, NULL, OPEN_EXISTING, NULL, NULL);
// Set file pointer
DWORD dwPtr1 = SetFilePointer(MasterBootRecord, 510, NULL, NULL);
if (dwPtr1 == INVALID_SET_FILE_POINTER) // Test for failure
{
cout<< "\n\nSetFilePointer Failed to write,Err No: "<< GetLastError();
Sleep(5000);
ExitProcess(0);
}
// Write to file
if (WriteFile(MasterBootRecord, dataWrite, 512, &write, NULL)) {
cout << "Boot signature overwritten." << endl;
Sleep(5000);
ExitProcess(0);
} else...
It turns out successful but the values written to the MBR are wrong. I am rather new to C++ thus am a little confused with this. Any help will be appreciated. Thanks
I want to read the hardware configuration to check if a license for my software is valid. Currently, I tried using WMI. This works fine on many machines for several weeks but sometimes, without an obvious reason, WMI returns the hardware configuration in a different format. For example, the serial number of the primary hard disc is converted from characters to a hex string, with all character hex values being swapped pair wise. I figured out that different Windows user types (admin/normal) influence the format but it also changes in other situations and in different ways, for which I am unable to figure out a pattern.
Does anybody know how to reliably check the hardware configuration using WMI? Or would it be possible to avoid the above problem using MFC?
WMI is indeed unreliable. You should avoid using it when you don't need it.
Here's one way without WMI:
#include <string>
#include <Dbt.h>
#include <winioctl.h>
#include <SetupAPI.h>
#pragma comment(lib, "SetupAPI.lib")
#include <initguid.h>
DWORD getDeviceNumber(HANDLE hDeviceHandle)
{
STORAGE_DEVICE_NUMBER sdn = { 0 };
sdn.DeviceNumber = -1;
DWORD dwBytesReturned = 0;
if (!DeviceIoControl(hDeviceHandle, IOCTL_STORAGE_GET_DEVICE_NUMBER, nullptr, 0, &sdn, sizeof(sdn), &dwBytesReturned, nullptr))
{
return -1; //Error
}
return sdn.DeviceNumber;
}
bool GetDeviceString(std::wstring &out)
{
wchar_t wDevicePath[] = L"\\\\.\\#:";
wDevicePath[4] = L'C'; //Replace this with your drive-letter & adjust code (C: / D: whatever)
HANDLE deviceHandle = CreateFileW(wDevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
if (deviceHandle == INVALID_HANDLE_VALUE)
return false;
DWORD dwVolumeDeviceNumber = getDeviceNumber(deviceHandle);
CloseHandle(deviceHandle);
HDEVINFO hDevInfo = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_DISK, nullptr, nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDevInfo == INVALID_HANDLE_VALUE)
return false; //Error
std::vector<BYTE> buf(1024);
PSP_DEVICE_INTERFACE_DETAIL_DATA_W psp = reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA_W>(buf.data());
SP_DEVICE_INTERFACE_DATA spInt;
SP_DEVINFO_DATA spDev;
spInt.cbSize = sizeof(spInt);
DWORD dwIndex = 0;
while (true)
{
if (!SetupDiEnumDeviceInterfaces(hDevInfo, nullptr, &GUID_DEVINTERFACE_DISK, dwIndex, &spInt))
break;
DWORD dwSize = 0;
SetupDiGetDeviceInterfaceDetailW(hDevInfo, &spInt, nullptr, 0, &dwSize, nullptr);
if (dwSize && dwSize <= buf.size())
{
psp->cbSize = sizeof(*psp);
memset(&spDev, sizeof(spDev), 0);
spDev.cbSize = sizeof(spDev);
long res = SetupDiGetDeviceInterfaceDetailW(hDevInfo, &spInt, psp, dwSize, &dwSize, &spDev);
if (res)
{
HANDLE hDrive = CreateFileW(psp->DevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
if (hDrive != INVALID_HANDLE_VALUE)
{
DWORD dwUsbDeviceNumber = getDeviceNumber(hDrive);
if (dwUsbDeviceNumber == dwVolumeDeviceNumber)
{
//Found
out = psp->DevicePath;
break;
}
}
CloseHandle(hDrive);
}
}
++dwIndex;
}
SetupDiDestroyDeviceInfoList(hDevInfo);
if (out.empty()) //Was not found
return false;
return true;
}
After that, you will get a large device string. You might want to read the needed information out of it.
Check the following regular expressions to retrieve these:
(Note that the string CAN change, depending on the device-type, so test it and add/adjust the regular expressions - these are from an USB-stick test)
ven_([^&#]+) //Vendor String/ID
prod_([^&#]+) //Product String/ID
rev_([^&#]+) //Revision String/ID
&[^#]*#([^&#]+) //Serial String/Number
Regular expressions ? Another example:
std::wregex (see std::basic_regex...).
std::wsmatch (see std::match_results...)
std::wstring wsDeviceString;
if (GetDeviceString(wsDeviceString))
{
std::wregex regexSerialNumber(L"&[^#]*#([^&#]+)");
std::wsmatch match;
if (std::regex_search(wsDeviceString, match, regexSerialNumber))
std::wcout << L"Serial Number of device is: " << match[1].str() << std::endl;
}
One license for your product please =)
Hello to this great community,
I have problems with the automatic conversion of ('\n') 0x0A to ('\n\r') 0x0D 0x0A when using a pipe to redirect child's stdout to a file, the child's output are bytes and not text.
First, I have used these examples MSDN-Creating a Child Process with Redirected Input and Output and http://support.microsoft.com/kb/190351), and now I have this basic application, it creates a pipe and redirect the child's STDOUT to a binary file. All this in a Win32 Console Application in Visual C++ 6.0 (yes it is old but is a requirement).
#define BUFSIZE 256
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
int _tmain(int argc, TCHAR *argv[])
{
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if ( ! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0) )
ErrorExit(TEXT("StdoutRd CreatePipe"));
if ( ! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) )
ErrorExit(TEXT("Stdout SetHandleInformation"));
CreateChildProcess();
if (!CloseHandle(g_hChildStd_OUT_Wr))
ErrorExit("CloseHandle");
ReadFromPipe();
if (!CloseHandle(g_hChildStd_OUT_Rd))
ErrorExit("CloseHandle");
return 0;
}
void CreateChildProcess()
{
TCHAR szCmdline[]=TEXT("child.exe");
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
BOOL bSuccess = FALSE;
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
bSuccess = CreateProcess(NULL,
szCmdline, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
if ( ! bSuccess )
ErrorExit(TEXT("CreateProcess"));
else
{
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
}
}
void ReadFromPipe(void)
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD nTotalBytesRead = 0;
fstream filePk;
filePk.open("result.out", ios::out | ios::trunc | ios::binary);
for (;;)
{
bSuccess = ReadFile( g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
if( ! bSuccess || dwRead == 0 ) {
if (GetLastError() == ERROR_BROKEN_PIPE)
break; // pipe done - normal exit path.
else
ErrorExit("ReadFile"); // Something bad happened.
}
filePk.write(chBuf, dwRead);
nTotalBytesRead += dwRead;
}
filePk.close();
char ibuff[24];
sprintf(ibuff,"%d bytes." , (int)nTotalBytesRead);
::MessageBox(NULL, ibuff, "", 0);
}
And in this dummy child.cpp you'll notice that if I set the STDOUT to binary mode everything works just fine (I get just 0x0A 0x0A!), but my real child is an EXE and I don't have access to that code.
int main(int argc, char* argv[])
{
_setmode( _fileno( stdout ), _O_BINARY );
printf("\n");
unsigned char buffer[] = {'\n'};
fwrite(buffer, sizeof(unsigned char), sizeof(buffer), stdout);
return 0;
}
So, after searching for about 2 days and considering that I have a basic C++ knowledge I ask: Is there a Way that I could do _setmode to the childs stdout from the parent, considering that I don't have access to the child's code.
As a solution, I am seriously considering finding every '0x0D' '0x0A' and replacing it with '0x0A'. I am really going crazy with this problem... So if someone could help me I will be very grateful.
Related Question: Win32 Stream Handles - Changing To Binary Mode but he has access to the child's code!
Edit
As, #librik point, the final solution will have to replace every single occurrence of 0x0D 0x0A by 0x0A. For this to work the file contents must be in memory. There are certain issues but I can live with it (excess of memory allocated). I hope this will be helpful:
void ReadFromPipe(void)
{
DWORD dwRead, dwWritten;
CHAR *chBuf = NULL, *chBufTmp = NULL;
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD nTotalBytesRead = 0;
fstream filePk;
filePk.open("result.out", ios::out | ios::trunc | ios::binary);
int nIter = 0;
for (;;)
{
if(chBuf == NULL) {
if((chBuf = (CHAR*)malloc(BUFSIZE*sizeof(CHAR))) == NULL) {
ErrorExit("Malloc");
}
} else {
chBufTmp = chBuf; // save pointer in case realloc fails
if((chBuf = (CHAR*)realloc(chBuf, (nIter+1)*(BUFSIZE*sizeof(CHAR)))) == NULL) {
free(chBufTmp); // free original block
ErrorExit("Realloc");
}
}
CHAR* chBufNew = chBuf+nTotalBytesRead;
bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBufNew, BUFSIZE, &dwRead, NULL);
if( ! bSuccess || dwRead == 0 ) {
if (GetLastError() == ERROR_BROKEN_PIPE) {
break; // pipe done - normal exit path.
} else {
ErrorExit("ReadFile"); // Something bad happened.
}
}
nTotalBytesRead += dwRead;
nIter ++;
}
// 0xD 0xA -> 0xA
nTotalBytesRead = ClearBuffer(chBuf, nTotalBytesRead);
filePk.write(chBuf, nTotalBytesRead);
filePk.close();
free(chBuf);
char ibuff[24];
sprintf(ibuff,"%d bytes." , (int)nTotalBytesRead);
::MessageBox(NULL, ibuff, "", 0);
}
int ClearBuffer(char *buffer, int bufferlength) {
// lmiguelhm-es requerido que TODO el buffer esté en memoria
int chdel = 0;
for (int i = 0; (i+chdel) < bufferlength; i++) {
char firstChar = buffer[i+chdel];
buffer[i] = firstChar;
if (firstChar == 0x0D) {
if ((i+chdel+1) < bufferlength) {
char secondChar = buffer[i+chdel+1];
if (secondChar == 0x0A) {
buffer[i] = secondChar;
chdel++;
}
}
}
}
return bufferlength - chdel;
}
Your problem is that the "stream mode" isn't part of Windows, so it isn't something you can change from outside the other program. It's part of the C and C++ system, and so it's a private part of each separate C or C++ program you run.
There's a library of functions that is combined with every program compiled in C++, called the "C++ Standard Library." The C++ Standard Library holds all the functions for streams like stdout. It's inside the other program's C++ Standard Library that the 0x0A is being converted to 0x0D 0x0A before it's written to the stream. _setmode is a function inside the C++ Standard Library which turns on and off that conversion, so when you add a call to it inside child.cpp, that tells child.cpp's C++ Standard Library to leave stdout alone. But you have no way to force the other program to call its _setmode function.
So the best thing really is the "crazy" solution you suggested:
As a solution, I am seriously considering finding every '0x0D' '0x0A'
and replacing it with '0x0A'.
So long as you know that child.exe is writing in text mode, not binary mode, then every single occurrence of 0x0D 0x0A must have originally been a single 0x0A. (If the program tried to write the two bytes 0x0D 0x0A, it would come out as the three bytes 0x0D 0x0D 0x0A.) Therefore you are absolutely safe and correct to "fix" the output by converting back again.
I think the easiest approach is just to write result.out exactly like you're doing it now, but then translate 0x0D 0x0A to 0x0A at the end, creating a new file that is correct. There are little tool programs you can download that will do this sort of thing for you -- one of them is called dos2unix. That might be the easiest way, in fact -- just make the last step of your program run dos2unix < result.out.with_bad_newlines > result.out. If, for some reason, you can't do this, you could have your program change 0x0D 0x0A to 0x0A inside chBuf before you write it out, translating as you go. (But be careful when chBuf ends in 0x0D...)
(There are certain techniques that can "inject" a little bit of code into another program that's under your control on Windows. They are a little dangerous, and a lot of trouble. If you're really unhappy with the translation idea, you can look up "DLL injection.")
Here is the code I am using:
std::wstring GetPathFromFileReference (DWORDLONG frn)
{
if (frn != 0)
{
HANDLE handle = NULL;
wchar_t file_buffer[2048] = { NULL };
wchar_t unicode_buffer[8] = { NULL };
UNICODE_STRING unicodeString;
unicodeString.Length = 8;
unicodeString.MaximumLength = 8;
unicodeString.Buffer = unicode_buffer;
OBJECT_ATTRIBUTES objAttributes = { NULL };
InitializeObjectAttributes(&objAttributes, &unicodeString, OBJ_CASE_INSENSITIVE, _root, NULL);
IO_STATUS_BLOCK ioStatusBlock = { NULL };
LARGE_INTEGER allocSize = { NULL };
int _result = NtCreateFile(&handle, GENERIC_ALL /*FILE_TRAVERSE*/ /* FILE_READ_DATA */, &objAttributes, &ioStatusBlock, /*&allocSize*/ NULL , NULL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_OPEN_BY_FILE_ID | FILE_NON_DIRECTORY_FILE /*FILE_OPEN_FOR_BACKUP_INTENT*/, NULL, NULL);
if (_result == S_OK)
{
typedef NTSTATUS (NTAPI *LPFN_NtQueryInformationFile) (HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, int);
LPFN_NtQueryInformationFile pfnNtQueryInformationFile = (LPFN_NtQueryInformationFile)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQueryInformationFile");
_result = pfnNtQueryInformationFile(handle, &ioStatusBlock, file_buffer, 4096, 9);
if (_result == S_OK)
{
return std::wstring(file_buffer + 2);
}
}
}
return L"";
}
The call to NtCreateFile is failing with STATUS_INVALID_PARAMETER. The commented out bits of code in that call show other things I have tried.
The RootDirectory handle is definitely getting set in objAttributes (to 0x30). I am using this same handle elsewhere in the code, and it is working perfectly. And the frn looks good too.
I have no idea what else to try or how to narrow the cause down any further :( Any help would be greatly appreciated.
EDIT: I forgot to mention what I am trying to achieve here. Sorry! The frn comes from the USN Change Journal. I have successfully read the Change Journal using my root handle (hence I believe it is correct), and for each entry I have got an frn and parent_frn. I want to get the full path to the file, and the code below is how I am trying to convert frn to path. Both frn and parent_frn give the same STATUS_INVALID_PARAMETER return code.
A comment on the documentation for NtCreateFile says that:
If using FILE_OPEN_BY_FILE_ID, the ObjectAttributes.RootDirectory handle MUST be filled in with a handle to the volume, otherwise you will get STATUS_INVALID_PARAMETER.
To open a handle to a volume you can use CreateFile using a path of \\.\X: where X is the drive letter. Note there is no trailing backslash. The CreateFile documentation has info about it (look for the string "Opens the C: volume.")
How can I make the code below to read correct text. In my text file has Hello welcome to C++, however at the end of the text, it has a new line. With the code below, my readBuffer always contains extra characters.
DWORD byteWritten;
int fileSize = 0;
//Use CreateFile to check if the file exists or not.
HANDLE hFile = CreateFile(myFile, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile != INVALID_HANDLE_VALUE)
{
BOOL readSuccess;
DWORD byteReading;
char readBuffer[256];
readSuccess = ReadFile(hFile, readBuffer, byteReading, &byteReading, NULL);
if(readSuccess == TRUE)
{
TCHAR myBuffer[256];
mbstowcs(myBuffer, readBuffer, 256);
if(_tcscmp(myBuffer, TEXT("Hello welcome to C++")) == 0)
{
FindClose(hFile);
CloseHandle(hFile);
WriteResultFile(TRUE, TEXT("success!"));
}
}
}
Thanks,
There are a few problems:
You're passing uninitialized data (byteReading) as the "# of bytes to read" parameter to ReadFile().
Depending on how you created the file, the file's contents may not have a terminating 0 byte. The code assumes that the terminator is present.
FindClose(hFile) doesn't make sense. CloseHandle(hFile) is all you need.
You need to call CloseHandle if CreateFile() succeeds. Currently, you call it only if you find the string you're looking for.
This isn't a bug, but it's helpful to zero-initialize your buffers. That makes it easier to see in the debugger exactly how much data is being read.
HANDLE hFile = CreateFile(myfile, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile != INVALID_HANDLE_VALUE)
{
BOOL readSuccess;
DWORD byteReading = 255;
char readBuffer[256];
readSuccess = ReadFile(hFile, readBuffer, byteReading, &byteReading, NULL);
readBuffer[byteReading] = 0;
if(readSuccess == TRUE)
{
TCHAR myBuffer[256];
mbstowcs(myBuffer, readBuffer, 256);
if(_tcscmp(myBuffer, TEXT("Hello welcome to C++")) == 0)
{
rv = 0;
}
}
CloseHandle(hFile);
}
I see two things:
byteReading isn't initialized
you are reading bytes so you have to terminate the string by 0.
CloseHandle is sufficient
Either remove the new line character from the file or use _tcsstr for checking the existence of the string "Hello Welcome to C++".