// ShowARP.cpp : ThinApp SDK sample program to illustrate the use of the registry objects
//               It will show the virtual Add/Remove Program entries contained in the package
//
// Usage: ShowARP <PhysicalPackageName>

#include "stdafx.h"

// Using #import creates some wrapper classes which allow you to concentrate on
// the logic instead of getting drowned in error handling
#import "progid:ThinApp.Management"
using namespace ThinAppSDK;

/*
 * Display ARP entries found in one (user or machine) registry key
 */
static unsigned ShowUninstallEntries(IThinApp_VRegistryObjectPtr VReg, LPCWSTR BaseKey)
{
   unsigned Entries = 0;

   // Since the method can fail (key not present), we call the raw method and check the HRESULT. We could also have wrapped
   // a VReg->OpenKey() call in a try/catch frame
   IThinApp_VRegKey *RawKey;
   HRESULT Hr = VReg->raw_OpenKey(_bstr_t(BaseKey), _bstr_t(L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"), &RawKey);
   if (FAILED(Hr))
      return 0;
   IThinApp_VRegKeyPtr Key(RawKey, false);

   // Iterate over all the subkeys of the Uninstall key.
   IThinApp_VRegKeysPtr SubKeys = Key->SubKeys;
   long SubKeysCount = SubKeys->Count;
   for (long SubKeyIndex = 1; SubKeyIndex <= SubKeysCount; SubKeyIndex++)
   {
      IThinApp_VRegKeyPtr SubKey = SubKeys->Item[SubKeyIndex];

      // Find the DisplayName value, that's the one we want to display
      IThinApp_VRegValuesPtr Values = SubKey->Values;
      long ValuesCount = Values->Count;
      for (long ValueIndex = 1; ValueIndex <= ValuesCount; ValueIndex++)
      {
         IThinApp_VRegValuePtr Value = Values->Item[ValueIndex];
         if (_wcsicmp(Value->Name, L"DisplayName") == 0 && Value->Type == REG_SZ)
         {
            _variant_t DisplayName(Value->Data);
            DisplayName.ChangeType(VT_BSTR);
            printf("%ls\n", (LPCWSTR) DisplayName.bstrVal);
            Entries++;
         }
      }
   }

   return Entries;
}

/*
 * Display ARP entries
 */
static void ShowARP(LPCWSTR PackageName)
{
   // Everything starts with the ThinApp.Management object, create it
   IThinApp_ManagementPtr Management;
   HRESULT Hr =  Management.CreateInstance(__uuidof(CThinApp_Management));
   if (FAILED(Hr)) 
   {
      fprintf(stderr, "Failed to create ThinApp.Management object, perhaps ThinApp SDK is not registered?\n");
      exit(1);
   }

   // Follow the chain from ThinApp.Management to ThinApp.Package to ThinApp.VRegistryObject
   IThinApp_PackagePtr Package = Management->OpenPackage(PackageName);
   IThinApp_VRegistryObjectPtr VReg = Package->GetVRegistryObject(0);

   printf("Add/Remove Program entries contained in package %ls:\n\n", PackageName);

   // Do the actual work of enumerating the entries
   unsigned TotalEntries;
   TotalEntries = ShowUninstallEntries(VReg, L"HKLM");
   TotalEntries += ShowUninstallEntries(VReg, L"HKCU");

   if (TotalEntries == 0)
      printf("No entries found\n");
   else if (TotalEntries == 1)
      printf("\n1 Entry found\n");
   else
      printf("\n%u Entries found\n", TotalEntries);
}

/*
 * Main program. Parse arguments and then call ShowARP to do the real work.
 */
int wmain(int argc, WCHAR *argv[])
{
#ifdef _DEBUG
   // Dump memory leaks on exit
   _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
#endif

   CoInitialize(NULL);

   // The smart pointer classes will throw _com_error on failures, handle these
   int ExitCode;
   try
   {
      if (argc != 2)
      {
         fprintf(stderr, "Usage: ShowARP <PhysicalPackageName>\n");
         exit(1);
      }

      // Produce the listing of ARP entries
      ShowARP(argv[1]);

      ExitCode = 0;
   }
   catch(_com_error e)
   {
      fprintf(stderr, "Error: %ls\n", (LPCWSTR) e.Description());
      ExitCode = 1;
   }

   CoUninitialize();

   return ExitCode;
}
