Concatenation tchar variables - winapi

I work with WinAPI and I have a function get_disk_drives() for retrieves available disk drives and a helper function get_current_disk_drive() for retrieves the full path and file name of the specified file.
void get_current_disk_drive(TCHAR dirname[]) {
TCHAR *fileExt = NULL;
TCHAR szDir[MAX_PATH];
GetFullPathName(dirname, MAX_PATH, szDir, &fileExt);
_tprintf(_T("Full path: %s \nFilename: %s\n"), szDir, fileExt);
}
void get_disk_drives() {
DWORD drives_bitmask = GetLogicalDrives();
for (int i = 0; i < 26; i++) {
if ((drives_bitmask >> i) & 1) {
TCHAR drive_name = (char)(65 + i);
TCHAR drive_path[] = drive_name + "\\";
get_current_disk_drive(drive_path);
}
}
}
int _tmain(int argc, _TCHAR* argv[]) {
get_disk_drives();
return 0;
}
Here I can't make concatenation:
TCHAR drive_name = (char)(65 + i);
TCHAR drive_path[] = drive_name + "\\";
get_current_disk_drive(drive_path);
Why? Where is my mistake?

operator+ cannot be used for C-strings, string literals, or characters. The effect (for legal expressions anyway) is pointer arithmetic. For concatenation you have to either explicitly call one of the strcat functions, or use std::basic_string instead:
typedef std::basic_string<TCHAR> tstring;
tstring drive_name;
drive_name += TCHAR( 65 + i );
tstring drive_path = drive_name + _T( '\\' );
You can access a C-string from a std::basic_string by invoking its c_str() member. Since this is a C-string represented as a pointer, you would have to change the signature of get_current_disk_drive to void get_current_disk_drive(const TCHAR* dirname), or pass a const tstring&.
It's also a good idea to stop using Code::Blocks. Defaulting to MBCS character encoding in 2015 is a crime.

Related

Read binary data from QProcess in Windows

