Advertisement

Character set problems

Started by July 05, 2010 12:06 AM
7 comments, last by rip-off 8 years ago
I'm sorry in advance if this is in the wrong section, I looked around and this seemed the best place to put this. Now for the question:

I recently started reading a book "Programming a multiplayer FPS in Directx" after seeing some reviews I realized that coming into this the code was poorly written and had errors but I was still interested.

After trying to run the source on the final chapter I saw many, many errors that took quite a while to troubleshoot and reapir but I managed to widdle down the errors from a few hundred to about 8.

Now this is where I get confused, the errors can easily be fixed by changing my character set to multi-byte but when it is multi-byte the error count goes up by 50. I'm still sort of new to this but I assume that the author wrote some multi-byte code for a unicode program. Anyway I need a fix of some sort that keeps the character set at Unicode but stops this error.

Here's the code and the error report.

#include "Main.h"//-----------------------------------------------------------------------------// Allows the menu dialog to update the sessions list.//-----------------------------------------------------------------------------void UpdateSessionsList( HWND window ){	// Enumerate the current sessions on the network.	g_engine->GetNetwork()->EnumerateSessions();	// Try to keep the same session selected, if it still exists.	SessionInfo *selectedSession = NULL;	int selected = (int)SendMessage( GetDlgItem( window, IDC_SESSIONS ), LB_GETCURSEL, 0, 0 );	if( selected != LB_ERR )		selectedSession = (SessionInfo*)SendMessage( GetDlgItem( window, IDC_SESSIONS ), LB_GETITEMDATA, selected, 0 );	// Tell the sessions list box not to redraw itself since it will change.	SendMessage( GetDlgItem( window, IDC_SESSIONS ), WM_SETREDRAW, false, 0 );	// Clear the contents of the sessions list box.	SendMessage( GetDlgItem( window, IDC_SESSIONS ), LB_RESETCONTENT, 0, 0 );	// Go through the list of sessions found on the local network.	char name[MAX_PATH];	SessionInfo *session = g_engine->GetNetwork()->GetNextSession( true );	while( session != NULL )	{		// Convert this session's name into a character string.		wcstombs( name, session->description.pwszSessionName, MAX_PATH );		// Add this session to the sessions list box.		int index = (int)SendMessage( GetDlgItem( window, IDC_SESSIONS ), LB_ADDSTRING, 0, (LPARAM)name );		SendMessage( GetDlgItem( window, IDC_SESSIONS ), LB_SETITEMDATA, index, (LPARAM)session );		// Check if this is the session the was selected before.		if( selectedSession == session )			SendMessage( GetDlgItem( window, IDC_SESSIONS ), LB_SETCURSEL, index, 0 );		// Go to the next session.		session = g_engine->GetNetwork()->GetNextSession();	}	// If there was no selected session, then select the first session.	if( selectedSession == NULL )		SendMessage( GetDlgItem( window, IDC_SESSIONS ), LB_SETCURSEL, 0, 0 );	// Tell the sessions list box to redraw itself now.	SendMessage( GetDlgItem( window, IDC_SESSIONS ), WM_SETREDRAW, true, 0 );	InvalidateRect( GetDlgItem( window, IDC_SESSIONS ), NULL, false );}//-----------------------------------------------------------------------------// Call back function for the menu's dialog.//-----------------------------------------------------------------------------int CALLBACK MenuDialogProc( HWND window, UINT msg, WPARAM wparam, LPARAM lparam ){	// These are used to keep the text in the edit boxes between state changes.	static char name[MAX_PATH] = "Unknown Player";	static char character[MAX_PATH] = "Marine.txt";	static char map[MAX_PATH] = "Abandoned City.txt";	switch( msg )	{		case WM_INITDIALOG:		{			// Show the player's name, selected character, and selected map.			SetWindowText( GetDlgItem( window, IDC_NAME ), name );			SetWindowText( GetDlgItem( window, IDC_CHARACTER ), character );			SetWindowText( GetDlgItem( window, IDC_MAP ), map );			// Allow the sessions list to update.			UpdateSessionsList( window );			return true;		}		case WM_COMMAND:		{			switch( LOWORD( wparam ) )			{				case IDC_HOST:				{					// Get the character and map.					PlayerData data;					GetWindowText( GetDlgItem( window, IDC_CHARACTER ), character, MAX_PATH );					GetWindowText( GetDlgItem( window, IDC_MAP ), map, MAX_PATH );					strcpy( data.character, character );					strcpy( data.map, map );					// Get the player's name.					GetWindowText( GetDlgItem( window, IDC_NAME ), name, MAX_PATH );					// Create a session name using the player's name.					char session[MAX_PATH];					sprintf( session, "%s's Session", name );					// Host a new session then switch to the game state.					if( g_engine->GetNetwork()->Host( name, session, 8, &data, sizeof( data ) ) )					{						g_engine->ChangeState( STATE_GAME );						EndDialog( window, true );					}					return true;				}				case IDC_SESSIONS:				{					// Check if the user double clicked on the session list.					if( HIWORD( wparam ) != LBN_DBLCLK )						return true;				} // If so, then fall through to IDC_JOIN.				case IDC_JOIN:				{					// Get the character.					PlayerData data;					GetWindowText( GetDlgItem( window, IDC_CHARACTER ), character, MAX_PATH );					strcpy( data.character, character );					// Get the player's name.					GetWindowText( GetDlgItem( window, IDC_NAME ), name, MAX_PATH );					// Get the selected session.					int session = (int)SendMessage( GetDlgItem( window, IDC_SESSIONS ), LB_GETCURSEL, 0, 0 );					// Join the selected session then switch to the game state.					if( g_engine->GetNetwork()->Join( name, session, &data, sizeof( data ) ) )					{						g_engine->ChangeState( STATE_GAME );						EndDialog( window, true );					}					else					{						// If the join failed, it may be because the session						// doesn't exist any more, so refresh the session list.						UpdateSessionsList( window );					}					return true;				}				case IDC_REFRESH:				{					// Refresh the session list.					UpdateSessionsList( window );					return true;				}				case IDC_EXIT:				{					PostQuitMessage( 0 );					return true;				}			}		}	}	return false;}//-----------------------------------------------------------------------------// Menu class constructor.//-----------------------------------------------------------------------------Menu::Menu() : State( STATE_MENU ){	// Does nothing but set's the state's ID.}//-----------------------------------------------------------------------------// Update the menu state.//-----------------------------------------------------------------------------void Menu::Update( float elapsed ){	// Display the menu dialog. Processing will hang here until this is closed.	DialogBox( NULL, MAKEINTRESOURCE( IDD_MENU ), g_engine->GetWindow(), MenuDialogProc );}





