DDE.CPP 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  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 : Dynamic Data Encapsulation *
  19. * *
  20. * File Name : DDE.CPP *
  21. * *
  22. * Programmer : Steve Wetherill *
  23. * *
  24. * Start Date : June 1, 1996 *
  25. * *
  26. * Last Update : June 8, 1996 [SW] *
  27. * *
  28. *-------------------------------------------------------------------------*
  29. * Functions: *
  30. * Instance_Class::InstanceClass -- class constructor *
  31. * Instance_Class::InstanceClass -- class destructor *
  32. * Instance_Class::Enable_Callback -- enables local processing of pokes *
  33. * Instance_Class::Register_Servers -- registers a local DDE DNS service *
  34. * Instance_Class::Cleanup_App -- currently does nothing *
  35. * Instance_Class::Test_Server_Running -- does a trial connect to remote *
  36. * Instance_Class::Open_Poke_Connection -- pokes some data to server *
  37. * Instance_Class::Close_Poke_Connectionp -- closes connection to remote *
  38. * Instance_Class::Poke_Server -- sends a chunk of data to remote *
  39. * Instance_Class::dde_callback -- processes DDE transactions *
  40. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  41. #ifdef WIN32
  42. #include <windows.h>
  43. #include "dde.h"
  44. /***************************************************************************
  45. * These are static members of Instance_Class
  46. *=========================================================================*/
  47. DWORD Instance_Class::id_inst; // instance identifier set by DdeInitialize
  48. BOOL Instance_Class::process_pokes; // controls response to pokes
  49. char Instance_Class::ascii_name[32]; // name of server
  50. #if (0) //ST - 5/8/2019
  51. static BOOL CALLBACK (*Instance_Class::callback) (
  52. LPBYTE pointer, // pointer to received data
  53. long length // length of received data or advisory flag
  54. ) = NULL;
  55. #endif
  56. /***************************************************************************
  57. * Instance_Class::InstanceClass -- class constructor *
  58. * *
  59. * INPUT: *
  60. * name1 null terminated ASCII client name *
  61. * name1 null terminated ASCII server name *
  62. * *
  63. * OUTPUT: *
  64. * dde_error = TRUE if error occurs when initializing DDE *
  65. * *
  66. * WARNINGS: *
  67. * none. *
  68. * *
  69. * HISTORY: *
  70. * 6/1/1996 SW : Created. *
  71. *=========================================================================*/
  72. Instance_Class::Instance_Class( LPSTR name1, LPSTR name2 )
  73. {
  74. name1; name2;
  75. return;
  76. #if (0) //ST - 5/8/2019
  77. dde_error = FALSE; // no errors
  78. process_pokes = FALSE; // disable pokes in callback
  79. id_inst = 0; // set to 0 for first time through
  80. conv_handle = 0; // conversation handle reset
  81. lstrcpy( ascii_name, name1 ); // keep a record of ASCII name
  82. if ( DdeInitialize(
  83. (LPDWORD) &id_inst, // instance identifier
  84. dde_callback,
  85. APPCLASS_STANDARD | // filter server messages
  86. CBF_FAIL_SELFCONNECTIONS, // prevent from connecting with self
  87. 0) != DMLERR_NO_ERROR) { // reserved
  88. dde_error = TRUE; // flag an error
  89. }
  90. local_name = DdeCreateStringHandle(
  91. id_inst, // instance identifier
  92. name1, // string to register
  93. CP_WINANSI); // Windows ANSI code page
  94. remote_name = DdeCreateStringHandle(
  95. id_inst, // instance identifier
  96. name2, // string to register
  97. CP_WINANSI); // Windows ANSI code page
  98. poke_topic = DdeCreateStringHandle(
  99. id_inst, // instance identifier
  100. "POKE TOPIC", // System topic
  101. CP_WINANSI); // Windows ANSI code page
  102. poke_item = DdeCreateStringHandle(
  103. id_inst, // instance identifier
  104. "POKE ITEM", // System topic
  105. CP_WINANSI); // Windows ANSI code page
  106. system_topic = DdeCreateStringHandle(
  107. id_inst, // instance identifier
  108. SZDDESYS_TOPIC, // System topic
  109. CP_WINANSI); // Windows ANSI code page
  110. #endif
  111. }
  112. /***************************************************************************
  113. * Instance_Class::~Instance_Class -- class destructor *
  114. * *
  115. * INPUT: *
  116. * none. *
  117. * *
  118. * OUTPUT: *
  119. * none. *
  120. * *
  121. * WARNINGS: *
  122. * none. *
  123. * *
  124. * HISTORY: *
  125. * 6/1/1996 SW : Created. *
  126. *=========================================================================*/
  127. Instance_Class::~Instance_Class()
  128. {
  129. DdeUninitialize( id_inst );
  130. }
  131. /***************************************************************************
  132. * Instance_Class::Enable_Callback -- enables user callback *
  133. * *
  134. * INPUT: *
  135. * TRUE = enable poke processing *
  136. * FALSE = disable poke processing *
  137. * *
  138. * OUTPUT: *
  139. * echos the input *
  140. * *
  141. * WARNINGS: *
  142. * user callback must be explicitly enabled. Disbabled by default. *
  143. * *
  144. * HISTORY: *
  145. * 6/1/1996 SW : Created. *
  146. *=========================================================================*/
  147. BOOL Instance_Class::Enable_Callback( BOOL flag ) // enable or disable callback
  148. {
  149. return (process_pokes = flag);
  150. }
  151. /***************************************************************************
  152. * Instance_Class::Register_Server -- registers a local DDE DNS service *
  153. * *
  154. * INPUT: *
  155. * BOOL CALLBACK ( *callback_fnc) ( LPBYTE, DWORD) = user poke callbacl *
  156. * *
  157. * OUTPUT: *
  158. * TRUE == success *
  159. * FALSE == failed *
  160. * *
  161. * WARNINGS: *
  162. * none. *
  163. * *
  164. * HISTORY: *
  165. * 6/1/1996 SW : Created. *
  166. *=========================================================================*/
  167. #if (0) //ST - 5/8/2019
  168. BOOL Instance_Class::Register_Server( BOOL CALLBACK ( *callback_fnc) (LPBYTE, long) )
  169. {
  170. if (DdeNameService( id_inst, local_name, 0L, DNS_REGISTER ) != 0L) {
  171. callback = callback_fnc;
  172. return ( TRUE );
  173. } else {
  174. return ( FALSE );
  175. }
  176. }
  177. #endif
  178. /***************************************************************************
  179. * Instance_Class::Test_Server_Running -- does a trial connect to remote *
  180. * *
  181. * INPUT: *
  182. * name = HSZ string handle of server name. *
  183. * *
  184. * OUTPUT: *
  185. * TRUE == successfully connected to remote *
  186. * FALSE == failed to connect *
  187. * *
  188. * WARNINGS: *
  189. * - Can be called for local or remote server but of course will *
  190. * fail if a called for local and local server is not "up". *
  191. * - Disconects before exiting. *
  192. * *
  193. * HISTORY: *
  194. * 6/1/1996 SW : Created. *
  195. *=========================================================================*/
  196. BOOL Instance_Class::Test_Server_Running( HSZ name )
  197. {
  198. if( Open_Poke_Connection( name ) == TRUE) {
  199. Close_Poke_Connection();
  200. return( TRUE );
  201. } else {
  202. return( FALSE );
  203. }
  204. }
  205. /***************************************************************************
  206. * Instance_Class::Open_Poke_Connection -- open a connection to server *
  207. * *
  208. * INPUT: *
  209. * name = HSZ server name. *
  210. * *
  211. * OUTPUT: *
  212. * TRUE == successfully opened connection *
  213. * FALSE == failed to connect *
  214. * *
  215. * WARNINGS: *
  216. * Can be called for local or remote server but of course will *
  217. * fail if a called for local and local server is not "up". *
  218. * *
  219. * HISTORY: *
  220. * 6/1/1996 SW : Created. *
  221. *=========================================================================*/
  222. BOOL Instance_Class::Open_Poke_Connection( HSZ name )
  223. {
  224. conv_handle = DdeConnect(
  225. id_inst, // instance identifier
  226. name, // service name string handle
  227. poke_topic, // topic string handle
  228. (PCONVCONTEXT) NULL);// use default context
  229. if (conv_handle == NULL) {
  230. return FALSE;
  231. } else {
  232. return TRUE;
  233. }
  234. }
  235. /***************************************************************************
  236. * Instance_Class::Close_Poke_Connection -- closes poke connection *
  237. * *
  238. * INPUT: *
  239. * none. *
  240. * *
  241. * OUTPUT: *
  242. * TRUE == successfully closed connection *
  243. * FALSE == failed to close connection for some reason *
  244. * *
  245. * WARNINGS: *
  246. * none. *
  247. * *
  248. * HISTORY: *
  249. * 6/1/1996 SW : Created. *
  250. *=========================================================================*/
  251. BOOL Instance_Class::Close_Poke_Connection( void )
  252. {
  253. if( conv_handle ) {
  254. HCONV temp_handle = conv_handle;
  255. conv_handle = NULL;
  256. return( DdeDisconnect( temp_handle ));
  257. } else {
  258. return( TRUE );
  259. }
  260. }
  261. /***************************************************************************
  262. * Instance_Class::Poke_Server -- pokes some data to server *
  263. * *
  264. * INPUT: *
  265. * poke_data points to data to send to remote *
  266. * poke_length length of buffer to send *
  267. * *
  268. * OUTPUT: *
  269. * TRUE == successfully poked the data *
  270. * FALSE == failed to connect *
  271. * *
  272. * WARNINGS: *
  273. * has a 3 second timeout (change POKE_TIMEOUT, in milliseconds) *
  274. * *
  275. * HISTORY: *
  276. * 6/1/1996 SW : Created. *
  277. *=========================================================================*/
  278. #define POKE_TIMEOUT 60*1000 // 60 sec timeout
  279. BOOL Instance_Class::Poke_Server( LPBYTE poke_data, DWORD poke_length )
  280. {
  281. if( DdeClientTransaction(
  282. poke_data, // address of data to pass to server
  283. poke_length, // length of data
  284. conv_handle, // handle of conversation
  285. poke_topic, // handle of item name string
  286. CF_TEXT, // no special clipboard data format
  287. XTYP_POKE, // transaction type
  288. POKE_TIMEOUT, // time-out duration (millisecs)
  289. (LPDWORD) NULL // address of transaction result (don't check)
  290. ) == 0) {
  291. return( FALSE);
  292. } else {
  293. return( TRUE );
  294. }
  295. }
  296. /***************************************************************************
  297. * Instance_Class::dde_callback -- callback dde event handler *
  298. * *
  299. * INPUT: *
  300. * dde_event transaction type *
  301. * uFmt clipboard data format *
  302. * hconv handle of the conversation *
  303. * hsz1 handle of a string *
  304. * hsz2 handle of a string *
  305. * hdata handle of a global memory object *
  306. * dwData1 transaction-specific data *
  307. * dwData2 transaction-specific data *
  308. * *
  309. * OUTPUT: *
  310. * context specific HDDEDATA object *
  311. * *
  312. * WARNINGS: *
  313. * NOTE: declared as HDDEDATA CALLBACK which means PASCAL parameters *
  314. * *
  315. * HISTORY: *
  316. * 6/1/1996 SW : Created. *
  317. *=========================================================================*/
  318. HDDEDATA CALLBACK Instance_Class::dde_callback(
  319. UINT dde_event, // transaction type
  320. UINT uFmt, // clipboard data format
  321. HCONV , // handle of the conversation
  322. HSZ hsz1, // handle of a string
  323. HSZ hsz2, // handle of a string
  324. HDDEDATA hdata, // handle of a global memory object
  325. DWORD , // transaction-specific data
  326. DWORD // transaction-specific data
  327. )
  328. {
  329. dde_event;
  330. uFmt;
  331. hsz1;
  332. hsz2;
  333. hdata;
  334. return (HDDEDATA)NULL;
  335. #if (0) // ST 5/8/2019
  336. if (!Instance_Class::callback){
  337. return (HDDEDATA) NULL;
  338. }
  339. switch ( dde_event ) {
  340. case XTYP_REGISTER:
  341. case XTYP_UNREGISTER:
  342. return (HDDEDATA) NULL;
  343. case XTYP_ADVDATA:
  344. return (HDDEDATA) DDE_FACK;
  345. case XTYP_XACT_COMPLETE:
  346. return (HDDEDATA) NULL;
  347. case XTYP_DISCONNECT:
  348. Instance_Class::callback( NULL, DDE_ADVISE_DISCONNECT);
  349. return (HDDEDATA) NULL;
  350. case XTYP_CONNECT: {
  351. char buffer[32];
  352. DdeQueryString (Instance_Class::id_inst, hsz2, buffer, sizeof (buffer), 0) ;
  353. if (0 != strcmp (buffer, Instance_Class::ascii_name)) {
  354. return (HDDEDATA) NULL;
  355. }
  356. DdeQueryString (Instance_Class::id_inst, hsz1, buffer, sizeof (buffer), 0) ;
  357. if (0 != strcmp (buffer, "POKE TOPIC")) {
  358. return (HDDEDATA) NULL;
  359. }
  360. Instance_Class::callback( NULL, DDE_ADVISE_CONNECT);
  361. return (HDDEDATA) TRUE;
  362. }
  363. case XTYP_POKE:
  364. if (Instance_Class::process_pokes == FALSE ) {
  365. return (HDDEDATA) DDE_FNOTPROCESSED; // processing disabled
  366. } else {
  367. char buffer[32];
  368. DdeQueryString (Instance_Class::id_inst, hsz1, buffer, sizeof (buffer), 0) ;
  369. if (0 != strcmp (buffer, "POKE TOPIC")) {
  370. return (HDDEDATA) DDE_FNOTPROCESSED;
  371. } else if (uFmt == CF_TEXT) { // make sure it's CF_TEXT
  372. BOOL processed;
  373. BYTE FAR *pdata;
  374. DWORD dw_length;
  375. if ( (pdata = DdeAccessData( hdata, &dw_length)) == NULL ) {
  376. return (HDDEDATA) DDE_FNOTPROCESSED;
  377. }
  378. processed = Instance_Class::callback((LPBYTE) pdata, dw_length);
  379. DdeUnaccessData( hdata );
  380. if (processed == TRUE) {
  381. return (HDDEDATA) DDE_FACK;
  382. } else {
  383. return (HDDEDATA) NULL;
  384. }
  385. }
  386. }
  387. default:
  388. return (HDDEDATA) NULL;
  389. }
  390. #endif
  391. }
  392. #endif //WIN32