1 /* 2 * PROJECT: ReactOS Applications Manager 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Classes for working with available applications 5 * COPYRIGHT: Copyright 2017 Alexander Shaposhnikov (sanchaez@reactos.org) 6 * Copyright 2020 He Yang (1160386205@qq.com) 7 * Copyright 2021-2023 Mark Jansen <mark.jansen@reactos.org> 8 */ 9 10 #include "rapps.h" 11 #include "appview.h" 12 13 CAppInfo::CAppInfo(const CStringW &Identifier, AppsCategories Category) 14 : szIdentifier(Identifier), iCategory(Category) 15 { 16 } 17 18 CAppInfo::~CAppInfo() 19 { 20 } 21 22 CAvailableApplicationInfo::CAvailableApplicationInfo( 23 CConfigParser *Parser, 24 const CStringW &PkgName, 25 AppsCategories Category, 26 const CPathW &BasePath) 27 : CAppInfo(PkgName, Category), m_Parser(Parser), m_ScrnshotRetrieved(false), m_LanguagesLoaded(false) 28 { 29 m_Parser->GetString(L"Name", szDisplayName); 30 m_Parser->GetString(L"Version", szDisplayVersion); 31 m_Parser->GetString(L"URLDownload", m_szUrlDownload); 32 m_Parser->GetString(L"Description", szComments); 33 34 CPathW IconPath = BasePath; 35 IconPath += L"icons"; 36 37 CStringW IconName; 38 if (m_Parser->GetString(L"Icon", IconName)) 39 { 40 IconPath += IconName; 41 } 42 else 43 { 44 // inifile.ico 45 IconPath += (szIdentifier + L".ico"); 46 } 47 48 if (PathFileExistsW(IconPath)) 49 { 50 szDisplayIcon = (LPCWSTR)IconPath; 51 } 52 53 INT iSizeBytes; 54 55 if (m_Parser->GetInt(L"SizeBytes", iSizeBytes)) 56 { 57 StrFormatByteSizeW(iSizeBytes, m_szSize.GetBuffer(MAX_PATH), MAX_PATH); 58 m_szSize.ReleaseBuffer(); 59 } 60 61 m_Parser->GetString(L"URLSite", m_szUrlSite); 62 } 63 64 CAvailableApplicationInfo::~CAvailableApplicationInfo() 65 { 66 delete m_Parser; 67 } 68 69 VOID 70 CAvailableApplicationInfo::ShowAppInfo(CAppRichEdit *RichEdit) 71 { 72 RichEdit->SetText(szDisplayName, CFE_BOLD); 73 InsertVersionInfo(RichEdit); 74 RichEdit->LoadAndInsertText(IDS_AINFO_LICENSE, LicenseString(), 0); 75 InsertLanguageInfo(RichEdit); 76 77 RichEdit->LoadAndInsertText(IDS_AINFO_SIZE, m_szSize, 0); 78 RichEdit->LoadAndInsertText(IDS_AINFO_URLSITE, m_szUrlSite, CFE_LINK); 79 RichEdit->LoadAndInsertText(IDS_AINFO_DESCRIPTION, szComments, 0); 80 RichEdit->LoadAndInsertText(IDS_AINFO_URLDOWNLOAD, m_szUrlDownload, CFE_LINK); 81 RichEdit->LoadAndInsertText(IDS_AINFO_PACKAGE_NAME, szIdentifier, 0); 82 } 83 84 int 85 CompareVersion(const CStringW &left, const CStringW &right) 86 { 87 int nLeft = 0, nRight = 0; 88 89 while (true) 90 { 91 CStringW leftPart = left.Tokenize(L".", nLeft); 92 CStringW rightPart = right.Tokenize(L".", nRight); 93 94 if (leftPart.IsEmpty() && rightPart.IsEmpty()) 95 return 0; 96 if (leftPart.IsEmpty()) 97 return -1; 98 if (rightPart.IsEmpty()) 99 return 1; 100 101 int leftVal, rightVal; 102 103 if (!StrToIntExW(leftPart, STIF_DEFAULT, &leftVal)) 104 leftVal = 0; 105 if (!StrToIntExW(rightPart, STIF_DEFAULT, &rightVal)) 106 rightVal = 0; 107 108 if (leftVal > rightVal) 109 return 1; 110 if (rightVal < leftVal) 111 return -1; 112 } 113 } 114 115 VOID 116 CAvailableApplicationInfo::InsertVersionInfo(CAppRichEdit *RichEdit) 117 { 118 CStringW szRegName; 119 m_Parser->GetString(DB_REGNAME, szRegName); 120 121 BOOL bIsInstalled = ::GetInstalledVersion(NULL, szRegName) || ::GetInstalledVersion(NULL, szDisplayName); 122 if (bIsInstalled) 123 { 124 CStringW szInstalledVersion; 125 CStringW szNameVersion = szDisplayName + L" " + szDisplayVersion; 126 BOOL bHasInstalledVersion = ::GetInstalledVersion(&szInstalledVersion, szRegName) || 127 ::GetInstalledVersion(&szInstalledVersion, szDisplayName) || 128 ::GetInstalledVersion(&szInstalledVersion, szNameVersion); 129 130 if (bHasInstalledVersion) 131 { 132 BOOL bHasUpdate = CompareVersion(szInstalledVersion, szDisplayVersion) < 0; 133 if (bHasUpdate) 134 { 135 RichEdit->LoadAndInsertText(IDS_STATUS_UPDATE_AVAILABLE, CFE_ITALIC); 136 RichEdit->LoadAndInsertText(IDS_AINFO_VERSION, szInstalledVersion, 0); 137 } 138 else 139 { 140 RichEdit->LoadAndInsertText(IDS_STATUS_INSTALLED, CFE_ITALIC); 141 } 142 } 143 else 144 { 145 RichEdit->LoadAndInsertText(IDS_STATUS_INSTALLED, CFE_ITALIC); 146 } 147 } 148 else 149 { 150 RichEdit->LoadAndInsertText(IDS_STATUS_NOTINSTALLED, CFE_ITALIC); 151 } 152 153 RichEdit->LoadAndInsertText(IDS_AINFO_AVAILABLEVERSION, szDisplayVersion, 0); 154 } 155 156 CStringW 157 CAvailableApplicationInfo::LicenseString() 158 { 159 INT IntBuffer; 160 m_Parser->GetInt(L"LicenseType", IntBuffer); 161 CStringW szLicenseString; 162 m_Parser->GetString(L"License", szLicenseString); 163 LicenseType licenseType; 164 165 if (IsKnownLicenseType(IntBuffer)) 166 { 167 licenseType = static_cast<LicenseType>(IntBuffer); 168 } 169 else 170 { 171 licenseType = LICENSE_NONE; 172 if (szLicenseString.CompareNoCase(L"Freeware") == 0) 173 { 174 licenseType = LICENSE_FREEWARE; 175 szLicenseString = L""; 176 } 177 } 178 179 CStringW szLicense; 180 switch (licenseType) 181 { 182 case LICENSE_OPENSOURCE: 183 szLicense.LoadStringW(IDS_LICENSE_OPENSOURCE); 184 break; 185 case LICENSE_FREEWARE: 186 szLicense.LoadStringW(IDS_LICENSE_FREEWARE); 187 break; 188 case LICENSE_TRIAL: 189 szLicense.LoadStringW(IDS_LICENSE_TRIAL); 190 break; 191 default: 192 return szLicenseString; 193 } 194 195 if (!szLicenseString.IsEmpty()) 196 szLicense += L" (" + szLicenseString + L")"; 197 return szLicense; 198 } 199 200 VOID 201 CAvailableApplicationInfo::InsertLanguageInfo(CAppRichEdit *RichEdit) 202 { 203 if (!m_LanguagesLoaded) 204 { 205 RetrieveLanguages(); 206 } 207 208 if (m_LanguageLCIDs.GetSize() == 0) 209 { 210 return; 211 } 212 213 const INT nTranslations = m_LanguageLCIDs.GetSize(); 214 CStringW szLangInfo; 215 CStringW szLoadedTextAvailability; 216 CStringW szLoadedAInfoText; 217 218 szLoadedAInfoText.LoadStringW(IDS_AINFO_LANGUAGES); 219 220 const LCID lcEnglish = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT); 221 if (m_LanguageLCIDs.Find(GetUserDefaultLCID()) >= 0) 222 { 223 szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_AVAILABLE_TRANSLATION); 224 if (nTranslations > 1) 225 { 226 CStringW buf; 227 buf.LoadStringW(IDS_LANGUAGE_MORE_PLACEHOLDER); 228 szLangInfo.Format(buf, nTranslations - 1); 229 } 230 else 231 { 232 szLangInfo.LoadStringW(IDS_LANGUAGE_SINGLE); 233 szLangInfo = L" (" + szLangInfo + L")"; 234 } 235 } 236 else if (m_LanguageLCIDs.Find(lcEnglish) >= 0) 237 { 238 szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_ENGLISH_TRANSLATION); 239 if (nTranslations > 1) 240 { 241 CStringW buf; 242 buf.LoadStringW(IDS_LANGUAGE_AVAILABLE_PLACEHOLDER); 243 szLangInfo.Format(buf, nTranslations - 1); 244 } 245 else 246 { 247 szLangInfo.LoadStringW(IDS_LANGUAGE_SINGLE); 248 szLangInfo = L" (" + szLangInfo + L")"; 249 } 250 } 251 else 252 { 253 szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_NO_TRANSLATION); 254 } 255 256 RichEdit->InsertText(szLoadedAInfoText, CFE_BOLD); 257 RichEdit->InsertText(szLoadedTextAvailability, NULL); 258 RichEdit->InsertText(szLangInfo, CFE_ITALIC); 259 } 260 261 VOID 262 CAvailableApplicationInfo::RetrieveLanguages() 263 { 264 m_LanguagesLoaded = true; 265 266 CStringW szBuffer; 267 if (!m_Parser->GetString(L"Languages", szBuffer)) 268 { 269 return; 270 } 271 272 // Parse parameter string 273 int iIndex = 0; 274 while (true) 275 { 276 CStringW szLocale = szBuffer.Tokenize(L"|", iIndex); 277 if (szLocale.IsEmpty()) 278 break; 279 280 szLocale = L"0x" + szLocale; 281 282 INT iLCID; 283 if (StrToIntExW(szLocale, STIF_SUPPORT_HEX, &iLCID)) 284 { 285 m_LanguageLCIDs.Add(static_cast<LCID>(iLCID)); 286 } 287 } 288 } 289 290 BOOL 291 CAvailableApplicationInfo::Valid() const 292 { 293 return !szDisplayName.IsEmpty() && !m_szUrlDownload.IsEmpty(); 294 } 295 296 BOOL 297 CAvailableApplicationInfo::CanModify() 298 { 299 return FALSE; 300 } 301 302 BOOL 303 CAvailableApplicationInfo::RetrieveIcon(CStringW &Path) const 304 { 305 Path = szDisplayIcon; 306 return !Path.IsEmpty(); 307 } 308 309 #define MAX_SCRNSHOT_NUM 16 310 BOOL 311 CAvailableApplicationInfo::RetrieveScreenshot(CStringW &Path) 312 { 313 if (!m_ScrnshotRetrieved) 314 { 315 static_assert(MAX_SCRNSHOT_NUM < 10000, "MAX_SCRNSHOT_NUM is too big"); 316 for (int i = 0; i < MAX_SCRNSHOT_NUM; i++) 317 { 318 CStringW ScrnshotField; 319 ScrnshotField.Format(L"Screenshot%d", i + 1); 320 CStringW ScrnshotLocation; 321 if (!m_Parser->GetString(ScrnshotField, ScrnshotLocation)) 322 { 323 // We stop at the first screenshot not found, 324 // so screenshots _have_ to be consecutive 325 break; 326 } 327 328 if (PathIsURLW(ScrnshotLocation.GetString())) 329 { 330 m_szScrnshotLocation.Add(ScrnshotLocation); 331 } 332 } 333 m_ScrnshotRetrieved = true; 334 } 335 336 if (m_szScrnshotLocation.GetSize() > 0) 337 { 338 Path = m_szScrnshotLocation[0]; 339 } 340 341 return !Path.IsEmpty(); 342 } 343 344 VOID 345 CAvailableApplicationInfo::GetDownloadInfo(CStringW &Url, CStringW &Sha1, ULONG &SizeInBytes) const 346 { 347 Url = m_szUrlDownload; 348 m_Parser->GetString(L"SHA1", Sha1); 349 INT iSizeBytes; 350 351 if (m_Parser->GetInt(L"SizeBytes", iSizeBytes)) 352 { 353 SizeInBytes = (ULONG)iSizeBytes; 354 } 355 else 356 { 357 SizeInBytes = 0; 358 } 359 } 360 361 VOID 362 CAvailableApplicationInfo::GetDisplayInfo(CStringW &License, CStringW &Size, CStringW &UrlSite, CStringW &UrlDownload) 363 { 364 License = LicenseString(); 365 Size = m_szSize; 366 UrlSite = m_szUrlSite; 367 UrlDownload = m_szUrlDownload; 368 } 369 370 InstallerType 371 CAvailableApplicationInfo::GetInstallerType() const 372 { 373 CStringW str; 374 m_Parser->GetString(DB_INSTALLER, str); 375 if (str.CompareNoCase(DB_GENINSTSECTION) == 0) 376 return INSTALLER_GENERATE; 377 else 378 return INSTALLER_UNKNOWN; 379 } 380 381 BOOL 382 CAvailableApplicationInfo::UninstallApplication(UninstallCommandFlags Flags) 383 { 384 ATLASSERT(FALSE && "Should not be called"); 385 return FALSE; 386 } 387 388 CInstalledApplicationInfo::CInstalledApplicationInfo( 389 HKEY Key, 390 const CStringW &KeyName, 391 AppsCategories Category, UINT KeyInfo) 392 : CAppInfo(KeyName, Category), m_hKey(Key), m_KeyInfo(KeyInfo) 393 { 394 if (GetApplicationRegString(L"DisplayName", szDisplayName)) 395 { 396 GetApplicationRegString(L"DisplayIcon", szDisplayIcon); 397 GetApplicationRegString(L"DisplayVersion", szDisplayVersion); 398 GetApplicationRegString(L"Comments", szComments); 399 } 400 } 401 402 CInstalledApplicationInfo::~CInstalledApplicationInfo() 403 { 404 } 405 406 VOID 407 CInstalledApplicationInfo::AddApplicationRegString( 408 CAppRichEdit *RichEdit, 409 UINT StringID, 410 const CStringW &String, 411 DWORD TextFlags) 412 { 413 CStringW Tmp; 414 if (GetApplicationRegString(String, Tmp)) 415 { 416 RichEdit->InsertTextWithString(StringID, Tmp, TextFlags); 417 } 418 } 419 420 VOID 421 CInstalledApplicationInfo::ShowAppInfo(CAppRichEdit *RichEdit) 422 { 423 RichEdit->SetText(szDisplayName, CFE_BOLD); 424 RichEdit->InsertText(L"\n", 0); 425 426 RichEdit->InsertTextWithString(IDS_INFO_VERSION, szDisplayVersion, 0); 427 AddApplicationRegString(RichEdit, IDS_INFO_PUBLISHER, L"Publisher", 0); 428 AddApplicationRegString(RichEdit, IDS_INFO_REGOWNER, L"RegOwner", 0); 429 AddApplicationRegString(RichEdit, IDS_INFO_PRODUCTID, L"ProductID", 0); 430 AddApplicationRegString(RichEdit, IDS_INFO_HELPLINK, L"HelpLink", CFM_LINK); 431 AddApplicationRegString(RichEdit, IDS_INFO_HELPPHONE, L"HelpTelephone", 0); 432 AddApplicationRegString(RichEdit, IDS_INFO_README, L"Readme", 0); 433 AddApplicationRegString(RichEdit, IDS_INFO_CONTACT, L"Contact", 0); 434 AddApplicationRegString(RichEdit, IDS_INFO_UPDATEINFO, L"URLUpdateInfo", CFM_LINK); 435 AddApplicationRegString(RichEdit, IDS_INFO_INFOABOUT, L"URLInfoAbout", CFM_LINK); 436 RichEdit->InsertTextWithString(IDS_INFO_COMMENTS, szComments, 0); 437 438 if (m_szInstallDate.IsEmpty()) 439 { 440 RetrieveInstallDate(); 441 } 442 443 RichEdit->InsertTextWithString(IDS_INFO_INSTALLDATE, m_szInstallDate, 0); 444 AddApplicationRegString(RichEdit, IDS_INFO_INSTLOCATION, L"InstallLocation", 0); 445 AddApplicationRegString(RichEdit, IDS_INFO_INSTALLSRC, L"InstallSource", 0); 446 447 if (m_szUninstallString.IsEmpty()) 448 { 449 RetrieveUninstallStrings(); 450 } 451 452 RichEdit->InsertTextWithString(IDS_INFO_UNINSTALLSTR, m_szUninstallString, 0); 453 RichEdit->InsertTextWithString(IDS_INFO_MODIFYPATH, m_szModifyString, 0); 454 } 455 456 VOID 457 CInstalledApplicationInfo::RetrieveInstallDate() 458 { 459 DWORD dwInstallTimeStamp; 460 SYSTEMTIME InstallLocalTime; 461 if (GetApplicationRegString(L"InstallDate", m_szInstallDate)) 462 { 463 ZeroMemory(&InstallLocalTime, sizeof(InstallLocalTime)); 464 // Check if we have 8 characters to parse the datetime. 465 // Maybe other formats exist as well? 466 m_szInstallDate = m_szInstallDate.Trim(); 467 if (m_szInstallDate.GetLength() == 8) 468 { 469 InstallLocalTime.wYear = wcstol(m_szInstallDate.Left(4).GetString(), NULL, 10); 470 InstallLocalTime.wMonth = wcstol(m_szInstallDate.Mid(4, 2).GetString(), NULL, 10); 471 InstallLocalTime.wDay = wcstol(m_szInstallDate.Mid(6, 2).GetString(), NULL, 10); 472 } 473 } 474 // It might be a DWORD (Unix timestamp). try again. 475 else if (GetApplicationRegDword(L"InstallDate", &dwInstallTimeStamp)) 476 { 477 FILETIME InstallFileTime; 478 SYSTEMTIME InstallSystemTime; 479 480 UnixTimeToFileTime(dwInstallTimeStamp, &InstallFileTime); 481 FileTimeToSystemTime(&InstallFileTime, &InstallSystemTime); 482 483 // convert to localtime 484 SystemTimeToTzSpecificLocalTime(NULL, &InstallSystemTime, &InstallLocalTime); 485 } 486 487 // convert to readable date string 488 int cchTimeStrLen = GetDateFormatW(LOCALE_USER_DEFAULT, 0, &InstallLocalTime, NULL, 0, 0); 489 490 GetDateFormatW( 491 LOCALE_USER_DEFAULT, // use default locale for current user 492 0, &InstallLocalTime, NULL, m_szInstallDate.GetBuffer(cchTimeStrLen), cchTimeStrLen); 493 m_szInstallDate.ReleaseBuffer(); 494 } 495 496 VOID 497 CInstalledApplicationInfo::RetrieveUninstallStrings() 498 { 499 DWORD dwWindowsInstaller = 0; 500 if (GetApplicationRegDword(L"WindowsInstaller", &dwWindowsInstaller) && dwWindowsInstaller) 501 { 502 // MSI has the same info in Uninstall / modify, so manually build it 503 m_szUninstallString.Format(L"msiexec /x%s", szIdentifier.GetString()); 504 } 505 else 506 { 507 GetApplicationRegString(L"UninstallString", m_szUninstallString); 508 } 509 DWORD dwNoModify = 0; 510 if (!GetApplicationRegDword(L"NoModify", &dwNoModify)) 511 { 512 CStringW Tmp; 513 if (GetApplicationRegString(L"NoModify", Tmp)) 514 { 515 dwNoModify = Tmp.GetLength() > 0 ? (Tmp[0] == '1') : 0; 516 } 517 else 518 { 519 dwNoModify = 0; 520 } 521 } 522 if (!dwNoModify) 523 { 524 if (dwWindowsInstaller) 525 { 526 m_szModifyString.Format(L"msiexec /i%s", szIdentifier.GetString()); 527 } 528 else 529 { 530 GetApplicationRegString(L"ModifyPath", m_szModifyString); 531 } 532 } 533 } 534 535 BOOL 536 CInstalledApplicationInfo::Valid() const 537 { 538 return !szDisplayName.IsEmpty(); 539 } 540 541 BOOL 542 CInstalledApplicationInfo::CanModify() 543 { 544 if (m_szUninstallString.IsEmpty()) 545 { 546 RetrieveUninstallStrings(); 547 } 548 549 return !m_szModifyString.IsEmpty(); 550 } 551 552 BOOL 553 CInstalledApplicationInfo::RetrieveIcon(CStringW &Path) const 554 { 555 Path = szDisplayIcon; 556 return !Path.IsEmpty(); 557 } 558 559 BOOL 560 CInstalledApplicationInfo::RetrieveScreenshot(CStringW & /*Path*/) 561 { 562 return FALSE; 563 } 564 565 VOID 566 CInstalledApplicationInfo::GetDownloadInfo(CStringW &Url, CStringW &Sha1, ULONG &SizeInBytes) const 567 { 568 ATLASSERT(FALSE && "Should not be called"); 569 } 570 571 VOID 572 CInstalledApplicationInfo::GetDisplayInfo(CStringW &License, CStringW &Size, CStringW &UrlSite, CStringW &UrlDownload) 573 { 574 ATLASSERT(FALSE && "Should not be called"); 575 } 576 577 InstallerType 578 CInstalledApplicationInfo::GetInstallerType() const 579 { 580 CRegKey reg; 581 if (reg.Open(m_hKey, GENERATE_ARPSUBKEY, KEY_READ) == ERROR_SUCCESS) 582 { 583 return INSTALLER_GENERATE; 584 } 585 return INSTALLER_UNKNOWN; 586 } 587 588 BOOL 589 CInstalledApplicationInfo::UninstallApplication(UninstallCommandFlags Flags) 590 { 591 if (GetInstallerType() == INSTALLER_GENERATE) 592 { 593 return UninstallGenerated(*this, Flags); 594 } 595 596 BOOL bModify = Flags & UCF_MODIFY; 597 if (m_szUninstallString.IsEmpty()) 598 { 599 RetrieveUninstallStrings(); 600 } 601 602 CStringW cmd = bModify ? m_szModifyString : m_szUninstallString; 603 if ((Flags & (UCF_MODIFY | UCF_SILENT)) == UCF_SILENT) 604 { 605 DWORD msi = 0; 606 msi = GetApplicationRegDword(L"WindowsInstaller", &msi) && msi; 607 if (msi) 608 { 609 cmd += L" /qn"; 610 } 611 else 612 { 613 CStringW silentcmd; 614 if (GetApplicationRegString(L"QuietUninstallString", silentcmd) && !silentcmd.IsEmpty()) 615 { 616 cmd = silentcmd; 617 } 618 } 619 } 620 621 BOOL bSuccess = StartProcess(cmd, TRUE); 622 623 if (bSuccess && !bModify) 624 WriteLogMessage(EVENTLOG_SUCCESS, MSG_SUCCESS_REMOVE, szDisplayName); 625 626 return bSuccess; 627 } 628 629 BOOL 630 CInstalledApplicationInfo::GetApplicationRegString(LPCWSTR lpKeyName, CStringW &String) 631 { 632 ULONG nChars = 0; 633 // Get the size 634 if (m_hKey.QueryStringValue(lpKeyName, NULL, &nChars) != ERROR_SUCCESS) 635 { 636 String.Empty(); 637 return FALSE; 638 } 639 640 LPWSTR Buffer = String.GetBuffer(nChars); 641 LONG lResult = m_hKey.QueryStringValue(lpKeyName, Buffer, &nChars); 642 if (nChars > 0 && Buffer[nChars - 1] == UNICODE_NULL) 643 nChars--; 644 String.ReleaseBuffer(nChars); 645 646 if (lResult != ERROR_SUCCESS) 647 { 648 String.Empty(); 649 return FALSE; 650 } 651 652 if (String.Find('%') >= 0) 653 { 654 CStringW Tmp; 655 DWORD dwLen = ExpandEnvironmentStringsW(String, NULL, 0); 656 if (dwLen > 0) 657 { 658 BOOL bSuccess = ExpandEnvironmentStringsW(String, Tmp.GetBuffer(dwLen), dwLen) == dwLen; 659 Tmp.ReleaseBuffer(dwLen - 1); 660 if (bSuccess) 661 { 662 String = Tmp; 663 } 664 else 665 { 666 String.Empty(); 667 return FALSE; 668 } 669 } 670 } 671 672 return TRUE; 673 } 674 675 BOOL 676 CInstalledApplicationInfo::GetApplicationRegDword(LPCWSTR lpKeyName, DWORD *lpValue) 677 { 678 DWORD dwSize = sizeof(DWORD), dwType; 679 if (RegQueryValueExW(m_hKey, lpKeyName, NULL, &dwType, (LPBYTE)lpValue, &dwSize) != ERROR_SUCCESS || 680 dwType != REG_DWORD) 681 { 682 return FALSE; 683 } 684 685 return TRUE; 686 } 687