CCDDE.CPP 22 KB

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