Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version
Go to top

MaChat - a chat with a browser for LANs

, 30 Jul 2002
This article shows how to create a Chat for Local Area Networks which uses the WebBrowser control to display the messages.
lsetup.zip
lSetup.msi
machatproject.zip
MaChatproject
Chat.suo
ChatLibrary
map
snChatLibrary.snk
MaChat
bin
Debug
AxSHDocVw.dll
data
html
line.jpg
smiley
rose.gif
smiley_biggrin.gif
smiley_confused.gif
smiley_cool.gif
smiley_cry.gif
smiley_dead.gif
smiley_eek.gif
smiley_frown.gif
smiley_laugh.gif
smiley_line.gif
smiley_mad.gif
smiley_OMG.gif
smiley_redface.gif
smiley_rolleyes.gif
smiley_smile.gif
smiley_snore.gif
smiley_squeamish.gif
smiley_suss.gif
smiley_tongue.gif
smiley_wink.gif
smiley_WTF.gif
icons
away.ico
brb.ico
browser.ico
dnd.ico
local.ico
offline.ico
private.ico
public.ico
remote.ico
user.ico
pl
SHDocVw.dll
temp
Release
AxSHDocVw.dll
data
html
line.jpg
smiley
rose.gif
smiley_biggrin.gif
smiley_confused.gif
smiley_cool.gif
smiley_cry.gif
smiley_dead.gif
smiley_eek.gif
smiley_frown.gif
smiley_laugh.gif
smiley_line.gif
smiley_mad.gif
smiley_OMG.gif
smiley_redface.gif
smiley_rolleyes.gif
smiley_smile.gif
smiley_snore.gif
smiley_squeamish.gif
smiley_suss.gif
smiley_tongue.gif
smiley_wink.gif
smiley_WTF.gif
icons
away.ico
brb.ico
browser.ico
dnd.ico
local.ico
offline.ico
private.ico
public.ico
remote.ico
user.ico
pl
SHDocVw.dll
temp
obj
Release
Resources
chat.ico
Images.resources
MagicLibrary
bin
Debug
Release
Collections
Common
Controls
InertButton.bmp
TabControl.bmp
Docking
MagicLibrary.csproj.user
Menus
MenuControl.bmp
obj
Debug
MagicLibrary.projdata
temp
TempPE
Release
MagicLibrary.projdata
temp
TempPE
Resources
ImagesCaptionIDE.bmp
ImagesCaptionPlain.bmp
ImagesMenuControl.bmp
ImagesPopupMenu.bmp
ImagesTabControl.bmp
LibraryIcon.ico
Win32
Resources
bin
obj
Setup
Setup.vdproj
Setup
ssetup.zip
sSetup.msi
////////////////////////////////////////////////////
// File            - ChatLibrary.cpp
// Autor           - Michael Mac
// Contact         - GreenSequoia@wp.pl
// Description     - Implementation of the Chat class.
////////////////////////////////////////////////////

#include "stdafx.h"
#include "ChatLibrary.h"

using namespace System::IO;

namespace ChatLibrary
{
	////////////////////////////////////////////////////
	// ChatLibrary::Chat
	////////////////////////////////////////////////////

	// Constructor
	Chat::Chat ()
	{
		// Create a protocol-layer class
		m_conCore = new Connection();

		// Create a serializer
#ifdef BINARY
		m_sSerializer = new BinaryFormatter();
#else
		m_sSerializer = new SoapFormatter();
#endif
				
		// Create Users and Channels classes
		m_arUsersInfo = new Collections::UserInfoCollection ();
		m_uLocalUser = new UserInfo();
		m_arChannels = new Collections::ChannelCollection ();
	}

	void Chat::Join( int nLocalPort, IPEndPoint* ipeMulticastGroup ) 
	{ 
		// Initialize connection and set several options
		m_conCore->Connect( nLocalPort, ipeMulticastGroup );
		m_conCore->Receive += new ConnectionEventHandler( this, MessageHandler );
		m_conCore->Terminator = (new System::Text::ASCIIEncoding())
			->GetBytes( "<close/>" );

		// Set LocalUser info
		LocalUser->EndPoint = m_conCore->LocalEndPoint;

		// Send Join message
		MessageHeader* msgJoin = new MessageHeader( MessageType::Join );
		msgJoin->Object = LocalUser;
		Send( msgJoin );
	}

	void Chat::Leave ()
	{
		// Send Leave message
		Send( new MessageHeader( MessageType::Leave ) );

		m_conCore->Close();
	}

	void Chat::Refresh ()
	{
		UsersInfo->Clear();
		
		// Prepare data to send refresh message
		MessageHeader* msgRefresh = new MessageHeader( MessageType::Refresh );
		msgRefresh->Object = LocalUser;

		// Send to the MulticastGroup
		Send( msgRefresh );
	}

	void Chat::SendLocalUserInfo ()
	{
		// Prepare data to send UserInfo message
		MessageHeader* msgUserInfo = new MessageHeader( MessageType::UserInfo );
		msgUserInfo->Object = LocalUser;

		// Send to the MulticastGroup
		Send( msgUserInfo );
	}
	
	// Private functions
	////////////////////////////////////////////////////

