DDE.CPP 19 KB

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