I have some .exe file (say some.exe) that writes to the standard output binary data. I have no sources of this program. I need to run some.exe from my C++/Qt application and read standard output of the process I created. When I'm trying to do this with QProcess::readAll someone replaces byte \n (0x0d) to \r\n (0x0a 0x0d).
Here is a code:
QProcess some;
some.start( "some.exe", QStringList() << "-I" << "inp.txt" );
// some.setTextModeEnabled( false ); // no effect at all
some.waitForFinished();
QByteArray output = some.readAll();
I tried in cmd.exe to redirect output to file like this:
some.exe -I inp.txt > out.bin
and viewed out.bin with hexedit there was 0a 0d in the place where should be 0d.
Edit:
Here is a simple program to emulate some.exe behaviour:
#include <stdio.h>
int main() {
char buf[] = { 0x00, 0x11, 0x0a, 0x33 };
fwrite( buf, sizeof( buf[ 0 ] ), sizeof( buf ), stdout );
}
run:
a.exe > out.bin
//out.bin
00 11 0d 0a 33
Note, that I can't modify some.exe that's why I shouldn't modify my example like _setmode( _fileno( stdout, BINARY ) )
The question is: how can I say to QProcess or to Windows or to console do not change CR with LF CR?
OS: Windows 7
Qt: 5.6.2
how can I say to QProcess or to Windows or to console do not change CR with LF CR?
They don't change anything. some.exe is broken. That's all. It outputs the wrong thing. Whoever made it output brinary data in text mode has messed up badly.
There's a way to recover, though. You have to implement a decoder that will fix the broken output of some.exe. You know that every 0a has to be preceded by 0d. So you have to parse the output, and if you find a 0a, and there's 0d before it, remove the 0d, and continue. Optionally, you can abort if a 0a is not preceded by 0d - some.exe should not produce such output since it's broken.
The appendBinFix function takes the corrupted data and appends the fixed version to a buffer.
// https://github.com/KubaO/stackoverflown/tree/master/questions/process-fix-binary-crlf-51519654
#include <QtCore>
#include <algorithm>
bool appendBinFix(QByteArray &buf, const char *src, int size) {
bool okData = true;
if (!size) return okData;
constexpr char CR = '\x0d';
constexpr char LF = '\x0a';
bool hasCR = buf.endsWith(CR);
buf.resize(buf.size() + size);
char *dst = buf.end() - size;
const char *lastSrc = src;
for (const char *const end = src + size; src != end; src++) {
char const c = *src;
if (c == LF) {
if (hasCR) {
std::copy(lastSrc, src, dst);
dst += (src - lastSrc);
dst[-1] = LF;
lastSrc = src + 1;
} else
okData = false;
}
hasCR = (c == CR);
}
dst = std::copy(lastSrc, src, dst);
buf.resize(dst - buf.constData());
return okData;
}
bool appendBinFix(QByteArray &buf, const QByteArray &src) {
return appendBinFix(buf, src.data(), src.size());
}
The following test harness ensures that it does the right thing, including emulating the output of some.exe (itself):
#include <QtTest>
#include <cstdio>
#ifdef Q_OS_WIN
#include <fcntl.h>
#include <io.h>
#endif
const auto dataFixed = QByteArrayLiteral("\x00\x11\x0d\x0a\x33");
const auto data = QByteArrayLiteral("\x00\x11\x0d\x0d\x0a\x33");
int writeOutput() {
#ifdef Q_OS_WIN
_setmode(_fileno(stdout), _O_BINARY);
#endif
auto size = fwrite(data.data(), 1, data.size(), stdout);
qDebug() << size << data.size();
return (size == data.size()) ? 0 : 1;
}
class AppendTest : public QObject {
Q_OBJECT
struct Result {
QByteArray d;
bool ok;
bool operator==(const Result &o) const { return ok == o.ok && d == o.d; }
};
static Result getFixed(const QByteArray &src, int split) {
Result f;
f.ok = appendBinFix(f.d, src.data(), split);
f.ok = appendBinFix(f.d, src.data() + split, src.size() - split) && f.ok;
return f;
}
Q_SLOT void worksWithLFCR() {
const auto lf_cr = QByteArrayLiteral("\x00\x11\x0a\x0d\x33");
for (int i = 0; i < lf_cr.size(); ++i)
QCOMPARE(getFixed(lf_cr, i), (Result{lf_cr, false}));
}
Q_SLOT void worksWithCRLF() {
const auto cr_lf = QByteArrayLiteral("\x00\x11\x0d\x0a\x33");
const auto cr_lf_fixed = QByteArrayLiteral("\x00\x11\x0a\x33");
for (int i = 0; i < cr_lf.size(); ++i)
QCOMPARE(getFixed(cr_lf, i), (Result{cr_lf_fixed, true}));
}
Q_SLOT void worksWithCRCRLF() {
for (int i = 0; i < data.size(); ++i) QCOMPARE(getFixed(data, i).d, dataFixed);
}
Q_SLOT void worksWithQProcess() {
QProcess proc;
proc.start(QCoreApplication::applicationFilePath(), {"output"},
QIODevice::ReadOnly);
proc.waitForFinished(5000);
QCOMPARE(proc.exitCode(), 0);
QCOMPARE(proc.exitStatus(), QProcess::NormalExit);
QByteArray out = proc.readAllStandardOutput();
QByteArray fixed;
appendBinFix(fixed, out);
QCOMPARE(out, data);
QCOMPARE(fixed, dataFixed);
}
};
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
if (app.arguments().size() > 1) return writeOutput();
AppendTest test;
QTEST_SET_MAIN_SOURCE_PATH
return QTest::qExec(&test, argc, argv);
}
#include "main.moc"
Unfortunately it has nothing to do with QProcess or Windows or console. It's all about CRT. Functions like printf or fwrite are taking into account _O_TEXT flag to add an additional 0x0D (true only for Windows). So the only solution is to modify stdout's fields of your some.exe with WriteProcessMemory or call the _setmode inside an address space of your some.exe with DLL Injection technique or patch the lib. But it's a tricky job.

I cant print a number inside a formatted MessageBox

