WOL_LOGN.CPP (18740B)
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 #ifdef WOLAPI_INTEGRATION 17 18 // Wol_Logn.cpp - WW online name/password dialog. 19 // ajw 07/16/98 20 21 #include "function.h" 22 23 #include "IconList.h" 24 #include "WolapiOb.h" 25 #include "PassEdit.h" 26 #include "WolStrng.h" 27 #include "BigCheck.h" 28 29 bool ReadSavedNicks( WolapiObject* pWO, IconListClass& NickList, char* szNameBuffer, char* szPassBuffer ); 30 bool bSaveNick( WolapiObject* pWO, const char* szNickToSave, const char* szPassToSave, bool bPassIsMangled ); 31 void DeleteNick( WolapiObject* pWO, int iOneBasedEntryToDelete ); 32 //char* LoadShpFile( const char* szShpFile ); 33 34 void DebugChatDef( HRESULT hRes ); 35 36 extern bool bTabKeyPressedHack; 37 38 //#include "WolDebug.h" 39 40 //*********************************************************************************************** 41 int WOL_Login_Dialog( WolapiObject* pWO ) 42 { 43 // Return values: 0 = user cancels, 1 = success, -1 = force game exit 44 45 if( pWO->bLoggedIn() ) 46 { 47 pWO->bReturningAfterGame = true; // Set trigger for chat dialog. 48 return 1; // We are already logged in, and have just come back from a game. 49 } 50 51 /* 52 ** Dialog & button dimensions 53 */ 54 #ifdef FRENCH 55 int d_dialog_w = 160 * RESFACTOR; // dialog width 56 #else 57 int d_dialog_w = 150 * RESFACTOR; // dialog width 58 #endif 59 int d_dialog_h = 85 * RESFACTOR; // dialog height 60 int d_dialog_x = (((320 * RESFACTOR) - d_dialog_w) / 2); 61 int d_dialog_y = (((255 * RESFACTOR) - d_dialog_h) / 2); 62 int d_dialog_cx = d_dialog_x + (d_dialog_w / 2); // coord of x-center 63 64 int d_txt8_h = 11 * RESFACTOR; // ht of 8-pt text 65 int d_margin = 7 * RESFACTOR; // margin width/height 66 int x_margin = 16 * RESFACTOR; // margin width/height 67 68 int top_margin = 0; 69 70 int d_name_w = 66 * RESFACTOR; 71 int d_name_h = 10 * RESFACTOR; 72 #ifdef FRENCH 73 int d_name_x = d_dialog_x + 25 * RESFACTOR; 74 #else 75 int d_name_x = d_dialog_x + 20 * RESFACTOR; 76 #endif 77 int d_name_y = d_dialog_y + top_margin + 25 * RESFACTOR; 78 79 int d_pass_w = 36 * RESFACTOR; 80 int d_pass_h = d_name_h; 81 int d_pass_x = d_name_x + d_name_w + 6 * RESFACTOR; 82 int d_pass_y = d_name_y; 83 84 int d_list_w = d_name_w; 85 int d_list_h = 20 * RESFACTOR; 86 int d_list_x = d_name_x; 87 int d_list_y = d_dialog_y + top_margin + 40 * RESFACTOR; 88 89 // int d_save_w = d_pass_w; 90 int d_save_h = 9 * RESFACTOR; 91 int d_save_x = d_pass_x + ( d_pass_w / 2 ) - ( d_pass_w / 2 ); 92 int d_save_y = d_list_y; // + ( d_list_h / 2 ) - ( d_save_h / 2 ); 93 94 int d_delete_w = d_pass_w; 95 int d_delete_h = 10 * RESFACTOR; 96 int d_delete_x = d_save_x; 97 int d_delete_y = d_list_y + d_list_h - d_delete_h; 98 99 #ifdef FRENCH 100 int d_connect_w = 45 * RESFACTOR; 101 #else 102 int d_connect_w = 40 * RESFACTOR; 103 #endif 104 int d_connect_h = 13 * RESFACTOR; 105 int d_connect_x = d_name_x + d_name_w/2 - d_connect_w/2; 106 int d_connect_y = d_dialog_y + top_margin + 65 * RESFACTOR; //d_dialog_y + d_dialog_h - d_connect_h - d_margin; 107 108 #if defined(GERMAN) || defined(FRENCH) 109 int d_cancel_w = 40 * RESFACTOR;//BG:40 110 #else 111 int d_cancel_w = 40 * RESFACTOR; 112 #endif 113 int d_cancel_h = 13 * RESFACTOR; 114 int d_cancel_x = d_pass_x + d_pass_w/2 - d_cancel_w/2; //d_dialog_cx + d_margin; 115 int d_cancel_y = d_connect_y; 116 117 /* 118 ** Button enumerations 119 */ 120 enum { 121 BUTTON_CONNECT = 100, 122 BUTTON_CANCEL, 123 LISTBOX_NICKS, 124 EDITBOX_NAME, 125 EDITBOX_PASS, 126 BUTTON_SAVECHECK, 127 BUTTON_DELETE, 128 }; 129 130 /* 131 ** Redraw values: in order from "top" to "bottom" layer of the dialog 132 */ 133 typedef enum { 134 REDRAW_NONE = 0, 135 REDRAW_BUTTONS, 136 REDRAW_BACKGROUND, 137 REDRAW_ALL = REDRAW_BACKGROUND 138 } RedrawType; 139 140 /* 141 ** Dialog variables 142 */ 143 int iReturn = 1; // 0 = user cancels, 1 = success, -1 = force game exit 144 145 /* 146 ** Other Variables 147 */ 148 char szNameBuffer[ WOL_NAME_LEN_MAX ] = {0}; // User name. 149 char szPassBuffer[ WOL_PASSWORD_LEN ] = {0}; // User password. 150 151 /* 152 ** Buttons 153 */ 154 ControlClass* commands = NULL; // the button list 155 156 TextButtonClass ConnectBtn( BUTTON_CONNECT, TXT_WOL_CONNECT, TPF_BUTTON, d_connect_x, d_connect_y, d_connect_w ); 157 TextButtonClass CancelBtn( BUTTON_CANCEL, TXT_CANCEL, TPF_BUTTON, d_cancel_x, d_cancel_y, d_cancel_w ); 158 159 IconListClass NickList( LISTBOX_NICKS, d_list_x, d_list_y, d_list_w, d_list_h, TPF_6PT_GRAD | TPF_NOSHADOW, 160 MFCD::Retrieve("BTN-UP.SHP"), MFCD::Retrieve("BTN-DN.SHP"), true, 1, 0 ); 161 162 WOLEditClass NameEdit( EDITBOX_NAME, szNameBuffer, sizeof(szNameBuffer), TPF_6PT_GRAD|TPF_NOSHADOW, 163 d_name_x, d_name_y, d_name_w, -1, EditClass::ALPHANUMERIC ); 164 165 PassEditClass PassEdit( EDITBOX_PASS, szPassBuffer, sizeof(szPassBuffer), TPF_6PT_GRAD|TPF_NOSHADOW, 166 d_pass_x, d_pass_y, d_pass_w, -1, EditClass::ALPHANUMERIC ); 167 168 // Just making sure globals are set right before String_Pixel_Width() call... sigh 169 Fancy_Text_Print( TXT_NONE, 0, 0, GadgetClass::Get_Color_Scheme(), TBLACK, TPF_6PT_GRAD | TPF_NOSHADOW ); 170 int iSaveTextWidth = String_Pixel_Width( TXT_WOL_SAVELOGIN ) + BIGCHECK_OFFSETX; 171 BigCheckBoxClass SaveCheckBox( BUTTON_SAVECHECK, d_save_x, d_save_y, iSaveTextWidth, d_save_h, 172 TXT_WOL_SAVELOGIN, TPF_6PT_GRAD | TPF_NOSHADOW, true ); 173 174 TextButtonClass DeleteBtn( BUTTON_DELETE, TXT_DELETE_BUTTON, TPF_BUTTON, d_delete_x, d_delete_y, d_delete_w ); 175 176 /* 177 ** Initialize. 178 */ 179 Set_Logic_Page(SeenBuff); 180 181 // Get saved nickname/passwords from the registry. 182 if( ReadSavedNicks( pWO, NickList, szNameBuffer, szPassBuffer ) ) 183 { 184 PassEdit.bClearOnNextSetFocus = true; 185 } 186 else 187 { 188 // Offer user the chance to go to web site now to get a nick. 189 if( pWO->DoWebRegistration() ) 190 { 191 // User chose to go to web page. Leave function so that we'll re-read nicks when they return. 192 return 0; 193 } 194 } 195 196 /* 197 ** Create the button list. 198 */ 199 commands = &ConnectBtn; 200 CancelBtn.Add_Tail(*commands); 201 NickList.Add_Tail(*commands); 202 NameEdit.Add_Tail(*commands); 203 PassEdit.Add_Tail(*commands); 204 SaveCheckBox.Add_Tail(*commands); 205 DeleteBtn.Add_Tail(*commands); 206 NameEdit.Set_Focus(); 207 208 if( NickList.Count() == 0 ) 209 DeleteBtn.Disable(); 210 211 /* 212 ** Main Processing Loop. 213 */ 214 Keyboard->Clear(); 215 bool firsttime = true; 216 bool display = true; 217 bool process = true; 218 while (process) { 219 220 /* 221 ** Invoke game callback. 222 */ 223 Call_Back(); 224 225 #ifdef WIN32 226 /* 227 ** If we have just received input focus again after running in the background then 228 ** we need to redraw. 229 */ 230 if (AllSurfaces.SurfacesRestored) { 231 AllSurfaces.SurfacesRestored=FALSE; 232 display = true; 233 } 234 #endif 235 236 /* 237 ** Refresh display if needed. 238 */ 239 if (display) { 240 241 //------------------------------------------------------------------------ 242 // Clear screen 243 //------------------------------------------------------------------------ 244 Hide_Mouse(); 245 Load_Title_Page(true); 246 // Show_Mouse(); 247 248 /* 249 ** Display the dialog box. 250 */ 251 // Hide_Mouse(); 252 if (display) { 253 Dialog_Box(d_dialog_x, d_dialog_y, d_dialog_w, d_dialog_h); 254 Draw_Caption(TXT_WOL_LOGINDIALOG, d_dialog_x, d_dialog_y, d_dialog_w); 255 } 256 257 /* 258 ** Redraw the buttons. 259 */ 260 if (display) { 261 Fancy_Text_Print( TXT_WOL_NAME, d_name_x + ( d_name_w / 2 ), d_name_y - 14, 262 GadgetClass::Get_Color_Scheme(), TBLACK, TPF_TEXT | TPF_CENTER ); 263 Fancy_Text_Print( TXT_WOL_PASSWORD, d_pass_x + ( d_pass_w / 2 ), d_pass_y - 14, 264 GadgetClass::Get_Color_Scheme(), TBLACK, TPF_TEXT | TPF_CENTER ); 265 commands->Flag_List_To_Redraw(); 266 } 267 Show_Mouse(); 268 display = false; 269 } 270 271 // Force mouse visible, as some beta testers report unexplicable disappearing cursors. 272 while( Get_Mouse_State() ) 273 Show_Mouse(); 274 // Be nice to other apps. 275 Sleep( 50 ); 276 277 /* 278 ** Get user input. 279 */ 280 bTabKeyPressedHack = false; 281 KeyNumType input = commands->Input(); 282 283 /* 284 ** The first time through the processing loop, set the edit 285 ** gadget to have the focus. The 286 ** focus must be set here since the gadget list has changed 287 ** and this change will cause any previous focus setting to be 288 ** cleared by the input processing routine. 289 */ 290 if (firsttime ) { 291 firsttime = false; 292 NameEdit.Set_Focus(); 293 NameEdit.Flag_To_Redraw(); 294 } 295 296 // /* 297 // ** If the <RETURN> key was pressed, then default to the appropriate 298 // ** action button according to the style of this dialog box. 299 // */ 300 /* if (input == KN_RETURN || input == (BUTTON_CONNECT|KN_BUTTON)) { 301 ToggleClass * toggle = NULL; 302 input = (KeyNumType)(BUTTON_CONNECT|KN_BUTTON); 303 CancelBtn.Turn_Off(); 304 toggle = (ToggleClass*)commands->Extract_Gadget(BUTTON_CONNECT); 305 if (toggle != NULL) { 306 toggle->Turn_On(); 307 toggle->IsPressed = true; 308 } 309 310 Hide_Mouse(); 311 commands->Draw_All(true); 312 Show_Mouse(); 313 } 314 */ 315 /* 316 ** Process input. 317 */ 318 // if( input ) 319 // debugprint( "input: %i\n", input ); 320 321 if( bTabKeyPressedHack ) 322 { 323 if( NameEdit.Has_Focus() ) 324 PassEdit.Set_Focus(); 325 else 326 NameEdit.Set_Focus(); 327 NameEdit.Flag_To_Redraw(); 328 PassEdit.Flag_To_Redraw(); 329 } 330 331 switch( input ) 332 { 333 /* 334 ** ESC/Cancel: break 335 */ 336 case ( KN_ESC ): 337 case ( BUTTON_CANCEL | KN_BUTTON ): 338 iReturn = 0; 339 process = false; 340 break; 341 342 case KN_RETURN: 343 case ( EDITBOX_NAME | KN_BUTTON ): 344 case ( EDITBOX_PASS | KN_BUTTON ): 345 case ( BUTTON_CONNECT | KN_BUTTON ): 346 { 347 if( !strlen( szNameBuffer ) ) 348 { 349 WWMessageBox().Process( TXT_WOL_MISSINGNAME ); 350 firsttime = true; // Bloody hack. 351 NameEdit.Set_Focus(); 352 Keyboard->Clear(); 353 display = true; 354 break; 355 } 356 if( !strlen( szPassBuffer ) ) 357 { 358 WWMessageBox().Process( TXT_WOL_MISSINGPASSWORD ); 359 firsttime = true; // Bloody hack. 360 PassEdit.Set_Focus(); 361 Keyboard->Clear(); 362 display = true; 363 break; 364 } 365 366 // If we have not done RequestServerList() yet, do it now. 367 if( !pWO->pChatSink->pServer ) 368 { 369 bool bBreak = false; 370 HRESULT hRes = pWO->GetChatServer(); 371 switch( hRes ) 372 { 373 case E_FAIL: 374 bBreak = true; 375 WWMessageBox().Process( TXT_WOL_CANTCONNECT ); 376 firsttime = true; // Bloody hack. 377 NameEdit.Set_Focus(); 378 Keyboard->Clear(); 379 display = true; 380 break; 381 case USERCANCELLED: 382 bBreak = true; 383 WWMessageBox().Process( TXT_WOL_LOGINCANCEL ); 384 firsttime = true; // Bloody hack. 385 NameEdit.Set_Focus(); 386 Keyboard->Clear(); 387 display = true; 388 break; 389 case PATCHAVOIDED: 390 bBreak = true; 391 firsttime = true; // Bloody hack. 392 NameEdit.Set_Focus(); 393 Keyboard->Clear(); 394 display = true; 395 break; 396 case PATCHDOWNLOADED: 397 bBreak = true; 398 process = false; 399 iReturn = -1; 400 break; 401 } 402 if( bBreak ) 403 break; 404 } 405 406 // RequestConnection()... 407 HRESULT hRes = pWO->AttemptLogin( szNameBuffer, szPassBuffer, PassEdit.bClearOnNextSetFocus ); 408 if( hRes == S_OK ) 409 { 410 if( SaveCheckBox.IsOn && !bSaveNick( pWO, szNameBuffer, szPassBuffer, PassEdit.bClearOnNextSetFocus ) ) 411 { 412 // Nick/pass save failed. 413 WWMessageBox().Process( TXT_WOL_CANTSAVENICK ); 414 } 415 process = false; 416 } 417 else 418 { 419 switch( hRes ) 420 { 421 case USERCANCELLED: 422 WWMessageBox().Process( TXT_WOL_LOGINCANCEL ); 423 break; 424 case CHAT_E_TIMEOUT: 425 WWMessageBox().Process( TXT_WOL_TIMEOUT ); 426 break; 427 case CHAT_E_BADPASS: 428 WWMessageBox().Process( TXT_WOL_BADPASS ); 429 break; 430 case CHAT_E_NICKINUSE: 431 WWMessageBox().Process( TXT_WOL_NICKINUSE ); 432 break; 433 case CHAT_E_CON_ERROR: 434 // This error value I pass back myself, when the emergency timeout is hit. 435 WWMessageBox().Process( TXT_WOL_TIMEOUT ); 436 break; 437 } 438 firsttime = true; // Bloody hack. 439 NameEdit.Set_Focus(); 440 Keyboard->Clear(); 441 display = true; 442 } 443 break; 444 } 445 446 /* 447 case( EDITBOX_PASS | KN_BUTTON ): 448 { 449 // Message with delay so that user has time to read it... 450 CDTimerClass<SystemTimerClass> timer; 451 timer = TICKS_PER_SECOND*4; 452 WWMessageBox().Process(TXT_WOL_DEBUG2, TXT_NONE); 453 while (timer > 0) { 454 Call_Back(); 455 } 456 Keyboard->Clear(); 457 458 display = true; 459 break; 460 } 461 */ 462 case ( LISTBOX_NICKS | KN_BUTTON ): 463 strcpy( szNameBuffer, NickList.Get_Item( NickList.Current_Index() ) ); 464 strcpy( szPassBuffer, NickList.Get_Item_ExtraDataString( NickList.Current_Index() ) ); 465 NameEdit.Flag_To_Redraw(); 466 PassEdit.Flag_To_Redraw(); 467 // Because the password is mangled, if the user begins to edit it now, we clear it. 468 // Otherwise we could get a half-mangled, half-unmangled password field. 469 // PassEdit.bClearOnNextSetFocus also acts as a flag telling us whether or not the 470 // password field is mangled or not. 471 PassEdit.bClearOnNextSetFocus = true; 472 // display = true; 473 break; 474 475 case ( BUTTON_SAVECHECK | KN_BUTTON ): 476 break; 477 478 case ( BUTTON_DELETE | KN_BUTTON ): 479 if( NickList.Count() > 0 ) 480 { 481 DeleteNick( pWO, NickList.Current_Index() + 1 ); 482 NickList.Remove_Item( NickList.Current_Index() ); 483 NickList.Flag_To_Redraw(); 484 if( NickList.Count() == 0 ) 485 { 486 DeleteBtn.Disable(); 487 DeleteBtn.Flag_To_Redraw(); 488 } 489 } 490 break; 491 492 default: 493 break; 494 } 495 } 496 497 return iReturn; 498 } 499 500 //*********************************************************************************************** 501 bool ReadSavedNicks( WolapiObject* pWO, IconListClass& NickList, char* szNameBuffer, char* szPassBuffer ) 502 { 503 // Read saved nickname/passwords from the registry. 504 // Set up the list of nick/passwords. 505 // Copy the first nick into the nick/password edits. 506 507 // Returns true if edits are set with a default nick/pass because a nick was found. 508 509 LPCSTR szNick; 510 LPCSTR szPass; 511 bool bReturn = false; 512 513 for( int i = 1; i != 3; i++ ) 514 { 515 if( pWO->pChat->GetNick( i, &szNick, &szPass ) == S_OK ) 516 { 517 if( *szNick ) 518 { 519 NickList.Add_Item( szNick, NULL, NULL, ICON_SHAPE, szPass ); 520 if( i == 1 ) 521 { 522 strcpy( szNameBuffer, szNick ); 523 strcpy( szPassBuffer, szPass ); 524 bReturn = true; 525 } 526 } 527 } 528 } 529 return bReturn; 530 } 531 532 //*********************************************************************************************** 533 bool bSaveNick( WolapiObject* pWO, const char* szNickToSave, const char* szPassToSave, bool bPassIsMangled ) 534 { 535 // Saves specified nick and password in the registry, using SetNick. 536 // Returns false if nick can't be saved. 537 538 // If slot 1 empty, use slot 1. 539 // Else push nick 1 down to second slot and save new nick in slot 1, unless 540 // nick 1 name matches new entry. 541 542 LPCSTR szNick; 543 LPCSTR szPass; 544 bool bPushSlot1 = true; 545 546 switch( pWO->pChat->GetNick( 1, &szNick, &szPass ) ) 547 { 548 case E_FAIL: 549 // Assume that this is because there is no registry entry. We can use this slot. 550 bPushSlot1 = false; 551 break; 552 case S_OK: 553 if( *szNick == 0 ) 554 bPushSlot1 = false; // We can use this blank slot. 555 else 556 if( strcmp( szNick, szNickToSave ) == 0 ) 557 bPushSlot1 = false; // We can use this slot as the name is the same. 558 break; 559 } 560 561 if( bPushSlot1 ) 562 { 563 // Move nick in slot 1 to slot 2. 564 pWO->pChat->SetNick( 2, szNick, szPass, false ); // (Already mangled.) 565 } 566 567 // Save new nick in slot 1. 568 return ( pWO->pChat->SetNick( 1, szNickToSave, szPassToSave, !bPassIsMangled ) == S_OK ); 569 570 /* 571 int iSlot; 572 bool bStop = false; 573 for( iSlot = 1; iSlot != 3; iSlot++ ) 574 { 575 switch( pWO->pChat->GetNick( iSlot, &szNick, &szPass ) ) 576 { 577 case E_FAIL: 578 // Assume that this is because there is no registry entry. We can use this slot. 579 bStop = true; 580 break; 581 case S_OK: 582 if( *szNick == 0 ) 583 bStop = true; // We can use this blank slot. 584 else 585 if( strcmp( szNick, szNickToSave ) == 0 ) 586 bStop = true; // We can use this slot as the name is the same. 587 break; 588 } 589 if( bStop ) 590 break; 591 } 592 if( iSlot == 3 ) 593 { 594 // No open slots were found. 595 // Get nick 1. 596 pWO->pChat->GetNick( 1, &szNick, &szPass ); 597 // Save as nick 2. 598 pWO->pChat->SetNick( 2, szNick, szPass, false ); // (Already mangled.) 599 // Save new nick 1. 600 return ( pWO->pChat->SetNick( 1, szNickToSave, szPassToSave, !bPassIsMangled ) == S_OK ); 601 } 602 else 603 { 604 // iSlot points to an open slot. 605 return ( pWO->pChat->SetNick( iSlot, szNickToSave, szPassToSave, !bPassIsMangled ) == S_OK ); 606 } 607 */ 608 } 609 610 //*********************************************************************************************** 611 void DeleteNick( WolapiObject* pWO, int iOneBasedEntryToDelete ) 612 { 613 // Delete a nick from the registry via wolapi SetNick. 614 // If nick to delete is in position one, and there is a second nick, move the second nick into position one. 615 if( iOneBasedEntryToDelete == 1 ) 616 { 617 // Check for nick 2. 618 LPCSTR szNick; 619 LPCSTR szPass; 620 if( pWO->pChat->GetNick( 2, &szNick, &szPass ) == S_OK && *szNick != 0 ) 621 { 622 // Copy nick in slot 2 to slot 1. 623 pWO->pChat->SetNick( 1, szNick, szPass, false ); // (Already mangled.) 624 // Delete slot 2. 625 HRESULT hRes = pWO->pChat->SetNick( 2, "", "", false ); 626 DebugChatDef( hRes ); 627 } 628 else 629 { 630 // No second nick. 631 HRESULT hRes = pWO->pChat->SetNick( 1, "", "", false ); 632 DebugChatDef( hRes ); 633 } 634 } 635 else 636 { 637 HRESULT hRes = pWO->pChat->SetNick( 2, "", "", false ); 638 DebugChatDef( hRes ); 639 } 640 } 641 642 /* 643 //*********************************************************************************************** 644 char* LoadShpFile( const char* szShpFile ) 645 { 646 // Returns pointer to shp data that has been new'ed (and must be delete[]d), or NULL if failure. 647 // ajw: No longer needed - I used this before putting new resources into a mix file. 648 HANDLE hFile; 649 hFile = CreateFile( szShpFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); 650 if( hFile == INVALID_HANDLE_VALUE ) 651 return NULL; 652 DWORD dwFileSize = GetFileSize( hFile, NULL ); 653 char* pShp = new char[ dwFileSize ]; 654 DWORD dwBytesRead; 655 ReadFile( hFile, pShp, dwFileSize, &dwBytesRead, NULL ); 656 // debugprint( "~~ LoadShpFile() - Read %i bytes out of %i from shp file.\n", dwBytesRead, dwFileSize ); 657 CloseHandle( hFile ); 658 return pShp; 659 } 660 */ 661 662 #endif