	void Chat::MessageHandler ( Object* sender, ConnectionEventArgs* e )
	{
		MessageHeader* msgMessage = DeserializeMessage( e->get_Message() );
		MessageHeader* msgResponse;

		bool m_bLocalMsg = msgMessage->get_Sender()->Equals( get_LocalUser()->get_EndPoint() );

		if ( !msgMessage->get_Channel() )
		{
			// Main message system
			switch ( msgMessage->get_Type() )
			{
			case MessageType::Join:
				if ( !m_bLocalMsg )
				{
					UsersInfo->Update( static_cast<ChatLibrary::UserInfo*>( msgMessage->Object ) );
						
					// Send a response
					msgResponse = new MessageHeader( MessageType::UserInfo );
					msgResponse->Object = LocalUser;
					Send( msgResponse, msgMessage->Sender );
				}

				// Raise Join event
				if ( UserJoinMsg )
					UserJoinMsg->Invoke( this, new MessageEventArgs( msgMessage ) );

				break;

			case MessageType::Refresh:
				if ( !m_bLocalMsg )
				{
					UsersInfo->Update( static_cast<ChatLibrary::UserInfo*>( msgMessage->get_Object() ) );
					
					// Send a response
					msgResponse = new MessageHeader( MessageType::UserInfo );
					msgResponse->Object = LocalUser;
					Send( msgResponse, msgMessage->Sender );
				}

				break;

			case MessageType::UserInfo:
				if ( !m_bLocalMsg )
					UsersInfo->Update( static_cast<ChatLibrary::UserInfo*>( msgMessage->get_Object() ) );

				// Fire an event
				if ( UserUpdateMsg )
					UserUpdateMsg->Invoke( this, new MessageEventArgs( msgMessage ) );

				break;

			case MessageType::Leave:
				if ( !m_bLocalMsg )
					UsersInfo->Remove( static_cast<ChatLibrary::UserInfo*>( UsersInfo->UserInfoFromEndPoint( msgMessage->Sender ) ) );
				
				// Raise Leave event
				if ( UserLeaveMsg )
					UserLeaveMsg->Invoke( this, new MessageEventArgs( msgMessage ) );

				break;
			case MessageType::Invite:
				if ( InviteMsg )
					InviteMsg->Invoke( this, new MessageEventArgs( msgMessage ) );

				break;

			case MessageType::Note:
				if ( NoteMsg )
					NoteMsg->Invoke( this, new MessageEventArgs( msgMessage ) );

				break;
				
			case MessageType::Unknown:
				if ( UnknownMsg )
					UnknownMsg->Invoke( this, new MessageEventArgs( msgMessage ) );

				break;

			default:
				if ( NotHandledMsg )
					NotHandledMsg->Invoke( this, new MessageEventArgs( msgMessage ) );

				break;
			}
		}
		else
		{
			// Channel message system
			Channel* channel = Channels->ChannelFromName( msgMessage->Channel );
			if ( channel )	
				channel->MessageHandler( this, msgMessage );
		}
	}

	// Serialize a message to a stream
	Byte Chat::SerializeMessage( MessageHeader* msgMessage )[]
	{
		// Create a stream where the serialized MessageHeader class will be placed
		MemoryStream* sStream = new MemoryStream();
		
		// Serialize the message
		m_sSerializer->Serialize( sStream, msgMessage );
		
		// Convert to byte array
		Byte arMessage[] = sStream->ToArray();
#ifdef _DEBUG
		Trace::Write ( "Message length: " );
		Trace::WriteLine ( arMessage->get_Length().ToString() );
#endif
		return arMessage;
	}
	// Deserialize a message from a stream
	MessageHeader* Chat::DeserializeMessage( Byte byteMessage[] )
	{
		// Create memory stream	
		MemoryStream* sStream =  new MemoryStream( byteMessage );

		// Deserialize
		MessageHeader* msgMessage = dynamic_cast<MessageHeader*>
			( m_sSerializer->Deserialize( sStream ) );
#ifdef _DEBUG
		String* strMessage = (new System::Text::ASCIIEncoding())
			->GetString( sStream->ToArray() );

		Trace::Write ( "Message length: " );
		Trace::WriteLine ( strMessage->get_Length().ToString() );
#endif
		return msgMessage;
	}

	// Send a message to the specific IPEndPoint
	void Chat::Send ( MessageHeader* msgMessage, IPEndPoint* ipeRemoteHost ) 
	{
		msgMessage->set_Sender( m_conCore->get_LocalEndPoint() );
		// Serialize
		Byte byteMessage[] = SerializeMessage( msgMessage );

		// Send
		m_conCore->Send( byteMessage, ipeRemoteHost );
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Michael Mac
Architect macmichal.pl
Poland Poland
Micheal is an independent consultant - www.macmichal.pl.
He's main areas of interest are: DDD\CqRS, TDD, SaaS, Design Patterns, Architecture. He specializes in .Net/C# for the early beginning of it and T-SQL. He's a writer, blogger (blog.macmichal.pl) and speaker.
 
In his spare time, he's climbing the mountains all over the Europe.

| Advertise | Privacy | Mobile
Web03 | 2.8.140916.1 | Last Updated 31 Jul 2002
Article Copyright 2002 by Michael Mac
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid