CCDDE.CPP (22996B)
1 // 2 // Copyright 2020 Electronic Arts Inc. 3 // 4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 5 // software: you can redistribute it and/or modify it under the terms of 6 // the GNU General Public License as published by the Free Software Foundation, 7 // either version 3 of the License, or (at your option) any later version. 8 9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 10 // in the hope that it will be useful, but with permitted additional restrictions 11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 12 // distributed with this program. You should have received a copy of the 13 // GNU General Public License along with permitted additional restrictions 14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection 15 16 17 /*********************************************************************************************** 18 *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** 19 *********************************************************************************************** 20 * * 21 * Project Name : Command & Conquer - Red Alert * 22 * * 23 * File Name : CCDDE.CPP * 24 * * 25 * Programmer : Steve Tall * 26 * * 27 * Start Date : 10/04/95 * 28 * * 29 * Last Update : August 5th, 1996 [ST] * 30 * * 31 *---------------------------------------------------------------------------------------------* 32 * Overview: * 33 * C&C's interface to the DDE class * 34 * * 35 *---------------------------------------------------------------------------------------------* 36 * * 37 * Functions: * 38 * DDE_Callback -- DDE server callback function * 39 * DDEServerClass::DDEServerClass -- class constructor * 40 * DDEServerClass::Enable -- Enables the DDE callback * 41 * DDEServerClass::Disable -- Disables the DDE callback * 42 * DDEServerClass::~DDEServerClass -- class destructor * 43 * DDESC::Callback -- callback function. Called from the DDE_Callback wrapper function * 44 * DDESC::Get_MPlayer_Game_Info -- returns a pointer to the multiplayer setup info from wchat * 45 * DDESC::Delete_MPlayer_Game_Info -- clears out multi player game setup info * 46 * DDESC::Time_Since_Heartbeat -- returns the time in ticks since the last heartbeat from wchat* 47 * * 48 * Send_Data_To_DDE_Server -- sends a packet to WChat * 49 * * 50 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 51 52 #ifdef WIN32 53 54 #include <WINDOWS.H> 55 #include "ccdde.h" 56 #include <stdio.h> 57 #include <timer.h> 58 59 DDEServerClass DDEServer; //Instance of the DDE Server class 60 61 Instance_Class *DDE_Class = NULL; // pointer for client callback 62 // this *must* be called DDE_Class 63 64 BOOL RA95AlreadyRunning = FALSE; //Was there an instance of Red Alert 95 already running when we started? 65 66 /* 67 ** Misc externs so we dont have to include FUNCTION.H 68 */ 69 extern HWND MainWindow; 70 extern TimerClass GameTimer; 71 extern bool GameTimerInUse; 72 extern void WWDebugString (char *string); 73 74 75 /*********************************************************************************************** 76 * DDE_Callback -- DDE server callback function * 77 * * 78 * Just acts as a wrapper for the DDEServerClass callback function * 79 * * 80 * INPUT: ptr to data from client * 81 * length of data * 82 * * 83 * OUTPUT: Nothing * 84 * * 85 * WARNINGS: None * 86 * * 87 * HISTORY: * 88 * 6/8/96 3:19PM ST : Created * 89 *=============================================================================================*/ 90 BOOL CALLBACK DDE_Callback (unsigned char *data, long length) 91 { 92 return (DDEServer.Callback(data, length)); 93 } 94 95 96 97 98 /*********************************************************************************************** 99 * DDEServerClass::DDEServerClass -- class constructor * 100 * * 101 * * 102 * * 103 * INPUT: Nothing * 104 * * 105 * OUTPUT: Nothing * 106 * * 107 * WARNINGS: None * 108 * * 109 * HISTORY: * 110 * 6/8/96 3:20PM ST : Created * 111 *=============================================================================================*/ 112 DDEServerClass::DDEServerClass(void) 113 { 114 MPlayerGameInfo = NULL; //Flag that we havnt received a start game info packet yet 115 116 //DDE_Class = new Instance_Class ("CONQUER", "WCHAT"); 117 DDE_Class = new Instance_Class ("REDALERT", "WCHAT"); 118 119 DDE_Class->Enable_Callback( TRUE ); 120 IsEnabled = TRUE; 121 122 if (DDE_Class->Test_Server_Running(DDE_Class->local_name)){ 123 RA95AlreadyRunning = TRUE; 124 }else{ 125 //DDE_Class->Register_Server( DDE_Callback ); // ST - 5/8/2019 126 } 127 } 128 129 130 131 /*********************************************************************************************** 132 * DDEServerClass::Enable -- Enables the DDE callback * 133 * * 134 * * 135 * * 136 * INPUT: Nothing * 137 * * 138 * OUTPUT: Nothing * 139 * * 140 * WARNINGS: None * 141 * * 142 * HISTORY: * 143 * 8/5/96 9:44PM ST : Created * 144 *=============================================================================================*/ 145 void DDEServerClass::Enable(void) 146 { 147 if (!IsEnabled){ 148 DDE_Class->Enable_Callback( TRUE ); 149 IsEnabled = TRUE; 150 } 151 } 152 153 154 155 /*********************************************************************************************** 156 * DDEServerClass::Disable -- Disables the DDE callback * 157 * * 158 * * 159 * * 160 * INPUT: Nothing * 161 * * 162 * OUTPUT: Nothing * 163 * * 164 * WARNINGS: None * 165 * * 166 * HISTORY: * 167 * 8/5/96 9:44PM ST : Created * 168 *=============================================================================================*/ 169 void DDEServerClass::Disable(void) 170 { 171 if (IsEnabled){ 172 DDE_Class->Enable_Callback( FALSE ); 173 IsEnabled = FALSE; 174 } 175 } 176 177 178 179 180 181 182 /*********************************************************************************************** 183 * DDEServerClass::~DDEServerClass -- class destructor * 184 * * 185 * * 186 * * 187 * INPUT: Nothing * 188 * * 189 * OUTPUT: Nothing * 190 * * 191 * WARNINGS: None * 192 * * 193 * HISTORY: * 194 * 6/8/96 3:20PM ST : Created * 195 *=============================================================================================*/ 196 DDEServerClass::~DDEServerClass(void) 197 { 198 Delete_MPlayer_Game_Info(); 199 delete( DDE_Class ); 200 } 201 202 203 204 /*********************************************************************************************** 205 * DDESC::Callback -- callback function. Called from the DDE_Callback wrapper function * 206 * * 207 * * 208 * * 209 * INPUT: data from DDE client * 210 * length of data * 211 * * 212 * OUTPUT: Nothing * 213 * * 214 * WARNINGS: Data has length and type as first 2 ints * 215 * * 216 * HISTORY: * 217 * 6/8/96 3:21PM ST : Created * 218 *=============================================================================================*/ 219 BOOL DDEServerClass::Callback(unsigned char *data, long length) 220 { 221 222 /* 223 ** If the packet length < 0 then this is a special advisory packet 224 */ 225 if ( length<0 ) { 226 227 switch( length ) { 228 229 case DDE_ADVISE_CONNECT: 230 WWDebugString("RA95 - DDE advisory: client connect detected."); 231 return TRUE; 232 233 case DDE_ADVISE_DISCONNECT: 234 WWDebugString("RA95 - DDE advisory: client disconnect detected."); 235 return TRUE; 236 237 default: 238 WWDebugString("RA95 - DDE advisory: Unknown DDE advise type."); 239 return FALSE; 240 } 241 242 }else{ 243 244 /* 245 ** Packet must be at least the length of the packet type & size fields to be valid 246 */ 247 if (length < 2*sizeof(int)) { 248 WWDebugString ("RA95 - Received invalid packet."); 249 return (FALSE); 250 } 251 252 /* 253 ** Find out what kind of packet this is and its length. 254 */ 255 int *packet_pointer = (int *)data; 256 int actual_length = ntohl(*packet_pointer++); 257 int packet_type = ntohl(*packet_pointer++); 258 259 /* 260 ** Strip the ID int from the start of the packet 261 */ 262 data += 2*sizeof (int); 263 length -= 2*sizeof (int); 264 actual_length -= 2*sizeof (int); 265 266 /* 267 ** Take the appropriate action for the packet type 268 */ 269 switch ( packet_type ){ 270 271 /* 272 ** This is a packet with the info required for starting a new internet game. This is really 273 * just C&CSPAWN.INI sent from WChat instead of read from disk. 274 */ 275 case DDE_PACKET_START_MPLAYER_GAME: 276 WWDebugString("RA95 - Received start game packet."); 277 Delete_MPlayer_Game_Info(); 278 MPlayerGameInfo = new char [actual_length + 1]; 279 memcpy (MPlayerGameInfo, data, actual_length); 280 *(MPlayerGameInfo + actual_length) = 0; //Terminator in case we treat it as a string 281 MPlayerGameInfoLength = actual_length; 282 LastHeartbeat = 0; 283 break; 284 285 case DDE_TICKLE: 286 WWDebugString("RA95 - Received 'tickle' packet."); 287 //SetForegroundWindow ( MainWindow ); 288 //ShowWindow ( MainWindow, SW_SHOWMAXIMIZED ); 289 break; 290 291 case DDE_PACKET_HEART_BEAT: 292 WWDebugString("RA95 - Received heart beat packet."); 293 if (GameTimerInUse){ 294 LastHeartbeat = GameTimer.Time(); 295 }else{ 296 LastHeartbeat = 0; 297 } 298 break; 299 300 default: 301 WWDebugString("RA95 - Received unrecognised packet."); 302 break; 303 304 } 305 } 306 307 return (TRUE); 308 309 } 310 311 312 313 /*********************************************************************************************** 314 * DDESC::Get_MPlayer_Game_Info -- returns a pointer to the multiplayer setup info from wchat * 315 * * 316 * * 317 * * 318 * INPUT: Nothing * 319 * * 320 * OUTPUT: ptr to data in .INI file format * 321 * * 322 * WARNINGS: None * 323 * * 324 * HISTORY: * 325 * 6/8/96 3:23PM ST : Created * 326 *=============================================================================================*/ 327 char *DDEServerClass::Get_MPlayer_Game_Info (void) 328 { 329 return (MPlayerGameInfo); 330 } 331 332 333 334 /*********************************************************************************************** 335 * DDESC::Delete_MPlayer_Game_Info -- clears out multi player game setup info * 336 * * 337 * * 338 * * 339 * INPUT: Nothing * 340 * * 341 * OUTPUT: Nothing * 342 * * 343 * WARNINGS: None * 344 * * 345 * HISTORY: * 346 * 6/8/96 3:24PM ST : Created * 347 *=============================================================================================*/ 348 void DDEServerClass::Delete_MPlayer_Game_Info(void) 349 { 350 if (MPlayerGameInfo){ 351 delete [] MPlayerGameInfo; 352 MPlayerGameInfo = NULL; 353 } 354 } 355 356 357 358 /*********************************************************************************************** 359 * DDESC::Time_Since_Heartbeat -- returns the time in ticks since the last heartbeat from wchat* 360 * * 361 * * 362 * * 363 * INPUT: Nothing * 364 * * 365 * OUTPUT: time since heartbeat * 366 * * 367 * WARNINGS: None * 368 * * 369 * HISTORY: * 370 * 6/9/96 11:05PM ST : Created * 371 *=============================================================================================*/ 372 int DDEServerClass::Time_Since_Heartbeat(void) 373 { 374 return (GameTimer.Time() - LastHeartbeat); 375 } 376 377 378 379 380 /*********************************************************************************************** 381 * Send_Data_To_DDE_Server -- sends a packet to WChat * 382 * * 383 * * 384 * * 385 * INPUT: ptr to the data to send * 386 * length of data * 387 * packet type identifier * 388 * * 389 * OUTPUT: true if packet successfully sent * 390 * * 391 * WARNINGS: None * 392 * * 393 * HISTORY: * 394 * 6/9/96 11:07PM ST : Created * 395 *=============================================================================================*/ 396 BOOL Send_Data_To_DDE_Server (char *data, int length, int packet_type) 397 { 398 if( DDE_Class->Open_Poke_Connection(DDE_Class->remote_name) == FALSE) { 399 WWDebugString("RA95 - Failed to connect for POKE!"); 400 return (FALSE); 401 } 402 403 char *poke_data = new char [length + 2*sizeof(int)]; 404 405 int *poke_data_int = (int*)poke_data; 406 407 *poke_data_int = htonl (length + 2*sizeof(int)); 408 *(poke_data_int+1)= htonl (packet_type); 409 410 memcpy (poke_data + 8, data, length); 411 412 413 if(DDE_Class->Poke_Server( (LPBYTE) poke_data, ntohl(*poke_data_int) ) == FALSE) { 414 WWDebugString("RA95 - POKE failed!\n"); 415 DDE_Class->Close_Poke_Connection(); // close down the link 416 delete poke_data; 417 return (FALSE); 418 } 419 420 DDE_Class->Close_Poke_Connection(); // close down the link 421 422 delete poke_data; 423 424 return (TRUE); 425 } 426 427 428 #endif //WIN32