And here is the Error report ignore the error about materials thats just something that needs to be commented out:



1>------ Build started: Project: Game, Configuration: Debug Win32 ------1>Compiling...1>GameMaterial.cpp1>c:\documents and settings\riley\desktop\chapter 13\game\gamematerial.cpp(14) : error C2512: 'Material' : no appropriate default constructor available1>Menu.cpp1>c:\documents and settings\riley\desktop\chapter 13\game\menu.cpp(36) : warning C4996: 'wcstombs' was declared deprecated1>        c:\program files\microsoft visual studio 8\vc\include\stdlib.h(562) : see declaration of 'wcstombs'1>        Message: 'This function or variable may be unsafe. Consider using wcstombs_s instead. To disable deprecation, use _CRT_SECURE_NO_DEPRECATE. See online help for details.'1>c:\documents and settings\riley\desktop\chapter 13\game\menu.cpp(74) : error C2664: 'SetWindowTextW' : cannot convert parameter 2 from 'char [260]' to 'LPCWSTR'1>        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast1>c:\documents and settings\riley\desktop\chapter 13\game\menu.cpp(75) : error C2664: 'SetWindowTextW' : cannot convert parameter 2 from 'char [260]' to 'LPCWSTR'1>        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast1>c:\documents and settings\riley\desktop\chapter 13\game\menu.cpp(76) : error C2664: 'SetWindowTextW' : cannot convert parameter 2 from 'char [260]' to 'LPCWSTR'1>        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast1>c:\documents and settings\riley\desktop\chapter 13\game\menu.cpp(92) : error C2664: 'GetWindowTextW' : cannot convert parameter 2 from 'char [260]' to 'LPWSTR'1>        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast1>c:\documents and settings\riley\desktop\chapter 13\game\menu.cpp(93) : error C2664: 'GetWindowTextW' : cannot convert parameter 2 from 'char [260]' to 'LPWSTR'1>        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast1>c:\documents and settings\riley\desktop\chapter 13\game\menu.cpp(98) : error C2664: 'GetWindowTextW' : cannot convert parameter 2 from 'char [260]' to 'LPWSTR'1>        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast1>c:\documents and settings\riley\desktop\chapter 13\game\menu.cpp(126) : error C2664: 'GetWindowTextW' : cannot convert parameter 2 from 'char [260]' to 'LPWSTR'1>        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast1>c:\documents and settings\riley\desktop\chapter 13\game\menu.cpp(130) : error C2664: 'GetWindowTextW' : cannot convert parameter 2 from 'char [260]' to 'LPWSTR'1>        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast




