🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

creating an invis window

Started by
12 comments, last by kalldrex 23 years, 4 months ago
heh i''m a little slow but creating an invis window just make my console server program actully work! can someone give me the commands for doing so?
ALL YOUR BASE ARE BELONG TO US!!!!
Advertisement
Are you sure this is what you want to do? Your going to be creating your server as a console right? You don't have to create an invisible window to receive Winsock messages....

Event objects are the way to go. (all examples given, use TCP)
also, keep in mind that this is meant to be a tutorial and I use MessageBoxes to display errors - you would want to handle the errors in a more appropriate manner...

Here's how to create the listening socket - really not any different than creating any listening socket except you associate this socket with a few network events... See the third and fourth comment in this code below.
    bool TCPServer::StartListenSocket(unsigned short port){DWORD			dwAddrStrLen;char			szBuf[256];		char			szAddress[128];int nRet;	//	// Initialize WinSock	//	nRet = WSAStartup(m_wVersionRequested, &m_wsaData);	if (nRet)	{		MessageBox(NULL, 				   "Initialize WinSock Failed",				   "SERVICE", 				   MB_OK);		return 0;	}	// Check version	if (m_wsaData.wVersion != m_wVersionRequested)	{       		MessageBox(NULL, 				   "Wrong WinSock Version",				   "SERVICE", 				   MB_OK);		return 0;	}	m_listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);	if (m_listenSocket == INVALID_SOCKET)	{		MessageBox(NULL, "Could not create listen socket", "SERVICE",MB_OK);		return FALSE;	}		// Create an event object to be used with this socket	//	m_hEvent = WSACreateEvent();	if (m_hEvent == WSA_INVALID_EVENT)	{		MessageBox(NULL, "WSACreateEvent()", "SERVICE",MB_OK);		closesocket(m_listenSocket);		return 0;	}	//	// Make the socket non-blocking and 	// associate it with network events	//	nRet = WSAEventSelect(m_listenSocket, m_hEvent, FD_ACCEPT|FD_READ|FD_WRITE|FD_CLOSE);	if (nRet == SOCKET_ERROR)	{		MessageBox(NULL, "EventSelect()", "SERVICE",MB_OK);		closesocket(m_listenSocket);		WSACloseEvent(m_hEvent);		return 0;	}	m_saServer.sin_port		 = htons(port);	m_saServer.sin_family		 = AF_INET;	m_saServer.sin_addr.s_addr = INADDR_ANY;		nRet = bind(m_listenSocket,(LPSOCKADDR)&m_saServer, sizeof(struct sockaddr));	if (nRet == SOCKET_ERROR)	{		MessageBox(NULL, "bind() error","SERVICE",MB_OK);		closesocket(m_listenSocket);		return false;	}	//	// Set the socket to listen	//	nRet = listen(m_listenSocket, SOMAXCONN);	if (nRet == SOCKET_ERROR)	{		MessageBox(NULL, "listen() error","SERVICE",MB_OK);		closesocket(m_listenSocket);		return false;	}	return 1;}  


Here is the main loop of the server... minus lots of stuff like ticks/timers etc... but you get the ideal.

   	...       	if(tcp.StartListenSocket(8586))	{		while(tcp.m_shutdown == 0)		{			// Inside this function - we loop through each connection 			// to determine if they have sent us a message.			// I have stripped much of the command parser out which can			// be found in the TCPServer class under ClientConversation()			// That function will probably have to be modified or another			// method devised to deal with each clients request/response.			tcp.HandleEvents(); 		}		tcp.StopListenSocket();	}	...  


now for the good stuff... How do I use event objects?

        void TCPServer::HandleEvents(){int		nRet;	DWORD state = WaitForSingleObject(m_hEvent,1);	if(state == 0)	{		fprintf(stdout, "m_hEvent state = %ld\n",state);		nRet = WSAEnumNetworkEvents(m_listenSocket, m_hEvent, &m_events);		if (nRet == SOCKET_ERROR)				fprintf(stderr,"WSAEnumNetworkEvents() SOCKET ERROR %d",nRet);		else			NegotiateClients();		ResetEvent(m_hEvent);	}	if(m_activeconnections >0)	{		CGameAccount* connection = m_cons->GetFirstConnection();		while(connection != NULL)		{			m_remoteSocket = connection->GetDescriptor();			nRet = WSAEnumNetworkEvents(m_remoteSocket, m_hEvent1, &m_events1);			if (nRet == SOCKET_ERROR)			{				fprintf(stderr,"WSAEnumNetworkEvents() SOCKET ERROR %d on socket %d\n",nRet,m_remoteSocket);				continue;			}			if(m_events1.lNetworkEvents > 0)			{				ClientConversation();					ResetEvent(m_hEvent1);			}			connection = m_cons->GetNextConnection();		}	}}  


I probably should break this up -- this is getting long. Stay tuned.

(EDIT: removed a few long lines...)

Edited by - Dak Lozar on February 8, 2001 1:38:50 PM
Dave Dak Lozar Loeser
"Software Engineering is a race between the programmers, trying to make bigger and better fool-proof software, and the universe trying to make bigger fools. So far the Universe in winning."--anonymous
Ok, where did I leave off?
TCPServer::HandleEvents()
This funcion is called from the servers main loop and inside there is alot going on... and most of the good stuff is handled in one line of code:
    DWORD state = WaitForSingleObject(m_hEvent,1);  This bit waits for one millisecond to see if any of the events that we are looking for on the listening socket have occured.IF one of the events (FD_ACCEPT|FD_READ|FD_WRITE|FD_CLOSE) that we have assigned to this socket have occured we make a call to NegotiateClients();   -NOTE- I just realized that I was looking for write and read events on this listener, probably don't need these... this is from some really old code - I chose this because one it's easy to read (tell me if it's not) and two, my new implementations of UDP and TCP socket code are wrapped in threads and mutexes... it gets pretty difficult to figure out what is going on.-END-NOTE-[/CODE]The next bit of code checks to see if there are active connections and if so We iterate through the list of connections checking to see if they have sent our server any messages... This looks really goofy to me now, but it works and it should be easy for you to understand. The important part of this code, for you to understand is that in a console application we don't have the luxury of the Windows GUI - and it's event driven architecture.... so, we have to use the kernal supplied event objects to pump our server.This line of code:if(m_events1.lNetworkEvents > 0)   handles that pump. If the m_events1.lNetworkEvents is larger than 0 we had a message from this socket and we need to handle it.... We do this by calling a member function ClientConversation();  Here the implementation:       void TCPServer::ClientConversation(){int		nRet;char	szBuffer[4096];GString tempBuf;char	szSeps[] = " \r\n";COMMAND_DATA* command_info;int index;	//fprintf(stderr,"+");		// FD_CLOSE	if (m_events1.lNetworkEvents & FD_CLOSE)	{		fprintf(stderr,"\nFD_CLOSE: %d",m_events1.iErrorCode[FD_CLOSE_BIT]);		closesocket(m_remoteSocket);		m_cons->RemoveConnection(m_remoteSocket);		m_activeconnections--;		}	// FD_CLOSE	if (m_events1.lNetworkEvents & FD_WRITE)	{		fprintf(stderr,"\nFD_WRITE: %d",m_events1.iErrorCode[FD_WRITE_BIT]);	}	// FD_READ	if (m_events1.lNetworkEvents & FD_READ)	{		fprintf(stderr,"\nFD_READ: %d", m_events1.iErrorCode[FD_READ_BIT]);		// Read the data and write it to stdout		nRet = recv(m_remoteSocket, szBuffer, sizeof(szBuffer), 0);		if (nRet == SOCKET_ERROR)		{			m_ErrorMessage = "SOCKET ERROR recv()";		}		szBuffer[nRet] = '\0';		tempBuf = szBuffer;		index = tempBuf.Find("\r\n", true);		if (index == -1)			index = tempBuf.Find("\n\r", true);		if (index != -1)		{			tempBuf = tempBuf.Left(index);		}...  Ok, why did I not finish the code? Well, this part is up to you. What we did here was to create a list of pointers to functions and using a binary search found the pointer to the function to handle the command for this message.... YUCK so, I didn't want to show you all that  Oh yea, heres the NegotiateClients();   member function:      void TCPServer::NegotiateClients(){	int	nRet;	// FD_ACCEPT	if (m_events.lNetworkEvents & FD_ACCEPT)	{		SOCKADDR_IN SockAddr;		int nLen = sizeof(SockAddr);		// HERE WE WILL ACCEPT THE CONNECTION		m_remoteSocket = accept(m_listenSocket, (LPSOCKADDR)&SockAddr,&nLen);		if (m_remoteSocket == INVALID_SOCKET)		{			m_ErrorMessage = "Error: accept()";			closesocket(m_remoteSocket); //closesocket(m_listenSocket);		}		GString add = inet_ntoa(SockAddr.sin_addr);		nRet = send(m_remoteSocket, "Welcome to xxxxxxx xxxxxxxxxxx Chat Server.\r\n Use commandlist for a list of commands available to you.\r\n", 104, 0);			// CREATE AN EVENT OBJECT TO BE USED WITH THIS SOCKET		m_hEvent1 = WSACreateEvent();		if (m_hEvent1 == WSA_INVALID_EVENT)		{			m_ErrorMessage = "Error: WSACreateEvent(m_hEvent1)";			closesocket(m_remoteSocket);		}				// MAKE THE SOCKET NON-BLOCKING AND 		// ASSOCIATE IT WITH NETWORK EVENTS		nRet = WSAEventSelect(m_remoteSocket, m_hEvent1, FD_READ|FD_WRITE|FD_CLOSE);		if (nRet == SOCKET_ERROR)		{			m_ErrorMessage = "Error: WSACreateEvent(m_hEvent1)";			closesocket(m_remoteSocket);			WSACloseEvent(m_hEvent1);		}		m_cons->AddConnection(m_remoteSocket, SockAddr);		m_activeconnections++;	}	nRet = WSAEventSelect(m_listenSocket, m_hEvent, FD_ACCEPT|FD_READ|FD_WRITE|FD_CLOSE);	if (nRet == SOCKET_ERROR)	{		m_ErrorMessage = "EventSelect()";		closesocket(m_listenSocket);		WSACloseEvent(m_hEvent);	}}    


HTH, and if you have any questions just drop me a line...

Game On,

Dave "Dak Lozar" Loeser

Edited by - Dak Lozar on February 8, 2001 2:04:43 PM
Dave Dak Lozar Loeser
"Software Engineering is a race between the programmers, trying to make bigger and better fool-proof software, and the universe trying to make bigger fools. So far the Universe in winning."--anonymous
First of all yes i need to create an invis window probably because i''m using win2k and it doesn''t like dos-mode console programs using winsock. Also i''m programming my game in UDP!
ALL YOUR BASE ARE BELONG TO US!!!!
Kalldrex, what do you mean when you say win2k doesn''t like console apps using winsock?

And Dak has it right, event objects are normally the cleanest way to handle this stuff in a console app. it''s easier than creating a message handler w/ invis window...

But if you need an invis window, there''s no rule that says you have to SHOW a window. As soon as you create it, you have a valid HWND and the message handler is registered.
I tried just the first part of that guy''s code, I just put this in my program

LPWSADATA m_wsaData;
int nRet = WSAStartup(0, m_wsaData);

And I included
It compiles fine, but when it tries to link it all up I get this:
error LNK2001: unresolved external symbol __imp__WSAStartup@8
Is there some kind of .lib file I should be having my program look for or something?
I am using win 2000 and vc++ 6.
Whenever you run a program in dos emulation (ms-dos prompt) and the program uses winsock it freezes when you try to run it.
ALL YOUR BASE ARE BELONG TO US!!!!
quote: Original post by devouree

I tried just the first part of that guy''s code, I just put this in my program

LPWSADATA m_wsaData;
int nRet = WSAStartup(0, m_wsaData);

And I included
It compiles fine, but when it tries to link it all up I get this:
error LNK2001: unresolved external symbol __imp__WSAStartup@8
Is there some kind of .lib file I should be having my program look for or something?
I am using win 2000 and vc++ 6.


Hi, I''m the guy - You need to add the WSOCK32.LIB if your using winsck WS2_32.LIB if your using winsock2.

Game On,

Dave "Dak Lozar" Loeser
Dave Dak Lozar Loeser
"Software Engineering is a race between the programmers, trying to make bigger and better fool-proof software, and the universe trying to make bigger fools. So far the Universe in winning."--anonymous
quote: Original post by kalldrex

Whenever you run a program in dos emulation (ms-dos prompt) and the program uses winsock it freezes when you try to run it.


I''m not sure what your doing but, I''m testing a server as we speak that is running on Win2k Professional. No freezes or otherwise...

I''m not totally sure that you understood what I was talking about before, and I know your using UDP - makes no diff - event objects work the same for UDP as they do for TCP.

Good luck on your server


Game On,

Dave "Dak Lozar" Loeser
Dave Dak Lozar Loeser
"Software Engineering is a race between the programmers, trying to make bigger and better fool-proof software, and the universe trying to make bigger fools. So far the Universe in winning."--anonymous
There seems to be some confusion about console apps. They are NOT DOS-based. They are NOT 16bit. They are 32bit Win32 apps that happen to be in text mode. I don''t see why Win2k would have trouble with this.


My Geekcode: "GCS d s: a14 C++$ P+(++) L+ E-- W+++$ K- w++(+++) O---- M-- Y-- PGP- t X
R- tv+ b++ DI+(+++) D- G e* h!"
Decode my geekcode!
Geekcode.com


Visit our web site:
Asylum Entertainment
My Geekcode: "GCS d s: a14 C++$ P+(++) L+ E-- W+++$ K- w++(+++) O---- M-- Y-- PGP- t XR- tv+ b++ DI+(+++) D- G e* h!"Decode my geekcode!Geekcode.com
Visit our web site:Asylum Entertainment

This topic is closed to new replies.

Advertisement