The following code does not work as it should. %i does not connect with its variable.
#include<Windows.h>
#include<stdio.h>
#include<tchar.h>
/* SCREENSIZE.C
This project contains the code that Programming Windows
book by Charles Petzold is using.
*/
int cdecl MessageBoxPrintfW(TCHAR *msgBoxTitle, TCHAR *msgBoxFormat, ...)
{
//define buffer
TCHAR msgBoxBuffer[1024];
//define iteration pointer
va_list argPtr;
//start iteration
va_start(argPtr, msgBoxFormat);
/*int _vsnwprintf_s(
wchar_t *const _Buffer,
const size_t _BufferCount,
const size_t _MaxCount,
const wchar_t *const _Format,
va_list _ArgList)
*/
_vsntprintf_s(msgBoxBuffer, sizeof(msgBoxBuffer) / sizeof(TCHAR), (sizeof(msgBoxBuffer) / sizeof(TCHAR)) - 1, msgBoxFormat, argPtr);
//end iteration
va_end(argPtr);
//Use return type to pass preconfigured MessageBox(0,"Text","Title",MB_OKCANCEL);
//Whe we use L before a string example: L"text" it is considered UNICODE format.
return(MessageBox(0, msgBoxFormat, msgBoxTitle, MB_OKCANCEL));
}
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR pCmdLine,
int iCmdShow)
{
int cxScreen, cyScreen;
cxScreen = GetSystemMetrics(SM_CXSCREEN);
cyScreen = GetSystemMetrics(SM_CYSCREEN);
MessageBoxPrintfW(TEXT ("SCREENSIZE"), TEXT("The screen is %i pixels wide by %i pixels high."), cxScreen, cyScreen);
return(0);
}
Why does this happen?
Below is the output that I get:
TCHAR msgBoxBuffer[1024];
_vsntprintf_s(msgBoxBuffer,...
...
return(MessageBox(0, msgBoxFormat, msgBoxTitle, MB_OKCANCEL));
Note that you are writting to msgBoxBuffer, but you never use msgBoxBuffer. So your message box doesn't change anything. Try the following instead:
int MessageBoxPrintfW(const TCHAR *msgBoxTitle, const TCHAR* msgBoxFormat, ...)
{
va_list args;
va_start(args, msgBoxFormat);
int len = _vsctprintf(msgBoxFormat, args) + 1; // add terminating '\0'
TCHAR *buf = new TCHAR[len];
_vstprintf_s(buf, len, msgBoxFormat, args);
int result = MessageBox(0, buf, msgBoxTitle, MB_OKCANCEL);
delete[]buf;
return result;
}
For C version use malloc(len * sizeof(TCHAR)) instead of new, and use free instead of delete[]

Some warnings being treated as errors while making a modified ver of ext2 kernel module under ubuntu

I have succeeded in making a modified version of ext2 (so called myext2.ko) and tested it for mount and umount, and something else; the problem occurs when I add the following code into my fs/myext2/file.c and tried to implement a simple "encryption" func, that is, negating the last bit of the read-in string :
ssize_t my_new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
{
struct iovec iov; //changed
struct kiocb kiocb;
struct iov_iter iter;
ssize_t ret;
//inserted by adward - begin
size_t i;
char buff[len];
for (i=0;i<len;i++){
buff[i] = buf[i] ^ 1;
}
iov.iov_base = (void __user *)buff;
iov.iov_len = len;
printk("Inside my_new_sync_write");
//inserted by adward - end
init_sync_kiocb(&ki_nbytesocb, filp);
kiocb.ki_pos = *ppos;
kiocb.ki_nbytes = len;
iov_iter_init(&iter, WRITE, &iov, 1, len);
ret = filp->f_op->write_iter(&kiocb, &iter);
if (-EIOCBQUEUED == ret)
ret = wait_on_sync_kiocb(&kiocb);
*ppos = kiocb.ki_pos;
return ret;
}
ssize_t my_new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
{
struct iovec iov = { .iov_base = buf, .iov_len = len };
struct kiocb kiocb;
struct iov_iter iter;
ssize_t ret;
//inserted by adward - begin
size_t i;
//inserted by adward - end
init_sync_kiocb(&kiocb, filp);
kiocb.ki_pos = *ppos;
kiocb.ki_nbytes = len;
iov_iter_init(&iter, READ, &iov, 1, len);
ret = filp->f_op->read_iter(&kiocb, &iter);
if (-EIOCBQUEUED == ret)
ret = wait_on_sync_kiocb(&kiocb);
*ppos = kiocb.ki_pos;
//inserted by adward - begin
for (i=0;i<len;i++){
buf[i] ^= 1;
}
printk("inside my_new_sync_read");
//inserted by adward - end
return ret;
}
The prototype of the above two functions are actually in fs/read_write.c , using by almost all file system types in the kernel code ver 3.17.6; I just copied them into fs/myext2/file.c and make some minor change as commented, so that I can do some test without having to change any Makefile.
But the moment I paste them into my file.c, "sudo make" gives the error message as following:
/home/adward/linux-3.17.6/fs/myext2/file.c:64:15: error: storage size of ‘kiocb’ isn’t known
struct kiocb kiocb;
^
/home/adward/linux-3.17.6/fs/myext2/file.c:65:18: error: storage size of ‘iter’ isn’t known
struct iov_iter iter;
^
and cc1: some warnings being treated as errors
even if I haven't refered to them by changing the func pointers in file_operations in the same source code file, or say, I haven't used them!
P.S.
My file_operation struct now looks like:
const struct file_operations myext2_file_operations = {
.llseek = generic_file_llseek,
.read = new_sync_read, //want to replace with my_new_sync_read
.write = new_sync_write, //want to replace with my_new_sync_write
...
}
Has anyone who have done something similar and crashed into some problems like this one? Please notify me if I have done something remarkable wrong, thanks.
Met the same error before. U should add <linux/aio.h> as ext2 uses asynchronous IO for reading/writing files.
Hope that helps :)

