Jump to content
  • Advertisement
Sign in to follow this  
Munro

Character set problems

This topic is 756 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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.cpp
1>c:\documents and settings\riley\desktop\chapter 13\game\gamematerial.cpp(14) : error C2512: 'Material' : no appropriate default constructor available
1>Menu.cpp
1>c:\documents and settings\riley\desktop\chapter 13\game\menu.cpp(36) : warning C4996: 'wcstombs' was declared deprecated
1> 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 cast
1>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 cast
1>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 cast
1>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 cast
1>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 cast
1>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 cast
1>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 cast
1>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 );

Share this post


Link to post
Share on other sites
Advertisement
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.

Share this post


Link to post
Share on other sites
Thanks for the help but I'm still quite new to this, how would I apply that fix to the code above?

Share this post


Link to post
Share on other sites
For simplicity, try replacing


static char name[MAX_PATH] = "Unknown Player";
//with
static 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.

Share this post


Link to post
Share on other sites
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 *'

Share this post


Link to post
Share on other sites
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 function
char* convertedString;
wcstombs(convertedString, name, name.length());
//existing line example
strcpy(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 :)

Share this post


Link to post
Share on other sites
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).

Share this post


Link to post
Share on other sites

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.

Edited by matt77hias

Share this post


Link to post
Share on other sites

This topic is 756 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Guest
This topic is now closed to further replies.
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!