CCDDE.CPP 22 KB

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