Thread: Really bad unicode problem with SendMessageW

  1. #1
    Registered User Rare177's Avatar
    Join Date
    May 2004
    Posts
    214

    Really bad unicode problem with SendMessageW

    ok well im making a admin tool for a chat program...bad thing is this program supports full unicode , the program i made hooks to the window and sends commands over winsock..but its not liking the idea of sending unicode with SendMessageW...here my code

    Code:
    	if (recv_buffer[0] == 'k') {
    
    	// Kick Command ...
    
    	TCHAR UserName[128];
    	TCHAR Password[128];
    	TCHAR Reason[128];
    	TCHAR RemoteUserName[128];
    	TCHAR Dummy[128];
    	MessageBoxPrintf(TEXT("test") , TEXT("%s") , recv_buffer);
    	// Store buffer in file ...
    
    	FILE *fp;
    	fp = fopen("temp.rtf","wt");
    	_ftprintf(fp, TEXT("%s"), recv_buffer);
    	fclose(fp);
    
    	// Read stored buffer into new char arrays
    
    	FILE *fpn;
    	fpn = fopen("temp.rtf","rt");
    	_ftscanf(fpn, TEXT("%127s %127s %127s %127s\n%127s"), Dummy, UserName, Password, RemoteUserName, Reason);
    	fclose(fpn);
    
    	for (int r=0; r<sizeof(Reason); r++){
    		if (Reason[r] == '_') {
    		   Reason[r] = ' ';
    		}
    	}
    
    	if (UserIsValid(UserName, Password)){
    
    		TCHAR Command[256] = {0};
    		TCHAR RoomMessage[256] = {0};
    		TCHAR LogMessage[256] = {0};
    
    		_stprintf(Command,"/kill", RemoteUserName);
    		if (REVEAL){
    		  _stprintf(RoomMessage,"/me %s will be kicked by %s (reason: %s).", RemoteUserName, UserName, Reason);
    		}else{
    		  _stprintf(RoomMessage,"/me %s will be kicked (reason: %s).", RemoteUserName, Reason);
    		}
    		_stprintf(LogMessage,"%s kicks %s - reason: %s\r\n", UserName, RemoteUserName, Reason);
    
     		AppendWindowText(hwndRichEdit, LogMessage);
    		MessageBoxPrintf(TEXT("test") , TEXT("%s") , RoomMessage);
    		SendMessage(HackedHandle, WM_SETTEXT, (WPARAM) &gte,  (LPARAM)RoomMessage);
    		SayIt();
    		Sleep(2000);
    		MessageBoxPrintf(TEXT("test") , TEXT("%s") , Command);
    		SendMessage(HackedHandle, WM_SETTEXT	, (WPARAM) &gte , (LPARAM)Command);
    		SayIt();
    
    	}else{
    
    		char ErrorMessage[128];
    		CHARFORMAT cf;
    
    		cf.dwMask = CFM_BOLD | CFM_COLOR;
    		cf.dwEffects = 0;
    		cf.cbSize = sizeof(cf);
    		cf.crTextColor = RGB(255,0,0);
    
    		SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf);
    
    		sprintf(ErrorMessage,"Kick command from %s - Access Denied (Incorrect Login).\r\n", inet_ntoa(from.sin_addr));
    		AppendWindowText(hwndRichEdit, ErrorMessage);
    
    		cf.crTextColor = RGB(0,0,255);
    
    		SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf);
    
    	}
    
    }
    thats just the command for one of the options..now no matter wat text i send to it that its ment to show..it allways comes up with things like this
    洯⁥⁦楷汬戠⁥楫正摥⠠敲獡湯›晧晧

    which is way off what it should be showing..please help , thanks
    Last edited by Rare177; 06-01-2004 at 05:57 AM.

  2. #2
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    OK, let's start at the top:

    If you want to use TCHAR functions you need to use the TEXT or _T macros.
    Code:
    	_ftprintf(fp,"%s", recv_buffer);
    should be:
    Code:
    	_ftprintf(fp, TEXT("%s"), recv_buffer);
    This following line is as bad as using gets() five times.
    Code:
    	_ftscanf(fpn,"%s %s %s %s\n%s", Dummy, UserName, Password, RemoteUserName, Reason);
    Since you don't specify a maximum length for any of the input strings, a malicious user can and will pass in longer strings. Since this input is received from the network, that qualifies as being a very bad thing. The code should look something like:
    Code:
    	_ftscanf(fpn, TEXT("%127s %127s %s %127s\n%127s"), Dummy, UserName, Password, RemoteUserName, Reason);
    Now to the actual problem:
    Code:
    		SendMessageW(HackedHandle, WM_SETTEXT, (WPARAM) &gte,  (LPARAM)RoomMessage);
    RoomMessage is an ANSI character string and you are passing it to SendMessageW which is expecting a UNICODE string. This is not going to give the correct results. I have no idea what gte is, but wParam should typically be zero for this message.

    If you really need a unicode command string use wsprintfW(), swprintf(), _snwprintf() or StringCchPrintfW() to create one. If you only need an ANSI command string, just use SendMessage().

    The problem is that you have a mix of TCHAR and char strings that is just not going to work. You need to decide if your program is going to be TCHAR compatible and run with it.

    Also note that sizeof(string) returns the size of an array in bytes and not in characters. To get the size of an array you need to divide by the size of a single element.
    Code:
    // WRONG! Passes the number of bytes of szBuffer instead of the number of characters.
    SendMessage(hwnd, WM_GETTEXT, sizeof(szBuffer), (LPARAM) szBuffer);
    
    // RIGHT, but unwieldy.
    SendMessage(hwnd, WM_GETTEXT, sizeof(szBuffer) / sizeof(szBuffer[0]), (LPARAM) szBuffer);
    
    // RIGHT, uses a macro to clean things up.
    #define ARRAYSIZE(arr) (sizeof(arr)/sizeof((arr)[0]))
    SendMessage(hwnd, WM_GETTEXT, ARRAYSIZE(szBuffer), (LPARAM) szBuffer);
    Last edited by anonytmouse; 06-01-2004 at 03:53 AM.

  3. #3
    Registered User Rare177's Avatar
    Join Date
    May 2004
    Posts
    214

    thanks a heap

    thank you so much for your reply
    if i declare them all as TCHAR do you think that may solve the problem along with changing the things u stated

  4. #4
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    Well it depends, it would be a good start. Are the contents of recv_buffer TCHAR? That is did you send them as TCHAR? Make sure you #define UNICODE and _UNICODE in your project settings or before #including header files. This will show you where some of the problems are.
    Code:
    	for (int r=0; r<sizeof(Reason); r++){
    Remember, to fix this, as outlined above.

    Can I ask why you need unicode?

  5. #5
    Registered User Rare177's Avatar
    Join Date
    May 2004
    Posts
    214
    well its a admin tool for a chat program which uses unicode
    alot of people have unicode in there names..so its not really to great without unicode..and yes the client is sending them as TCHAR and i set the server to recieve as TCHAR..only problem now is that it show
    k %s %s %s in the messagebox

    i really appreciate your help this has been stressing me out

  6. #6
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    Which message box? Have you defined UNICODE and _UNICODE and got it to compile?

  7. #7
    Registered User Rare177's Avatar
    Join Date
    May 2004
    Posts
    214
    if you look on the server before it does it all stuff theres a messagebox that prints all of it im not sure wats wrong and yes i defined UNICODE and _UNICODE
    maybe something from the client...heres the code for the client

    Code:
    	if ((HWND) lParam == hwndKick) {
    
    		TCHAR UserName[256];
    		TCHAR Password[256];
    		TCHAR RemoteUserName[256];
    		TCHAR Reason[256];
    
    		SendMessageW(hwndUserNameEdit, WM_GETTEXT, (WPARAM) sizeof(UserName), (LPARAM) UserName);
    		SendMessageW(hwndPasswordEdit, WM_GETTEXT, (WPARAM) sizeof(Password), (LPARAM) Password);
    		SendMessageW(hwndRemoteNameEdit, WM_USER + 94, (WPARAM) &gte , (LPARAM) RemoteUserName);
    		SendMessageW(hwndReasonEdit, WM_GETTEXT, (WPARAM) sizeof(Reason), (LPARAM) Reason);
    
    		MessageBoxPrintf(TEXT("test") , TEXT("%s") , RemoteUserName);
    
    		if (strcmp(UserName,"")==0){
    			AppendWindowText(hwndRichEdit,"> Please enter your User Name.\r\n");
    			break;
    		}else
    
    		if (strcmp(Password,"")==0){
    			AppendWindowText(hwndRichEdit,"> Please enter your Password.\r\n");
    			break;
    		}else
    
    		if (strcmp(RemoteUserName,"")==0){
    			AppendWindowText(hwndRichEdit,"> Please enter the User Name of the person you want to kick.\r\n");
    			break;
    		}else
    
    		if (strcmp(Reason,"")==0){
    			AppendWindowText(hwndRichEdit,"> Please give a reason as to why you wish to kick this user.\r\n");
    			break;
    		}
    
    		for (int i=0; i<ARRAYSIZE(Reason); i++){
    
    			if (Reason[i] == ' '){
    				Reason[i] = '_';
    			}
    
    		}
    
    
    		swprintf(SendBuffer,"k %s %s %s\n%s", UserName, Password, RemoteUserName, Reason);
    
    		MessageBoxPrintf(TEXT("test") , TEXT("%s") , SendBuffer);
    
    		_beginthread(ConnectAndSend, 0, NULL);
    
    	}

  8. #8
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    OK, you must be getting a ton of warnings!

    Code:
    SendMessageW(hwndUserNameEdit, WM_GETTEXT, (WPARAM) sizeof(UserName), (LPARAM) UserName);
    Again, using sizeof in this manner is not correct. See my original post.

    Code:
    		if (strcmp(UserName,"")==0){
    If you have UNICODE/_UNICODE correctly defined this will be giving a compiler warning or error. strcmp is for comparing two ansi strings. The TCHAR version is:
    Code:
    		if (_tcscmp(UserName,TEXT(""))==0){
    Code:
    		swprintf(SendBuffer,"k %s %s %s\n%s", UserName, Password, RemoteUserName, Reason);
    This must be giving a warning. You are passing an ANSI string to a unicode function. To use the TCHAR version would look like:
    Code:
    		_stprintf(SendBuffer,TEXT("k %s %s %s\n%s"), UserName, Password, RemoteUserName, Reason);
    Code:
    		SendMessageW(hwndUserNameEdit, WM_GETTEXT, (WPARAM) sizeof(UserName), (LPARAM) UserName);
    I would just use the generic SendMessage without the W. If you have UNICODE defined the pre-processor will replace it with the W version. This makes it easier to build an ansi version that will run on windows 9x by simply not defining UNICODE.

    Unfortunately, you can not ignore the warnings. They need to be worked through.

  9. #9
    Registered User Rare177's Avatar
    Join Date
    May 2004
    Posts
    214
    i cant thank you enough
    ill give it a go

  10. #10
    Registered User Rare177's Avatar
    Join Date
    May 2004
    Posts
    214
    ok its working much better know , i can actually get text to show
    only one thing wrong thou...i was testing this lot of unicode
    ẸẶẲẵẶẶẴẴ
    and it was comming up as
    ¸ ¶ ² µ ¶ ¶ ´ ´
    i have defined unicode and _unicode as #define UNICODE
    and #define _UNICODE
    and gte is the structure for GETTEXTEX
    i reposted the server again up there ^^ thanks!

  11. #11
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    OK, much better, we're getting there!

    You missed this:
    Code:
    	for (int r=0; r<sizeof(Reason); r++){
    --
    Code:
    		_stprintf(Command,"/kill", RemoteUserName);
    You should be getting a warning for these. You must qualify with TEXT macro. Pretty much all string literals should be surrounded with the TEXT macro.
    --
    Is UNICODE/_UNICODE defined in the file where the MessageBoxPrintf() function is? What about the AppendWindowText()? It looks like the MessageBoxPrintf function is still expecting ansi strings.

    P.S Just repost the code when needed rather than editing(unless it is very large). Less scrolling! :-)

  12. #12
    Registered User Rare177's Avatar
    Join Date
    May 2004
    Posts
    214
    where abouts do u put

    Code:
    for (int r=0; r<sizeof(Reason); r++){
    theres one in there as

    Code:
    	for (int r=0; r<sizeof(Reason); r++){
    		if (Reason[r] == '_') {
    		   Reason[r] = ' ';
    		}
    	}

  13. #13
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    I meant you need to replace it with:
    Code:
    for (int r=0; r<ARRAYSIZE(Reason); r++){
    because sizeof(Reason) will equal 256 when UNICODE is defined and you will go way past the end of the array which is 128 characters long.

    P.S I'm off for a while now.

  14. #14
    Registered User Rare177's Avatar
    Join Date
    May 2004
    Posts
    214
    ok im really stuck i have gone throu it several times and i cant seem to find out wats wrong..theres a few bugs but nothing compared to what it is before
    1.when it recieves ANSI strings it only shows the first char
    2.when you send unicode it sends but converts to ascii art text but isnt one char like the first one
    3.for the command where its /kill RemoteUsername and it sends command as the last message, its only showing /kill and no remote username..ill include all definitions and includes....also test.h is for messageboxprintf

    Code:
    definitions and includes for the server 
    
    
    Code:
    #include <windows.h>
    #include <richedit.h>
    #include <winsock2.h>
    #include <stdio.h>
    #include <process.h>
    #include <shellapi.h>
    #include <wchar.h>
    #include "test.h"
    
    #define UNICODE
    #define _UNICODE
    #define ARRAYSIZE(arr) (sizeof(arr)/sizeof((arr)[0]))
    #define IDI_ICON1 500
    #define IDI_APP_ICON 600
    #define IDI_TRAY_ICON 800
    #define BANNER
    
    #define WM_TRAYNOTIFY		(WM_USER + 1000)
    #define IDC_TRAYICON		1001
    
    #define ID_TRAY_EXIT		1002
    #define ID_TRAY_RESTORE		1003
    #define ID_TRAY_HIDE		1004
    the kick command for the server
    Code:
    
    	if (recv_buffer[0] == 'k') {
    
    	// Kick Command ...
    
    	TCHAR UserName[128];
    	TCHAR Password[128];
    	TCHAR Reason[128];
    	TCHAR RemoteUserName[128];
    	TCHAR Dummy[128];
    	MessageBoxPrintf(TEXT("test") , TEXT("%s") , recv_buffer);
    	// Store buffer in file ...
    
    	FILE *fp;
    	fp = fopen("temp.rtf","wt");
    	_ftprintf(fp, TEXT("%s"), recv_buffer);
    	fclose(fp);
    
    	// Read stored buffer into new char arrays
    
    	FILE *fpn;
    	fpn = fopen("temp.rtf","rt");
    	_ftscanf(fpn, TEXT("%127s %127s %127s %127s\n%127s"), Dummy, UserName, Password, RemoteUserName, Reason);
    	fclose(fpn);
    
    	for (int r=0; r<ARRAYSIZE(Reason); r++){
    		if (Reason[r] == '_') {
    		   Reason[r] = ' ';
    		}
    	}
    
    	if (UserIsValid(UserName, Password)){
    
    		TCHAR Command[256] = {0};
    		TCHAR RoomMessage[256] = {0};
    		TCHAR LogMessage[256] = {0};
    
    		_stprintf(Command,"/kill", RemoteUserName);
    		if (REVEAL){
    		  _stprintf(RoomMessage,"/me %s will be kicked by %s (reason: %s).", RemoteUserName, UserName, Reason);
    		}else{
    		  _stprintf(RoomMessage,"/me %s will be kicked (reason: %s).", RemoteUserName, Reason);
    		}
    		_stprintf(LogMessage,"%s kicks %s - reason: %s\r\n", UserName, RemoteUserName, Reason);
    
     		AppendWindowText(hwndRichEdit, LogMessage);
    		MessageBoxPrintf(TEXT("test") , TEXT("%s") , RoomMessage);
    		SendMessage(HackedHandle, WM_SETTEXT, (WPARAM) &gte,  (LPARAM)RoomMessage);
    		SayIt();
    		Sleep(2000);
    		MessageBoxPrintf(TEXT("test") , TEXT("%s") , Command);
    		SendMessage(HackedHandle, WM_SETTEXT	, (WPARAM) &gte , (LPARAM)Command);
    		SayIt();
    
    	}else{
    
    		char ErrorMessage[128];
    		CHARFORMAT cf;
    
    		cf.dwMask = CFM_BOLD | CFM_COLOR;
    		cf.dwEffects = 0;
    		cf.cbSize = sizeof(cf);
    		cf.crTextColor = RGB(255,0,0);
    
    		SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf);
    
    		sprintf(ErrorMessage,"Kick command from %s - Access Denied (Incorrect Login).\r\n", inet_ntoa(from.sin_addr));
    		AppendWindowText(hwndRichEdit, ErrorMessage);
    
    		cf.crTextColor = RGB(0,0,255);
    
    		SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf);
    
    	}
    
    }
    the def's and includes for the client
    Code:
    #include <windows.h>
    #include <winsock2.h>
    #include <richedit.h>
    #include <stdio.h>
    #include <process.h>
    #include <shellapi.h>
    #include <commctrl.h>
    #include <wchar.h>
    #include "test.h"
    
    #define ARRAYSIZE(arr) (sizeof(arr)/sizeof((arr)[0]))
    #define UNICODE
    #define _UNICODE
    #define IDI_ICON1 500
    #define IDI_APP_ICON 600
    #define BANNER 700
    #define MINI 		807
    #define UNBAN 802
    #define WM_TRAYNOTIFY 			(WM_USER + 1000)
    #define IDC_TRAYICON  			1001
    #define RT_MANIFEST				24
    
    #define IDM_POP_EXIT        	1002
    #define IDM_POP_RESTORE     	1003
    #define IDM_POP_HIDE			1004
    the kick command for the client
    Code:
    	if ((HWND) lParam == hwndKick) {
    
    		TCHAR UserName[256];
    		TCHAR Password[256];
    		TCHAR RemoteUserName[256];
    		TCHAR Reason[256];
    
    		SendMessage(hwndUserNameEdit, WM_GETTEXT, (WPARAM)ARRAYSIZE(UserName), (LPARAM) UserName);
    		SendMessage(hwndPasswordEdit, WM_GETTEXT, (WPARAM) ARRAYSIZE(Password), (LPARAM) Password);
    		SendMessage(hwndRemoteNameEdit, WM_USER + 94, (WPARAM) &gte , (LPARAM) RemoteUserName);
    		SendMessage(hwndReasonEdit, WM_GETTEXT, (WPARAM) ARRAYSIZE(Reason), (LPARAM) Reason);
    
    		MessageBoxPrintf(TEXT("test") , TEXT("%s") , RemoteUserName);
    
    		if (_tcscmp(UserName,TEXT(""))==0){
    			AppendWindowText(hwndRichEdit,"> Please enter your User Name.\r\n");
    			break;
    		}else
    
    		if (_tcscmp(UserName,TEXT(""))==0){
    			AppendWindowText(hwndRichEdit,"> Please enter your Password.\r\n");
    			break;
    		}else
    
    		if (_tcscmp(UserName,TEXT(""))==0){
    			AppendWindowText(hwndRichEdit,"> Please enter the User Name of the person you want to kick.\r\n");
    			break;
    		}else
    
    		if (_tcscmp(UserName,TEXT(""))==0){
    			AppendWindowText(hwndRichEdit,"> Please give a reason as to why you wish to kick this user.\r\n");
    			break;
    		}
    
    		for (int r=0; r<ARRAYSIZE(Reason); r++){
    
    			if (Reason[r] == ' '){
    				Reason[r] = '_';
    			}
    
    		}
    
    
    		_stprintf(SendBuffer,TEXT("k %s %s %s\n%s"), UserName, Password, RemoteUserName, Reason);
    
    		MessageBoxPrintf(TEXT("test") , TEXT("%s") , SendBuffer);
    
    		_beginthread(ConnectAndSend, 0, NULL);
    
    	}
    thanks for helping muchly appreciated

  15. #15
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    - The #define for UNICODE/_UNICODE must go before the #includes or in your project settings. Where you have it has no effect! Also, you should #include <tchar.h>.
    Code:
    #define UNICODE
    #define _UNICODE
    #include <windows.h>
    #include <winsock2.h>
    #include <richedit.h>
    #include <shellapi.h>
    #include <commctrl.h>
    #include <process.h>
    #include <stdio.h>
    #include <wchar.h>
    #include <tchar.h>
    #include "test.h"
    --
    Code:
    	_stprintf(Command,"/kill", RemoteUserName);
    As mentioned, you are not using RemoteUserName here. Possibly you want:
    Code:
    	_stprintf(Command, TEXT("/kill %s"), RemoteUserName);
    --
    Code:
    	_ftprintf(fp, TEXT("%s"), recv_buffer);
    There is no need to output to a temp file just to use _ftscanf(). You can use _stscanf()(the TCHAR version of sscanf) to scan directly from the buffer.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Minor problem...bad stuff
    By beene in forum Windows Programming
    Replies: 19
    Last Post: 10-21-2006, 06:11 AM
  2. message box and unicode problem
    By Jumper in forum Windows Programming
    Replies: 2
    Last Post: 05-11-2004, 02:53 PM
  3. Replies: 5
    Last Post: 12-03-2003, 05:47 PM
  4. Cursor, UNICODE and VK's
    By GaPe in forum C Programming
    Replies: 10
    Last Post: 04-07-2002, 03:45 AM
  5. beginner problem
    By The_Nymph in forum C Programming
    Replies: 4
    Last Post: 03-05-2002, 05:46 PM