4

I'm still an extreme noob when it comes to C++. And one of the things (as of now) I currently hate, is the 1,000,000,000 different types of variables in winAPI. This small program I made to check if a window exists was made really quickly. But what's the hardest part? Simply comparing "strings" together to see if it's the match. The simplest part is the hardest!

Anyways, to my question: How can I compare a to toFind, to see if they match?

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lparam){
    TCHAR a[260];
    string toFind = "Google Chrome";

    hwnd = GetParent(hwnd);
    GetWindowText(hwnd, a, sizeof(a));

    if(strcmp(a,toFind) == 0){          //doesn't work
        cout << "found the window";
    }

    return TRUE;
}
Justin
  • 409
  • 2
  • 8
  • 14
  • 1
    Are you compiling with `UNICODE` defined? The answer will depend on whether `TCHAR` is `wchar_t` or `char`. – Jesse Good Jul 30 '13 at 05:13
  • @JesseGood "Character Set: Use Unicode Character Set" – Justin Jul 30 '13 at 05:15
  • @Jesse: It doesn't have to. The whole point of the `t` family is to abstract over whether `UNICODE` is defined or not. – icktoofay Jul 30 '13 at 05:19
  • @JesseGood I had to use TCHAR for the GetWindowText function. – Justin Jul 30 '13 at 05:23
  • Your code has a buffer overrun in it. `GetWindowText` wants the size in characters, and you are giving it the size in bytes. If `TCHAR` is `wchar_t` the two are not the same. – Joel Jul 30 '13 at 05:47
  • Read [this answer to question](http://stackoverflow.com/a/17838574/1237747). It is not the thing you are looking for but also advice. Main point of that it is to use strings in stead of char arrays. – ST3 Jul 30 '13 at 06:05
  • Your introduction mentions both "C++" and "WinAPI". Please be aware that the WinAPI is a mix of technologies, with significant parts (such as this) being pure C instead of C++. In C++, you can compare `std::string` like integers, with `a==b`. This is very intentional, it's why `std::find` can work on any type of container. – MSalters Jul 30 '13 at 07:59

4 Answers4

5

The easiest way is probably not to use c-style arrays to begin with and since you are compiling with UNICODE to use std::wstring:

std::wstring a;
a.resize(260);
std::wstring toFind = L"Google Chrome";

hwnd = GetParent(hwnd);
int size = GetWindowText(hwnd, &a[0], a.size());
a.resize(size);

Then it is simple as:

if(a == toFind)
{

}
Jesse Good
  • 50,901
  • 14
  • 124
  • 166
  • I don't think that will actually work as-is. `const char* const Value = "Google Chrome"; string buf(Value); string buf2; buf2.resize(260); strcpy(&buf2[0], Value); cout << "Equal? " << (buf == buf2) << "\n";` This prints `Equal? 0` for me. `string` can contain embedded nulls. – Joel Jul 30 '13 at 05:57
  • @Joel: Thanks for the comment. I forgot to resize the string after the call (updated). In your example, just add `buf2.resize(buf.size());` after the cal to `strcpy`. – Jesse Good Jul 30 '13 at 06:12
  • In this case, it _will_ contain embedded nuls. There's one at `[260]`, but `GetWindowText(hwnd, &a[0], 260)` adds a nul _before_ `[260]`. – MSalters Jul 30 '13 at 08:47
  • Right. The code is fixed now, but originally it would have been comparing essentially `"Google Chrome"` against `"Google Chrome\0\0\0\0\0..."`. With regular C strings and `strcmp`, that would have been OK, but with `std::basic_string` they don't compare equal because `std::basic_string` is not null-terminated. – Joel Jul 30 '13 at 12:47
3

You shouldn't use string in that case but also a TCHAR[] and then compare with the appropriate wrapper function:

TCHAR toFind[] = _T("Google Chrome");

...

if (_tcscmp(a, toFind) == 0)

TCHAR might be char or wchar_t, depending on whether UNICODE is defined (and I surely hope it is defined in your case, which also might explain why it isn't working directly). So if you decide to use it (I wouldn't, as I am fairly sure I never, ever will write software for Windows 9x/ME again or generally software without Unicode support), you also have to abide by its rules.

Joey
  • 344,408
  • 85
  • 689
  • 683
  • Easier solution was to typedef a `tstring`( i.e. `std::basic_string` ). But indeed, todays easy solution is `UNICODE` – MSalters Jul 30 '13 at 08:00
  • I was unaware of being able to use `std::basic_string` as a plain old `T[]`, due to not really being a C++ developer. Jesse's answer is probably better anyway (but points out a pitfall of that approach too). – Joey Jul 30 '13 at 08:13
0

Change the string type from "string" to "wstring". You'll also have to change "strcmp" to something like "wstrcmp". Basically, wstring are wide strings used in UNICODE.

Cos314
  • 302
  • 1
  • 5
0

std::string is a typedef of std::basic_string. std::wstring is typedef std::basic_string.

What you want is

typedef std::basic_string<TCHAR> tstring;

And then use in-place of std::string.

See also tchar vs wstring and std::basic_string

Community
  • 1
  • 1
kfsone
  • 23,617
  • 2
  • 42
  • 74