UTF8ToUTF16 failing

I have the following code which is just three sets of functions for converting UTF8 to UTF16 and vice-versa. It converts using 3 different techniques..
However, all of them fail:
std::ostream& operator << (std::ostream& os, const std::string &data)
{
SetConsoleOutputCP(CP_UTF8);
DWORD slen = data.size();
WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), data.c_str(), data.size(), &slen, nullptr);
return os;
}
std::wostream& operator <<(std::wostream& os, const std::wstring &data)
{
DWORD slen = data.size();
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), data.c_str(), slen, &slen, nullptr);
return os;
}
std::wstring AUTF8ToUTF16(const std::string &data)
{
return std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(data);
}
std::string AUTF16ToUTF8(const std::wstring &data)
{
return std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(data);
}
std::wstring BUTF8ToUTF16(const std::string& utf8)
{
std::wstring utf16;
int len = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0);
if (len > 1)
{
utf16.resize(len - 1);
wchar_t* ptr = &utf16[0];
MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, ptr, len);
}
return utf16;
}
std::string BUTF16ToUTF8(const std::wstring& utf16)
{
std::string utf8;
int len = WideCharToMultiByte(CP_UTF8, 0, utf16.c_str(), -1, NULL, 0, 0, 0);
if (len > 1)
{
utf8.resize(len - 1);
char* ptr = &utf8[0];
WideCharToMultiByte(CP_UTF8, 0, utf16.c_str(), -1, ptr, len, 0, 0);
}
return utf8;
}
std::string CUTF16ToUTF8(const std::wstring &data)
{
std::string result;
result.resize(std::wcstombs(nullptr, &data[0], data.size()));
std::wcstombs(&result[0], &data[0], data.size());
return result;
}
std::wstring CUTF8ToUTF16(const std::string &data)
{
std::wstring result;
result.resize(std::mbstowcs(nullptr, &data[0], data.size()));
std::mbstowcs(&result[0], &data[0], data.size());
return result;
}
int main()
{
std::string str = "консоли";
MessageBoxA(nullptr, str.c_str(), str.c_str(), 0); //Works Fine!
std::wstring wstr = AUTF8ToUTF16(str); //Crash!
MessageBoxW(nullptr, wstr.c_str(), wstr.c_str(), 0); //Fail - Crash + Display nothing..
wstr = BUTF8ToUTF16(str);
MessageBoxW(nullptr, wstr.c_str(), wstr.c_str(), 0); //Fail - Random chars..
wstr = CUTF8ToUTF16(str);
MessageBoxW(nullptr, wstr.c_str(), wstr.c_str(), 0); //Fail - Question marks..
std::cin.get();
}
The only thing that works above is the MessageBoxA. I don't understand why because I'm told that Windows converts everything to UTF16 anyway so why can't I convert it myself?
Why does none of my conversions work?
Is there a reason my code does not work?
The root problem why all of your approaches fail is that they require the std::string to be UTF-8 encoded but std::string str = "консоли" is not UTF-8 encoded unless you save the .cpp file as UTF-8 and configure your compiler's default codepage to UTF-8. In most C++11 compilers, you can use the u8 prefix to force the string to use UTF-8:
std::string str = u8"консоли";
However, VS 2013 does not support that feature yet:
Support For C++11 Features
Unicode string literals
2010 No
2012 No
2013 No
Windows itself does not support UTF-8 in most API functions that take a char* as input (an exception is MultiByteToWideChar() when using CP_UTF8). When you call an A function, it calls the corresponding W function internally, converting any char* data to/from UTF-16 using Windows' default codepage (CP_ACP). So you get random results when you use non CP_ACP data with functions that are expecting it. As such, MessageBoxA() will work correctly only if your .cpp file and compiler are using the same codepage as CP_ACP so the unprefixed char* data matches what MessageBoxA() is expecting.
I don't know why AUTF8ToUTF16() is crashing, probably a bug in your compiler's STL implementation when processing bad data.
BUTF8ToUTF16() is not handling this case in the documentation: "If the input byte/char sequences are invalid, returns U+FFFD for UTF encodings." Also, your implementation is not optimal. Use length() instead of -1 on inputs to avoid dealing with null terminator issues.
CUTF8ToUTF16() is not doing any error handling or validations. However converting non-valid input to question marks or U+FFFD is very common in most libraries.

