Programming In C and Win32 API: Comparing Strings - c

I am writing a program in C and Windows API. I am using Visual Studio 2010 Express and Character Set is set to "Not Set". I have made an edit control to accept username. Here's declaration:
hwnduser = CreateWindow (TEXT("EDIT"), NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
220, 70, 80, 20,
hwnd, (HMENU) 3, NULL, NULL);
I am fetching its value into a string named username.
len = GetWindowTextLength(hwnduser) + 1;
GetWindowText(hwnduser, username, len);
Now, the valid username is in a string called c_user:
char c_user[] = "foo";
When I compare them to check if the user has entered valid username using following code,
if (username == c_user)
{
MessageBox(hwnd, "Foo", "Bar", MB_OK);
}
else
{
MessageBox(hwnd, "Bar", "Foo", MB_OK);
}
It never validates. Instead, the else condition is always executed! Where am I making a mistake?
How to correct this?
I have tried strcmp! But still, output does not change. See the output(and comparison in code):

C and C++ have no built-in string type and so you cannot compare strings this way. C and C++ instead use an array of chars and this syntax simply compares the address of each array (which won't match).
Instead use strcmp() or _tcscmp().

I believe you'll actually need to use wchar_t's (wide characters). it's been a while since I've looked at the syntax but i think it'll be something like this:
wchar_t* c_user = L"foo";
if (wcscmp(username, c_user) == 0)
...
make sure username is also defined as the correct type.
you might also look into TCHAR which is a more generic representatic of a character type (it changes based off of the compiler settings). depending on settings, itll either be a char or wchar_t i think.

Writing username == c_user checks whether they both point to the same memory location.
You need to call strcmp to compare the strings' values.

I'd use strcmp (or any synonym)
if ( strcmp( username, c_user) == 0 )
{
// 0 indicate there is no difference, thus equal
}
else
{
}

You should use strcmp for this , or strcmpi if you want to ignore the case.

if (strcmp(username, c_user) == 0)
{
...
}

Use the functions GetWindowTextA() and MessageBoxA(), it works for me.

Related

Struggling with conversion of an LPBYTE to char* or anything alike in C (Chinese output?)

I've got a C project that I'm working on and I'm having a problem.
The program reads a string that is echoed by a .php page. It uses this code
to read the data and appoint it to a variable, which get sent to the Commands() function:
LPSTR szBuffer=(LPSTR)chunk+0x1000;
DWORD dwRead;
if (CWA(_HttpSendRequestA, wininet, hHttpRequest, szHeaders, lpstrlenA(szHeaders), szReq, lpstrlenA(szReq)) != 0)
{
CWA(_InternetReadFileA, wininet, hHttpRequest, szBuffer, 0x400, &dwRead);
if (dwRead)
Commands((LPBYTE)szBuffer, dwRead);
}
As you can see the data is sent to the Commands() function, which receives the LPBYTE szBuffer (named "command" in the function) and the DWORD dwRead (named "size" in the function).
In the Commands() function, it's supposed to read the string that it read from the .php page. However, since the data seems to be stored as LPBYTE, I've done a lot of things trying to get that to a char*. When I thought I had finally got it however, I tried outputting it using a MessageBox (to see if it displays the string it should have read). However, this returns me Chinese characters (while the original string should be this:
"TASKci=0C73CCFD206BBD011E7087CE0806E6F6E69630,job=dlex,ti=AD62A5950B76F3812C542C24040EACE9,pr=https,ur=//test.com/test.txt,cl=".
Screenshot of what it returns me: http://prntscr.com/h0p5iw
How the code inside Commands() looks:
BOOL Commands(LPBYTE command, DWORD size) {
LPTSTR x = (LPTSTR)((char*)command);
{
int msgboxID = MessageBox(
NULL,
x,
(LPCWSTR)L"Woop",
MB_ICONWARNING | MB_CANCELTRYCONTINUE | MB_DEFBUTTON2 );
}
CWA(Sleep, kernel32, 100);
return 1; }
I'm new at C (I've only written stuff in C# before) so I am sorry if I am asking any dumb questions, I've really tried my best but I cannot seem to find any solution by myself.
Also, keep in mind that everything except for the stuff inside the Commands() function is not coded by me but by someone who is way more experienced. That code should be fine and I am sure that it is reading the data from the page, it's probably just me screwing up a conversion somewhere.
A narrow string (char*) tends to look like Chinese when you use it somewhere that expects a wide UTF-16 Unicode string.
You cannot just cast the string to change its type, you need to call MultiByteToWideChar.

Add string to LPTSTR [duplicate]

This question already has answers here:
How do I concatenate const/literal strings in C?
(17 answers)
Closed 6 years ago.
I want to add an string to a LPTSTR.
The code is:
hSourceFile = CreateFile(
pszSourceFile,
FILE_READ_DATA,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE != hSourceFile)
{
_tprintf(
TEXT("The source plaintext file, %s, is open. \n"),
pszSourceFile);
}
The pszSourceFile is a type of LPTSTR, but i want to add some extra text.
Like (not working)
pszSourceFile + ".txt"
What is the best way to do this?
Considering the C-style and the use of the Windows API (with TEXT() et. al.); use _tcscat() or _tcsncat() (the later requires a buffer size).
For example;
TCHAR buffer[1024] = {}; // or '\0'
_tcsncat(buffer, pszSourceFile, 1024);
_tcsncat(buffer, TEXT(".txt"), 1024);
Demo.
Warning; watch out for your buffer overruns. Assuming the "normal" Windows 260 character path file and name limits (_MAX_PATH), the buffer needs to cater for that.
For C++ (as originally tagged), an alternative is to use std::basic_string<TCHAR> and then the operator+ (or +=) as per usual. The .c_str() will get you the resultant string;
std::basic_string<TCHAR> buffer(pszSourceFile);
buffer += TEXT(".txt");
auto ptr = buffer.c_str();
Your particular use case is not a simple "append" but rather an insert/format. Along the same lines as Niall you are using the TCHAR macros so I would recommend _stprintf_s (or _sntprintf_s... see MSDN)
TCHAR output[SIZE] = {0};
_stprintf_s(output, _T("The %s directory"), pszSourceFile);
Of course it depends on what exactly pszSourceFile is... if it is a std::string then you'll need to use the c_str() member to get a pointer, and you'll need to be careful about using std::string versus std::wstring.

Opening registry key in c

I have create a key using regedit, now I want to get its value. It doesn't give any error but it isn't showing anything.
Code :
int main() {
HKEY hKey;
RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Ehsan Akbari", 0, KEY_ALL_ACCESS, &hKey);
TCHAR sz[50];
DWORD size = 50,type;
RegEnumValue(hKey, 0, L"test", &size, NULL, &type, (LPBYTE)sz, &size);
RegCloseKey(hKey);
getch();
return 0;
}
An image of regedit :picture
What am I doing wrong?
Edit
When I debugged I saw that hKey is NULL, but GetLastError doesn't report anything.
Here are the immediate problems that I can see:
You detect no errors because you don't check for errors. Read the documentation for each function. The error code is returned in the return value.
You ask for KEY_ALL_ACCESS which won't be granted under HKLM. You need to request just read access KEY_READ.
Your screenshot shows the key has been created under HKCU, and you're trying to open it under HKLM.
RegEnumValue expects the size of the data buffer in bytes. You pass the length, the number of characters.
You are mixing Unicode literals and TCHAR. This is pointless. Your code won't compile targeting MBCS and in any case you don't care about Win98 any more. Stop using TCHAR and use wchar_t instead.
The lpValueName parameter must be a modifiable buffer. You pass a literal. Remember that this function enumerates values. It does not read specific named values as perhaps you expect.
The lpcchValueName parameter contains the size of the buffer you passed to lpcchValue in characters. You pass the length of the data buffer.
The data returned may not be null terminated. You must protect against this as described in the documentation.
For a C program which ignores its arguments, the correct main is int main(void).
I expect there are more errors but I stopped looking at this point. I recommend you spend some quality time with the documentation.
To open the path "Ehsan Akbari" in HKEY_CURRENT_USER you could try this:
HKEY hKey;
long result = RegOpenKeyEx(HKEY_CURRENT_USER , TEXT("\\Ehsan Akbari"), 0, KEY_ALL_ACCESS, &hKey);
if ( result == ERROR_SUCCESS )
{
cout << "OK" << endl;
}
else
{
cout << "Error " << result << endl;
}

I'm trying to list startup programs in C by using registry

I'm beginner in C and I want to make a program that lists all the startup programs in windows..
I figured out I can do this by opening the registers
so I opened the registers.
ret = RegOpenKeyEx (HKEY_LOCAL_MACHINE , TEXT ("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"), 0, KEY_QUERY_VALUE, &hKey);
and read
ret = RegQueryValueEx (hKey, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"), 0, &d_type, (LPBYTE)d_buffer, &d_byte );
my question is how can I get the strings(program names) from those registries?
I've been struggling due to the error when I tried to make an char arr[]; and move the values into it.
so maybe I'm doing something wrong.. should I use pointer or something?
could anyone give me some clues for this?
thanks
the flow goes like this :
1) open the registry key (registers are completly different things)
2) ask how many registry values the key has
3) iterate over them and get their data (which is what you are looking for)
this code snippet get the keyHandle, enumerate the values, and get theit data into a buffer
DWORD numberOfValues;
LONG result = RegQueryInfoKey(
keyHandle,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&numberOfValues,
NULL,
NULL,
NULL,
NULL);
wchar_t valueName [300];
DWORD bufferSize;
for (DWORD i = 0; i<numberOfValues; i++){
bufferSize = 300;
LONG result = RegEnumValue(
keyHandle,
i,
valueName,
&bufferSize,
0,
nullptr,
nullptr,
&bufferSize);
if (result == ERROR_SUCCESS){
valueName[bufferSize] = 0;
//do something with valueName, this is the name of the program
}
}
note: this program assume you define your program as Unicode program. (you should, since you can't really espect that all program names will be named in pure english)
note2 : I do realize you learn C, which is a woderfull language to start with, but this task was much easier using C++ or C#. keep that in mind for future tasks.
RegQueryValueEx (hKey, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"), 0, &d_type, (LPBYTE)d_buffer, &d_byte );
RegQueryValueEx only works if you know the name of the value in advance.
RegQueryValueEx (hKey, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"), "SmartAudio", &d_type, (LPBYTE)d_buffer, &d_byte );
If there is value with the name Smart Audio then it will print Data. But if you don't know name of value then you may use
int main()
{
system("C:\\Windows\\system32\\reg.exe QUERY HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Run");
}
It will give you output like this -

C code to check null pointer from json calls

I am a JSON newbie. It seems to me that I ought to be checking for a NULL pointer returned from all of the calls to cJSON_GetObjectItem(). But if there are MANY items within the object, this checking becomes quite verbose. Do I need to check for NULLs returned from this call, and if so, is there a better way to do it than shown below?
jsonPortArray = cJSON_GetObjectItem(jsonInput,"port");
if (jsonPortArray != NULL)
{
for (portIndex = 0; portIndex < cJSON_GetArraySize(jsonPortArray); portIndex++)
{
jsonPort = cJSON_GetArrayItem(jsonPortArray, portIndex);
if (jsonPort == 0)
break; // Bail out of loop if null ptr.
// ******* Is this safe? I see this style a lot.
port[portIndex].portNum = cJSON_GetObjectItem(jsonPort, "portNum")->valueint;
port[portIndex].portDir = cJSON_GetObjectItem(jsonPort, "portDir")->valueint;
port[portIndex].portType = cJSON_GetObjectItem(jsonPort, "portType")->valueint;
/*
I shortened the list of values to get, but there are MANY.
*/
// ******* Or do I need to check NULLs for every item, like this?
if ( cJSON_GetObjectItem(jsonPort, "portNum") != NULL)
{
port[portIndex].portNum = cJSON_GetObjectItem(jsonPort, "portNum")->valueint;
}
}
}
You should check for NULL, that or expect your program to segfault on bad input.
You can make it less verbose however:
#define JSON_OBJECT_NOT_NULL(jsonThing, name) \
(cJSON_GetObjectItem(jsonThing, name) != NULL ? \
cJSON_GetObjectItem(jsonThing, name)->valueint : -1)
...
port[portIndex].portNum = JSON_OBJECT_NOT_NULL(jsonPort, "portNum");
Here I use a macro and the inline if to either assign to the value of ->valueint or -1 if the return was NULL.
Please note that this behaviour isn't exactly the same as what you had, if the return is NULL, I'm setting the value to -1, you were taking no action in your example. If you set to -1, you do still have to later detect that it is the invalid -1 value.
Also, for readablity I broke the define into multiple lines, the \ characters are escaping the newlines, so that means no spaces after the \ characters, or, join it onto one line.
#define JSON_OBJECT_NOT_NULL(jsonThing, name) (cJSON_GetObjectItem(jsonThing, name) != NULL ? cJSON_GetObjectItem(jsonThing, name)->valueint : -1)
Well, first make sure you use NULL not 0 when checking. It's required in C.
But basically other than that, no. You can't do anything else. If you don't know if a value exists, you need to check before you use it. JSON, being unstructured as it is, requires this when using a strongly typed language. Java has the same "problem".
You can change your style to return values early to decrease indenting that makes code hard to read, but you need to check the return of your calls.

Resources