Convert int to LPCWSTR by using wsprintf - c++

As the following code:
int a = 16;
wchar_t *buffer = {0};
wsprintf(buffer,L"%d", a);
MessageBox(NULL, buffer, buffer, MB_OK);
I want to covert int to LPCWSTR in order to put MessageBox.
I really newbie in using wsprintf. Any one can help me explain clearly for me using this function??? (Please, I also read MSDN but still dont't clear)
I mean, I want to print "16" in MessageBox

You initialize your buffer to nullptr. Just create an array of wchar_ts that allocates enough space for you and you're off the hook:
int a = 16;
wchar_t buffer[256];
wsprintfW(buffer, L"%d", a);
MessageBoxW(nullptr, buffer, buffer, MB_OK);

Related

Windows API ReadFile() skips one out of every two characters

My aim is to read all the text located in a file. For some reason whenever I read from the file and print the result (drawText), the buffer seems to be skipping one character every two positions. HELLO will become HLO and SCAVENGER becomes SAEGR.
This is for Windows API. I wonder if CreateFile() and ReadFile() are just fine and whether it's something else causing the issue.
void init(HDC hdc)
{
HANDLE hFile;
LPCSTR fileName = "c:\\Users\\kanaa\\Desktop\\code\\HW2_StarterCode\\words.txt";
hFile = CreateFileA(fileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwFileSize = GetFileSize(hFile, NULL);
DWORD dwBytesRead;
WCHAR* buffer = new WCHAR[dwFileSize / 2 + 1];
buffer[dwFileSize / 2] = 0;
bool read = ReadFile(hFile, buffer, dwFileSize, &dwBytesRead, NULL);
std::wstring wstr(buffer);
std::string str(wstr.begin(), wstr.end());
delete[] buffer;
CloseHandle(hFile);
if (read) parse(str, hdc);
}
void parse(std::string word, HDC hdc)
{
std::string to = word;
std::wstring wword = std::wstring(to.begin(), to.end());
const WCHAR* wcword = wword.c_str();
Graphics graphics(hdc);
drawText(&graphics, wcword);
}
The problem was the WCHAR buffer. Below are the corrections
CHAR* buffer = new CHAR[dwFileSize/sizeof(char) + 1];
bool read = ReadFile(hFile, buffer, dwFileSize, &dwBytesRead, NULL);
buffer[dwBytesRead] = 0;
You are processing the file data using a wchar_t[] buffer. wchar_t is 2 bytes in size on Windows. So, in the statement:
std::string str(wstr.begin(), wstr.end());
You are iterating through the file data 2 bytes at a time, interpreting each byte pair as a single wchar_t that gets truncated to a 1-byte char, discarding the other byte. That is why your str ends up skipping every other character.
Process the file data using a char[] buffer instead. However, there are easier ways to read 7/8-bit file data into a std::string.
Lastly, in this statement:
std::wstring wword = std::wstring(to.begin(), to.end());
This is not the correct way to convert a std::string to a std::wstring. All you are doing is iterating through the chars converting each one as-is into a 2-byte wchar_t. Windows APIs expect wchar_t strings to be encoded in UTF-16, which your code is not converting to. You need to use MultiByteToWideChar(), std::wstring_convert, or other equivalent Unicode library call to perform that conversion. In which case, you first need to know the encoding of the source file in order to convert it to Unicode correctly.

MessageBox printing extra unicode characters from TCHAR buffer

So i'm in the middle of trying to get a NamedPipe IPC project working so that my C# GUI can communicate with my C++ code, i should mention i'm a fair bit out of my depth on the C++ side at the moment, although, for the most part i have it working.
I cannot for the life of me figure out how to 'translate?' the chReply buffer received by the C++ listener to a simple string and MessageBox it, i'm always getting extra unicode characters. I have added what i think are the most important parts.
C# Pipe Write
byte[] bReply = Encoding.Unicode.GetBytes("#TEST 123 456");
uint cbBytesWritten;
uint cbReplyBytes = (uint)bReply.Length;
bool bResult = PipeNative.WriteFile(hPipe, bReply, cbReplyBytes, out cbBytesWritten, IntPtr.Zero);
C++ Pipe Read
// Project's Character Set: Unicode
// BUFFER_SIZE = 1024
TCHAR chRequest[BUFFER_SIZE];
DWORD cbBytesWritten, cbRequestBytes;
TCHAR chReply[BUFFER_SIZE];
DWORD cbBytesRead, cbReplyBytes;
cbReplyBytes = sizeof(TCHAR) * BUFFER_SIZE;
do
{
bResult = ReadFile(hPipe, chReply, cbReplyBytes, &cbBytesRead, NULL);
}
while(!bResult);
MessageBox(NULL, chReply, _T("GUI Request"), MB_OK);
If somebody could save me from drowning i would be extremely grateful.
You have a few problems. The first of which is that you read and discard data. The second of which is you don't pay attention to the end of the buffer location.
// Project's Character Set: Unicode
// BUFFER_SIZE = 1024
TCHAR chRequest[BUFFER_SIZE];
DWORD cbBytesWritten, cbRequestBytes;
std::basic_string<TCHAR> result;
do {
TCHAR chReply[BUFFER_SIZE];
DWORD cbBytesRead;
bResult = ReadFile(hPipe, chReply, sizeof(chReply), &cbBytesRead, NULL);
if (bResult)
result.insert( result.end(), chReply, chReply+cbBytesRead/2 );
}
while(!bResult);
MessageBox(NULL, result.data(), _T("GUI Request"), MB_OK);
here we copy the bytes over into a basic_string<TCHAR>. It automatically handles null termination and the like, and permits long messages to be passed.
We'll read them 1024 characters at a time.
VTT is right. You need to initialize chReply with zeroes after each call to ReadFile.

How to change clipboard data in Windows

I have the following clipboard data:
Can I somehow change indexes of these records?
Also can I remove / make zero-length some of them?
Is it possible via WinAPI?
As for the first question, I don't see any function for this purpose.
As for the second question, I wrote the following code:
#include <Windows.h>
int main()
{
OpenClipboard(NULL);
HGLOBAL hdst = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(int));
int* dst = (int*)GlobalLock(hdst);
dst[0] = 0;
GlobalUnlock(hdst);
SetClipboardData(49166, hdst);
CloseClipboard();
}
but it didn't zeroed the record of the 49166 format.
How can I do it?
This is a method to do that. First, obtain the clipboard data string by use GetClipboardData api, and then modify the data string by your way. Second, rewrite string to cliboard by use SetClipboardData api.
You don't call GetClipboardData first from you code, you can do that like this:
char *buffer = NULL;
CString fromClipboard;
//open the cliboard
if (OpenClipboard())
{
HANDLE hData = GetClipboardData(CF_TEXT);
char* buffer = (char *)GlobalLock(hData);
fromClipboard = buffer;
//modify fromClipboard string by your method and rewrite to clipboard
//maybe like this
fromCliboard.Replace("hello", "world");
HGLOBAL clipbuffer;
char* buffer;
EmptyClipboard();
clipbuffer = GlobalAlloc(GMEM_DDESHARE, source.GetLength()+1);
buffer = (char*)GlobalLock(clipbuffer);
strcpy(buffer, LPCSTR(source));
GlobalUnlock(hData);
GlobalUnlock(clipbuffer);
SetClipboardData(CF_TEXT,clipbuffer);
CloseClipboard();
}

C++ MessageBox character array

I am having difficulties using MessageBox function with variables
I have
int main(int argc, char* argv[])
{
char* filename = argv[0];
DWORD length = strlen(filename);
MessageBox(0, TEXT("filename text"), TEXT("length text"), 0); // Works
}
But I want to output variables filename and length as:
MessageBox(0, filename, length, 0); -- compiler error
Function MessageBox has syntax:
int WINAPI MessageBox(
_In_opt_ HWND hWnd,
_In_opt_ LPCTSTR lpText,
_In_opt_ LPCTSTR lpCaption,
_In_ UINT uType
);
I tried using
MessageBox(0, (LPCWSTR)filename, (LPCWSTR)length, 0);
but the output is in some kind of hieroglyphs.
The variable length is not a string, and only strings can be used. It doesn't help that you try to cast it to a char* as then the value of length will be taken as a pointer to the string which will cause undefined behavior.
For C++, you can use e.g. std::to_string to convert non-string values to strings, like
MessageBox(0, filename, std::to_string(length).c_str(), 0);
Note that you must use the c_str function to get a char*.
If you don't have std::to_string then you can use e.g. std::istringstream instead:
std::istringstream is;
is << length;
MessageBox(0, filename, is.str().c_str(), 0);
If you want a more old-style C solution, then there's snprintf (or _snprintf in Visual Studio):
char length_string[20];
_snprintf(length_string, sizeof(length_string), "%ld", length);
MessageBox(0, filename, length_string, 0);
With a C++ win32 project in VS2015 a char array displays in a MessageBox with this code. Include header atlstr.h
// open a file in read mode.
ifstream myInfile;
myInfile.open("C:\\Users\\Desktop\\CodeOnDesktop\\myTrialMessageBox.txt");
if (myInfile.fail())
{
MessageBox(NULL,
L"We have an error trying to open the file myTrialMessageBox.txt",
L"Opening a file.",
MB_ICONERROR);
}
char data[200];
// Read the data from the file and display it.
//infile >> data; // Only gets the first word.
myInfile.getline(data, 100);
//To use CString, include the atlstr.h header.
// Cast array called data to a CString to enable use as MessageBox parameter.
CString cdata = (CString)data;
// or CString cdata = CString(_T("A string"));
MessageBox(NULL,
cdata,
L"Opening a file.",
MB_ICONERROR);
// close the opened file.
myInfile.close();

How to convert LPWSTR* (or WCHAR*) to LPWSTR

I'm having a difficulty in converting a value to LPWSTR. I'm getting a registry value, and trying to return the result as LPWSTR. It appears the registry call using RegQueryValueExW works with a variety of types going in to store the result, but I can't cast any of them back to LPWSTR.
LPWSTR value;
HKEY hKey;
long result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"RegEntry1", 0, ACCESS|KEY_WOW64_32KEY, &hKey);
if (result == ERROR_SUCCESS)
{
//WCHAR buffer[512];
//TCHAR buffer[512];
LPWSTR buffer[512];
DWORD bufferSize = sizeof(buffer);
ULONG queryVal = 0;
queryVal = RegQueryValueExW(hKey, L"Path", 0, NULL, (LPBYTE)buffer, &bufferSize);
if (queryVal == ERROR_SUCCESS)
{
//Access violation error here; I need some type of conversion.
value = buffer;
}
}
No posts that I've read on here so far have led me to an answer. C++ is not my primary dev language.
UPDATE: None of the proposed answers worked for me. I found an alternative way to do what I needed.
You don't want a buffer of LPWSTR, you want a buffer of wchar_t. A pointer to that will be LPWSTR as it's a typedef for wchar_t *.
These two lines from WinNT.h are relevant:
typedef wchar_t WCHAR; // wc, 16-bit UNICODE character
typedef __nullterminated WCHAR *NWPSTR, *LPWSTR, *PWSTR;
Edit: I suspect the problem is with the part of the code you haven't shown us. Are you returning value from a function? If so then the problem is that you're returning a pointer to a buffer that has gone out of scope and been destroyed. I would return a std::wstring or CString instead.
Your buffer variable is declaring an array of 512 wchar_t* pointers when it should be declaring an array of 512 wchar_t characters instead. The first commented-out line of code is the correct code to use:
WCHAR buffer[512];
DWORD bufferSize = sizeof(buffer);
ULONG queryVal = RegQueryValueExW(hKey, L"Path", 0, NULL, (LPBYTE)buffer, &bufferSize);
if (queryVal == ERROR_SUCCESS)
{
//...
}
Keep in mind that the buffer will not be null-terminated if the Registry value was not stored with its own null-terminator, so you should allocate some extra space for your own null terminator, just in case:
WCHAR buffer[512+1];
DWORD bufferSize = (sizeof(buffer) - sizeof(WCHAR));
LONG queryVal = RegQueryValueExW(hKey, L"Path", 0, NULL, (LPBYTE)buffer, &bufferSize);
if (queryVal == ERROR_SUCCESS)
{
buffer[bufferSize / sizeof(WCHAR)] = 0;
//...
}
Alternatively, use RegGetValue() instead, which handles the null terminator for you:
WCHAR buffer[512+1];
DWORD bufferSize = sizeof(buffer);
LONG queryVal = RegGetValueW(hKey, NULL, L"Path", RRF_RT_REG_SZ | RRF_RT_REG_EXPAND_SZ, NULL, buffer, &bufferSize);
if (queryVal == ERROR_SUCCESS)
{
//...
}