Is there a format specifier that always means char string with _tprintf?

When you build an app on Windows using TCHAR support, %s in _tprintf() means char * string for Ansi builds and wchar_t * for Unicode builds while %S means the reverse.
But are there any format specifiers that always mean char * string no matter if it's an Ansi or Unicode build? Since even on Windows UTF-16 is not really used for files or networking it turns out to still be fairly often that you'll want to deal with byte-based strings regardless of the native character type you compile your app as.
The h modifier forces both %s and %S to char*, and the l modifier forces both to wchar_t*, ie: %hs, %hS, %ls, and %lS.
This might also solve your problem:
_TCHAR *message;
_tprintf(_T("\n>>>>>> %d") TEXT(" message is:%s\n"),4,message);
You can easily write something like this:
#ifdef _UNICODE
#define PF_ASCIISTR "%S"L
#define PF_UNICODESTR "%s"L
#else
#define PF_ASCIISTR "%s"
#define PF_UNICODESTR "%S"
#endif
and then you use the PF_ASCIISTR or the PF_UNICODESTR macros in your format string, exploiting the C automatic string literals concatenation:
_tprintf(_T("There are %d ") PF_ASCIISTR _T(" over the table"), 10, "pens");
I found, that '_vsntprintf_s' uses '%s' for type TCHAR and works for both, GCC and MSVC.
So you could wrap it like:
int myprintf(const TCHAR* lpszFormat, va_list argptr) {
int len = _vsctprintf(lpszFormat, argptr); // -1:err
if (len<=0) {return len;}
auto* pT = new TCHAR[2 + size_t(len)];
_vsntprintf_s(pT, (2+len)*sizeof(TCHAR), 1+len, lpszFormat, argptr);
int rv = printf("%ls", pT);
delete[] pT;
return rv;
}
int myprintf(const TCHAR* lpszFormat, ...) {
va_list argptr;
va_start(argptr, lpszFormat);
int rv = myprintf(lpszFormat, argptr);
va_end(argptr);
return rv;
}
int main(int, char**) { return myprintf(_T("%s"), _T("Test")); }

Resources