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