This is one of the problem lines, they all look somewhat like this:
SetWindowText( GetDlgItem( window, IDC_NAME ), name );
First, thanks for bringing up some truly horrific supresssed memories. This bit me hard with the source code from "Windows Game Programming for Dummies" (I've progressed from dummy to mildly retarded since).

Secondly,

    char buffer[260];    sprintf(buffer, YOUR STRING HERE /* , var, var, etc */);    // Convert to a wchar_t*    size_t origsize = strlen(buffer) + 1;    const size_t newsize = 100;    size_t convertedChars = 0;    wchar_t wcstring[newsize];    mbstowcs_s(&convertedChars, wcstring, origsize, buffer, _TRUNCATE);


wcstring becomes useable as your LPCWSTR.

or alternatively, if you know the string at coding time, there's the simple but ugly

static TCHAR szTitle[] = _T("YOUR STRING HERE");


Both of these have been working quite happily for me in VC++ Express 2008.
The high cost of living hasn't affected its popularity.
Advertisement
Thanks for the help but I'm still quite new to this, how would I apply that fix to the code above?
For simplicity, try replacing

static char name[MAX_PATH] = "Unknown Player";//withstatic TCHAR name[] = _T("Unknown Player");


(dont forget to include <tchar.h>) and see if that removes any errors. Secondly, I've noticed your code using the function wcstombs, and you'll note my fix uses its inverse, mbstowcs. It's probably worth just feeding the argument you're trying to convert, session->description.pwszSessionName for example, into the SetWindowText function as argument 2, e.g.

SetWindowText(window, session->description.pwszSessionName );


and see if that works.

For a re-usable fix, you can wrap the larger block of code i posted into a function called stringConverter or similar, and before an instance that generates the "can't convert from char [260] to LPCWSTR" error, use it to convert the char[] to a wchar_t[]. Then feed your function the wchar_t.
The high cost of living hasn't affected its popularity.
Applying that first fix to name, map, and character reduced my errors from 8 to 6 but now I'm getting 6 errors that all look somewhat like this:

error C2664: 'strcpy' : cannot convert parameter 2 from 'TCHAR [11]' to 'const char *'
Same problem in reverse :) . Your strcpy lines are trying to copy the TCHAR[] into a struct(or class maybe) called data. I can't see where data is defined (and it looks like a lot of the confusion is coming out of a resource file - I don't know much about them, my compiler doesn't support editing them, but all your IDC_??? type tags are referencing data inside it).

what you can now do is something like:
//Add variations of these two lines before strcpy, or better yet, write a functionchar* convertedString;wcstombs(convertedString, name, name.length());//existing line examplestrcpy(data.name, convertedString);


You'll need to play around with things like predetermined lengths of convertedString, whether or not there is such a function as tchar::length() (for name.length() ) and such, but tinkering with things is the fun part of building them. Unfortunately I've spent the day coding assembly for an inverter, so I'm not in C++ space right now :)
The high cost of living hasn't affected its popularity.
Advertisement
There is usually one set of functions that operate on char and another that operate on wchar_t. There is a generic character type, TCHAR, which become char or wchar_t depending on your character set settings for the project. The various Windows functions will switch between SomeFunctionA or SomeFunctionW (for the function SomeFunction) depending on these settings too. For C run-time library functions, consult MSDN; for example, the generic form of strcpy is _tcscpy. It may be easier to use these generic forms throughout your project, rather than convert to and from the different encodings (this may be unavoidable, however, depending on the requirements of any third-party libraries you're using).

[Website] [+++ Divide By Cucumber Error. Please Reinstall Universe And Reboot +++]

A lot of persons do not seem to be able to build the code accompanying Vaughan Young's book "Programming a multiplayer FPS in Directx" due to a combination of obsolete/deprecated code and libraries, and a Visual Studio 6 project to start from. Although, it is in my opinion better to make the code buildable by yourself starting from an empty Visual Studio solution since it is essential for understanding what you are actually doing and otherwise you will never learn it, I created a repository with a Visual Studio 2015 solution file containing both the Engine and Game projects.

🧙

Please don't revive such old threads, thanks.

This topic is closed to new replies.

Advertisement