The following program is meant to print the name of the window that has focus or at least the name of the command prompt where the program is running.But it prints only one character which is W. Why is it so ? Where am I making a mistake ?
#include <Windows.h>
#include <stdio.h>
int main() {
TCHAR title[500];
int i=0;
while(i<10) {
GetWindowText(GetForegroundWindow(), title, 500);
printf("%s\n",title);
i++;
system("pause");
}
}
I dare to guess that TCHAR expands to wchar_t or short to support Unicode (UTF-16, to be more precise) and that's the source of the problem.
In UTF16, the character 'W' is represented by 2 bytes: 87 (ASCII code for 'W') and 0.
If you try to print a UTF-16 string beginning with 'W' with the regular printf(), printf() will reinterpret that UTF-16 string as "W\0" and stop printing right after 'W'.
To print strings of TCHAR you should use _tprintf() instead.
Because it is a TCHAR it can be ansi or unicode. Use _tprintf instead printf
If you want to continue using ANSI version with printf, use GetWindowTextA and replace TCHAR with char because Windows have 2 set of API that work with strings:
1) version (A) that work with ANSI strings and take char* or const char* as input.
2) version (W) that work with wide strings and take wchar_t* or const wchar_t* as input. Since this is native version of the function it is slightly faster and also it can work with Unicode strings.
Since _UNICODE is defined in your project, TCHAR will be mapped to wchar_t and GetWindowText will be mapped to GetWindowTextW, so you that use printf to work with narrow strings can't print wchar_t* with '%s, you should either use _tprintf or stop using TCHAR and directly call version of API that best match your need (here call GetWindowTextA) for example you can use this:
wchar_t title[500];
GetWindowTextW(GetForegroundWindow(), title, 500);
printf("%ls\n", title);
Related
I have the following c++ code:
#include "stdafx.h"
#include <atlstr.h>
int _tmain(int argc, _TCHAR* argv[])
{
CString OFST_PATH;
TCHAR DIR_PATH[MAX_PATH];
GetCurrentDirectory(MAX_PATH, DIR_PATH);
OFST_PATH.Format(DIR_PATH);
CHAR *pOFST_PATH = (LPSTR)(LPCTSTR)OFST_PATH;
return 0;
}
I want to understand why the value of pOFST_PATH in the end of the program is "c"? what did (LPSTR)(LPCTSTR) casting of variable OFST_PATH did to the whole path that was written in there?
As you can see in the following window, when debuging the variables values are:
CString and LPCTSTR are both based on TCHAR, which is wchar_t when UNICODE is defined (which it is, in your case, as I can tell by the value of argv in your debugger). When you do this:
(LPCTSTR)OFST_PATH
That works okay, because CString has a conversion operator to LPCTSTR. But with UNICODE defined, LPCTSTR is LPCWSTR, a.k.a. wchar_t const*. It points to an array of utf16 characters. The first character in that array is L'c' (that's the wide character version of 'c'). The bytes of L'c' look like this in memory: 0x63 0x00. That's the ASCII code for the letter 'c', followed by a zero. So, when you convert your CString to LPCTSTR, that's valid, however, your next conversion:
(LPSTR)(LPCTSTR)OFST_PATH
That's not valid. LPSTR is char*, so you are treating a wchar_t const* as if it's a char*. Well your debugger assumes that when it sees a char*, it is looking at a null terminated narrow character string. And if you remember from above what the value of the bytes of the first character were, it is the ASCII value for the letter 'c', followed by a zero. So the debugger sees this as a null terminated string consisting of just the letter 'c'.
The moral of the story is, don't use c-style casts if you don't understand what they do, and whether they are appropriate.
How would I take...
string modelPath = "blah/blah.obj"
and concatenate it with...
L" not found."
While passing it in as LPCWSTR. I tried to do
(LPCWSTR)(modelPath + " was not found.").c_str()
However that did not work. Here is a larger example of what it looks like now.
if(!fin)
{
MessageBox(0, L"Models/WheelFinal.txt not found.", 0, 0); //
return;
}
LPCWSTR is a L ong P ointer to a C onstant W ide STR ing. Wide strings, at least in Win32, are 16 bits, whereas (const) char strings (i.e. (C)STR or their pointer-counterparts LP(C)STR) are 8 bits.
Think of them on Win32 as typedef const char* LPCSTR and typedef const wchar_t* LPCWSTR.
std::string is an 8-bit string (using the underlying type char by default) whereas std::wstring is a wider character string (i.e. 16-bits on win32, using wchar_t by default).
If you can, use std::wstring to concatenate a L"string" as a drop-in replacement.
A note on MessageBox()
Windows has a funny habit of defining macros for API calls that switch out underlying calls given the program's multibyte configuration. For almost every API call that uses strings, there is a FunctionA and FunctionW call that takes an LPCSTR or LPWCSTR respectively.
MessageBox is one of them. In Visual Studio, you can go into project settings and change your Multi-Byte (wide/narrow) setting or you can simply call MessageBoxA/W directly in order to pass in different encodings of strings.
For example:
LPWCSTR wideString = L"Hello, ";
MessageBoxW(NULL, (std::wstring(wideString) + L"world!").c_str(), L"Hello!", MB_OK);
LPCSTR narrowString = "Hello, ";
MessageBoxA(NULL, (std::string(narrowString) + "world!").c_str(), "Hello!", MB_OK);
If you can change modelPath to std::wstring, it becomes easy:
MessageBox(nullptr, (modelPath + L" not found.").c_str(), nullptr, 0);
I changed your 0 pointer values into nullptr as well.
Since std::string represents a narrow string, std::wstring represents a wide string, and the two are wildly different, casting from one representation to the other does not work, while starting with the appropriate one does. On the other hand, one can properly convert between representations using the new <codecvt> header in C++11.
I'm trying to combine 2 tchar.
char username[UNLEN+1];
DWORD username_len = UNLEN+1;
GetUserName(username, &username_len);
TCHAR* appdatapath ="C:\\Users\\"+username+"\\AppData";
But I get error error at appdatapath line. How can I combine 2 tchar? Thanks
Have a look at strcat and wcscat. You can't add char pointer with char array.
If you are on a windows machine, you can use _tcscat which will redirect to the right function to use depending on _UNICODE and _MBCS defines.
Might want to use the safe versions as well by appending _s to the function name.
As pointed in the comments, you can also use snprintf like so:
const size_t concatenated_size = 256;
char concatenated[concatenated_size];
snprintf(concatenated, concatenated_size, "C:\\Users\\%s\\AppData", username);
Since you have string literals before and after the runtime string, it is probably a better approach.
To answer the question in the title: you concatenate two TCHAR strings using the _tcscat function.
However, there are other issues in your code related to this: GetUserName expects a LPTSTR, i.e. a pointer to a buffer TCHAR characters. Furthermore, there's another TCHAR usage in
TCHAR* appdatapath ="C:\\Users\\"+username+"\\AppData";
The issue with this is that the type to which TCHAR expands changes depending on whether _UNICODE is defined. In particular, if you set it, TCHAR (eventually) expands to wchar and hence GetUserName expects a wchar_t* but you pass a char*. Another issue is that you cannot concatenate C arrays using the + operator.
I suggest to stop worrying about TCHAR in the first place and always just compile with _UNICODE defined - and use wchar throughout your code. Also, since you're using C++, just use std::wstring:
wchar username[UNLEN+1];
DWORD username_len = UNLEN+1;
GetUserNameW(username, &username_len);
std::wstring appdatapath = L"C:\\Users\\";
appdatapath += username;
appdatapath += L"\\AppData";
Last but not least: your entire code can probably be replaced with a call to the SHGetSpecialFolderPath function - pass CSIDL_APPDATA to it to get the "AppData" path.
#include <tchar.h>
const size_t stringSize= 20;
TCHAR value[stringSize] = { 0 };
_tcscat_s(value, stringSize, TEXT("appendMe"));
MSDN: _tcscat_s
I'm trying to convert a TCHAR to a string as in:
std::string mypath;
TCHAR path[MAX_PATH];
GetModuleFileName( NULL, path, MAX_PATH );
I need to set mypath to that of path. I did a simple loop and concatenated path[index] to mypath and this works but I don't like this way.
I'm new to C++ but have done plenty of C#. I've seen examples of the GetModuleFileName that passes in a "char" but it doesn't like it. It needs the TCHAR or a LPWSTR.
TCHAR is a macro defined as a char or wchar depending on what you have your character set defined to. The default after 2008 is have the character set to unicode. this code works if you change your character set.
int _tmain(int argc, _TCHAR* argv[])
{
TCHAR* bob ="hi";
string s = bob;
}
Right click on the project settings and chage the folowing
if You want to use TCHAR as a Unicode character set use wstring
When I really need to do it I use the following:
TCHAR infoBuf[32767];
GetWindowsDirectory(infoBuf, 32767);
And then I convert it to a wstring which can be converted to a standard std::string:
wstring test(&infoBuf[0]); //convert to wstring
string test2(test.begin(), test.end()); //and convert to string.
If you want the path in chars, you should call GetModuleFilenameA. That function takes LPSTR instead of LPTSTR.
Note that almost all Win32 functions that take or return strings have two version, one ending in A (ANSI?) and the other ending in W (wide).
You can also convert from _TCHAR* to char* using wcstombs or wcstombs_s function
http://msdn.microsoft.com/en-us/library/5d7tc9zw%28v=vs.80%29.aspx
Hi this is a late answer but I have an idea.
{wstring test = User;
std::wcout << test << std::endl;
string test2(test.begin(), test.end());
std::cout << test2 << std::endl;}
User is in this example the username as a TCHAR.
Now I can use the name as a string or wstring.
This is the easiest way to convert the TCHAR to a string.
I have a TCHAR and value as below:
TCHAR szDestPathRoot[MAX_PATH]="String This";
Now I want the 1st three character from TCHAR , like below:
szDestPathRoot.substring(0,2);
How can I do this.
TCHAR[] is a simple null-terminated array (rather than a C++ class). As a result, there's no ".substring()" method.
TCHAR[] (by definition) can either be a wide character string (Unicode) or a simple char string (ASCII). This means there are wcs and str equivalents for each string function (wcslen() vs strlen(), etc etc). And an agnostic, compile-time TCHAR equivalent that can be either/or.
The TCHAR equivalent of strncpy() is tcsncpy().
Final caveat: to declare a TCHARliteral, it's best to use the _T() macro, as shown in the following snippet:
TCHAR szDestPathRoot[MAX_PATH] = _T("String This");
TCHAR szStrNew[4];
_tcsncpy (str_new, szTestPathRoot, 3);
You may find these links to be of interest:
http://msdn.microsoft.com/en-us/library/xdsywd25%28VS.71%29.aspx
http://www.i18nguy.com/unicode/c-unicode.html
http://msdn.microsoft.com/en-us/library/5dae5d43(VS.80).aspx (for using the secure _tcsncpy_s)
TCHAR szDestPathRoot[MAX_PATH]="String This";
TCHAR substringValue[4] = {0};
memcpy(substringValue, szDestPathRoot, sizeof(TCHAR) * 3);
As you have tagged your question with "C++" you can use the string classes of the std library:
std::wstring strDestPathRoot( _T("String This") );
strDestPathRoot.substr( 0, 2 );
This is somewhat ugly but if you know for sure that:
The string holds at least 4 TCHAR (3 chars plus the terminating NUL)
The content of the string can be modified (which is the case in your example).
You don't have to keep the original string intact
You could just put a terminating NUL at the 4th position to make the string 3 char long.
szDestPathRoot[3] = _T('\0');
Note that this operation is destructive to the original string
You should really be using a string class in C++ code though.