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