]> git.kernelconcepts.de Git - karo-tx-redboot.git/blobdiff - tools/src/tools/pkgadmin/win32/PkgAdminDlg.cpp
Initial revision
[karo-tx-redboot.git] / tools / src / tools / pkgadmin / win32 / PkgAdminDlg.cpp
diff --git a/tools/src/tools/pkgadmin/win32/PkgAdminDlg.cpp b/tools/src/tools/pkgadmin/win32/PkgAdminDlg.cpp
new file mode 100644 (file)
index 0000000..d6b4f9e
--- /dev/null
@@ -0,0 +1,619 @@
+//####COPYRIGHTBEGIN####
+//                                                                          
+// ----------------------------------------------------------------------------
+// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
+//
+// This program is part of the eCos host tools.
+//
+// This program is free software; you can redistribute it and/or modify it 
+// under the terms of the GNU General Public License as published by the Free 
+// Software Foundation; either version 2 of the License, or (at your option) 
+// any later version.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+// more details.
+// 
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+//
+// ----------------------------------------------------------------------------
+//                                                                          
+//####COPYRIGHTEND####
+// PkgAdminDlg.cpp : implementation file
+//
+
+#include "stdafx.h"
+
+#include "PkgAdmin.h"
+#include "PkgAdminDlg.h"
+#include "PkgAdminLicenseDlg.h"
+#include "PkgAdminTclWaitDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CPkgadminAboutDlg dialog used for App About
+
+class CPkgadminAboutDlg : public CDialog
+{
+public:
+       CPkgadminAboutDlg();
+
+// Dialog Data
+       //{{AFX_DATA(CPkgadminAboutDlg)
+       enum { IDD = IDD_PKGADMIN_ABOUTBOX };
+       //}}AFX_DATA
+
+       // ClassWizard generated virtual function overrides
+       //{{AFX_VIRTUAL(CPkgadminAboutDlg)
+       protected:
+       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+       //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+       //{{AFX_MSG(CPkgadminAboutDlg)
+       //}}AFX_MSG
+       DECLARE_MESSAGE_MAP()
+};
+
+CPkgadminAboutDlg::CPkgadminAboutDlg() : CDialog(CPkgadminAboutDlg::IDD)
+{
+       //{{AFX_DATA_INIT(CPkgadminAboutDlg)
+       //}}AFX_DATA_INIT
+}
+
+void CPkgadminAboutDlg::DoDataExchange(CDataExchange* pDX)
+{
+       CDialog::DoDataExchange(pDX);
+       //{{AFX_DATA_MAP(CPkgadminAboutDlg)
+       //}}AFX_DATA_MAP
+}
+
+BEGIN_MESSAGE_MAP(CPkgadminAboutDlg, CDialog)
+       //{{AFX_MSG_MAP(CPkgadminAboutDlg)
+               // No message handlers
+       //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CPkgAdminDlg dialog
+
+CPkgAdminDlg::CPkgAdminDlg(LPCTSTR pszRepository,LPCTSTR pszUserTools)
+       : CeCosDialog(CPkgAdminDlg::IDD, NULL)
+{
+       //{{AFX_DATA_INIT(CPkgAdminDlg)
+               // NOTE: the ClassWizard will add member initialization here
+       //}}AFX_DATA_INIT
+       // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
+  if(pszRepository){
+         m_strRepository=pszRepository;
+  }
+  if(pszUserTools){
+         m_strUserTools=pszUserTools;
+  }
+       m_CdlPkgData = NULL;
+}
+
+void CPkgAdminDlg::DoDataExchange(CDataExchange* pDX)
+{
+       CeCosDialog::DoDataExchange(pDX);
+       //{{AFX_DATA_MAP(CPkgAdminDlg)
+       DDX_Control(pDX, IDC_PKGADMIN_REMOVE, m_btnRemove);
+       DDX_Control(pDX, IDC_PKGADMIN_TREE, m_ctrlPackageTree);
+       //}}AFX_DATA_MAP
+}
+
+BEGIN_MESSAGE_MAP(CPkgAdminDlg, CeCosDialog)
+       //{{AFX_MSG_MAP(CPkgAdminDlg)
+       ON_WM_SYSCOMMAND()
+       ON_WM_PAINT()
+       ON_WM_QUERYDRAGICON()
+       ON_BN_CLICKED(IDC_PKGADMIN_REMOVE, OnPkgadminRemove)
+       ON_WM_DESTROY()
+       ON_BN_CLICKED(IDC_PKGADMIN_ADD, OnPkgadminAdd)
+       ON_BN_CLICKED(IDCLOSE, OnClose)
+       ON_BN_CLICKED(IDC_PKGADMIN_REPOSITORY, OnPkgadminRepository)
+       ON_NOTIFY(TVN_SELCHANGED, IDC_PKGADMIN_TREE, OnSelchangedPkgadminTree)
+       //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CPkgAdminDlg message handlers
+
+BOOL CPkgAdminDlg::OnInitDialog()
+{
+       CeCosDialog::OnInitDialog();
+
+  if(this==AfxGetApp()->m_pMainWnd){ // only if the dialog is the application
+         // Add "About..." menu item to system menu.
+
+         // IDM_ABOUTBOX must be in the system command range.
+         ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
+         ASSERT(IDM_ABOUTBOX < 0xF000);
+
+         CMenu* pSysMenu = GetSystemMenu(FALSE);
+         if (pSysMenu != NULL)
+         {
+                 CString strAboutMenu;
+                 strAboutMenu.LoadString(IDS_ABOUTBOX);
+                 if (!strAboutMenu.IsEmpty())
+                 {
+                         pSysMenu->AppendMenu(MF_SEPARATOR);
+                         pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
+                 }
+         }
+
+       // Set the icon for this dialog.  The framework does this automatically
+       //  when the application's main window is not a dialog
+         SetIcon(m_hIcon, TRUE);                       // Set big icon
+       
+  // The following AppWizard-generated call was causing the 32x32 icon to
+       //  be resized for use as a 16x16 icon. Removing the call causes the
+       //  correct 16x16 icon to be displayed.
+//     SetIcon(m_hIcon, FALSE);                // Set small icon
+       
+       // TODO: Add extra initialization here
+
+       // setup the repsoitory location
+
+         if (m_strRepository.IsEmpty()) // if the repository cannot be located
+         {
+                 OnPkgadminRepository (); // prompt the user for the repository location
+                 if (m_strRepository.IsEmpty ())
+                 {
+                         PostMessage (WM_COMMAND,IDCANCEL);
+                         return TRUE;
+                 }
+         }
+  } else {
+    GetDlgItem(IDC_PKGADMIN_REPOSITORY)->ShowWindow(SW_HIDE);
+  }
+
+       // setup the path to the user tools (tar and gunzip)
+
+       if ((! m_strUserTools.IsEmpty()) || FindUserToolsPath ()) // if the user tools can be located
+       {
+               // add the user tools to the PATH environment variable
+               const DWORD nLength = GetEnvironmentVariable (_T("PATH"), NULL, 0) + 1;
+               TCHAR * pszOldPath  = new TCHAR [nLength];
+               GetEnvironmentVariable (_T("PATH"), pszOldPath, nLength);
+               SetEnvironmentVariable (_T("PATH"), CString (pszOldPath) + _T(";") + m_strUserTools);
+               delete [] pszOldPath;
+       }
+
+       // setup the package tree image list
+
+       m_ilTreeIcons.Create (IDB_PKGADMIN_TREEICONS, 16, 1, RGB (0,128,128));
+       m_ctrlPackageTree.SetImageList (&m_ilTreeIcons, TVSIL_NORMAL);
+
+       // populate the package tree
+
+       while (! PopulatePackageTree (m_strRepository))
+       {
+               m_strRepository = _T("");
+               OnPkgadminRepository (); // prompt the user for the repository location
+               if (m_strRepository.IsEmpty ()) // if dialog was cancelled
+               {
+                       PostQuitMessage (1);
+                       return TRUE;
+               }
+       }
+       
+       return TRUE;  // return TRUE  unless you set the focus to a control
+}
+
+void CPkgAdminDlg::OnSysCommand(UINT nID, LPARAM lParam)
+{
+       if ((nID & 0xFFF0) == IDM_ABOUTBOX)
+       {
+               CPkgadminAboutDlg dlgAbout;
+               dlgAbout.DoModal();
+       }
+       else
+       {
+               CeCosDialog::OnSysCommand(nID, lParam);
+       }
+}
+
+// If you add a minimize button to your dialog, you will need the code below
+//  to draw the icon.  For MFC applications using the document/view model,
+//  this is automatically done for you by the framework.
+
+void CPkgAdminDlg::OnPaint() 
+{
+       if (IsIconic())
+       {
+               CPaintDC dc(this); // device context for painting
+
+               SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
+
+               // Center icon in client rectangle
+               int cxIcon = GetSystemMetrics(SM_CXICON);
+               int cyIcon = GetSystemMetrics(SM_CYICON);
+               CRect rect;
+               GetClientRect(&rect);
+               int x = (rect.Width() - cxIcon + 1) / 2;
+               int y = (rect.Height() - cyIcon + 1) / 2;
+
+               // Draw the icon
+               dc.DrawIcon(x, y, m_hIcon);
+       }
+       else
+       {
+               CeCosDialog::OnPaint();
+       }
+}
+
+// The system calls this to obtain the cursor to display while the user drags
+//  the minimized window.
+HCURSOR CPkgAdminDlg::OnQueryDragIcon()
+{
+       return (HCURSOR) m_hIcon;
+}
+
+// Trivial handlers; otherwise CdlPackagesDatabaseBody::make asserts.
+void CdlErrorHandler (std::string message)
+{
+};
+
+void CdlWarningHandler (std::string message)
+{
+};
+
+
+bool CPkgAdminDlg::PopulatePackageTree(LPCTSTR pszPackagesPath)
+{
+       // delete any existing CDL database
+
+       if (m_CdlPkgData)
+       {
+               delete m_CdlPkgData;
+               m_CdlPkgData = NULL;
+       }
+
+       // load the package database
+
+       try
+       {
+        // Cdl asserts unless the handlers are present.
+#if 1
+        m_CdlPkgData = CdlPackagesDatabaseBody::make (UnicodeToStdStr (pszPackagesPath), &CdlErrorHandler, &CdlWarningHandler);
+#else
+        m_CdlPkgData = CdlPackagesDatabaseBody::make (UnicodeToStdStr (pszPackagesPath));
+#endif
+       }
+       catch (CdlStringException exception)
+       {
+               CString strMessage;
+               strMessage.Format (_T("Error loading database:\n\n%s"), CString (exception.get_message ().c_str ()));
+               AfxMessageBox (strMessage);
+               return false;
+       }
+       catch (...)
+       {
+               AfxMessageBox (_T("Error loading database"));
+               return false;
+       }
+
+       // clear the old package tree
+
+       ClearPackageTree ();
+
+       // populate the new package tree
+
+       const std::vector<std::string>& packages = m_CdlPkgData->get_packages ();
+       for (std::vector<std::string>::const_iterator package = packages.begin (); package != packages.end (); package++)
+       {
+               // add a package node
+
+               TRACE (_T("Adding package %s:"), CString (package->c_str ()));
+               HTREEITEM hPackage = m_ctrlPackageTree.InsertItem (CString (m_CdlPkgData->get_package_aliases (*package) [0].c_str ()));
+               m_ctrlPackageTree.SetItemData (hPackage, (DWORD) new CString (package->c_str ()));
+               m_ctrlPackageTree.SetItemImage (hPackage, 0, 0);
+
+               const std::vector<std::string>& versions = m_CdlPkgData->get_package_versions (* package);
+               for (std::vector<std::string>::const_iterator version = versions.begin (); version != versions.end (); version++)
+               {
+                       // add a version node
+
+                       TRACE (_T(" %s"), CString (version->c_str ()));
+                       const HTREEITEM hVersion = m_ctrlPackageTree.InsertItem (CString (version->c_str ()), hPackage);
+                       m_ctrlPackageTree.SetItemImage (hVersion, 1, 1);
+               }
+               TRACE (_T("\n"));
+               m_ctrlPackageTree.SortChildren (hPackage); // sort the version nodes
+       }
+
+       m_ctrlPackageTree.SortChildren (NULL); // sort the package nodes
+
+  if(this==AfxGetApp()->m_pMainWnd){ // if the dialog is the application
+         // update the caption bar
+         CString strCaption (m_strRepository);
+         strCaption.Replace (_TCHAR('/'), _TCHAR('\\'));
+         strCaption += _T(" - eCos Package Administration Tool");
+         SetWindowText (strCaption);
+  }
+
+       return true;
+}
+
+void CPkgAdminDlg::OnPkgadminRemove() 
+{
+       const HTREEITEM hTreeItem = m_ctrlPackageTree.GetSelectedItem ();
+       if (! hTreeItem)
+               return;
+
+       if (IDYES != CWnd::MessageBox (_T("The selected package will be deleted from the repository. Core eCos packages may be restored only by reinstalling eCos.\n\nDo you wish to continue?"),
+               _T("Remove Package"), MB_YESNO | MB_ICONEXCLAMATION))
+               return;
+
+       const CString * pstrPackage = (const CString *) m_ctrlPackageTree.GetItemData (hTreeItem);
+       if (pstrPackage) // if a package node is selected
+       {
+               // remove all package version nodes
+
+               bool bStatus = true;
+               HTREEITEM hChildItem = m_ctrlPackageTree.GetChildItem (hTreeItem);
+               while (hChildItem && bStatus)
+               {
+                       const HTREEITEM hNextChildItem = m_ctrlPackageTree.GetNextSiblingItem (hChildItem);                     
+                       bStatus = RemovePackageVersion (hChildItem);
+                       hChildItem = hNextChildItem;
+               }
+
+               // remove the package node
+
+               if (bStatus)
+               {
+                       delete pstrPackage;
+                       m_ctrlPackageTree.DeleteItem (hTreeItem);
+               }
+       }
+       else // a version node is selected
+       {
+               // remove the version node
+
+               const HTREEITEM hParentItem = m_ctrlPackageTree.GetParentItem (hTreeItem);
+               ASSERT (hParentItem);
+               if (RemovePackageVersion (hTreeItem) && ! m_ctrlPackageTree.ItemHasChildren (hParentItem)) // if the only version was deleted
+               {
+                       // remove the package node
+
+                       delete pstrPackage;
+                       m_ctrlPackageTree.DeleteItem (hParentItem); 
+               }
+       }
+}
+
+void CPkgAdminDlg::ClearPackageTree()
+{
+       HTREEITEM hPackage = m_ctrlPackageTree.GetRootItem ();
+       if (! hPackage) // if no packages in the tree...
+               return;     // ...nothing to do
+
+       while (hPackage)
+       {
+               const HTREEITEM hNextPackage = m_ctrlPackageTree.GetNextSiblingItem (hPackage);
+               TRACE (_T("Deleting package %s\n"), * ((CString *) m_ctrlPackageTree.GetItemData (hPackage)));
+               delete (CString *) m_ctrlPackageTree.GetItemData (hPackage);
+               m_ctrlPackageTree.DeleteItem (hPackage);
+               hPackage = hNextPackage;
+       }
+}
+
+void CPkgAdminDlg::OnDestroy() 
+{
+       CeCosDialog::OnDestroy();
+       
+       // free memory allocated to the tree item data CStrings
+
+       ClearPackageTree ();
+
+       // free memory allocated to the CDL database
+
+       if (m_CdlPkgData)
+               delete m_CdlPkgData;
+
+}
+
+void CPkgAdminDlg::OnPkgadminAdd() 
+{
+       CFileDialog dlg (TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT, _T("eCos Package Files (*.epk)|*.epk||"), GetParent ());
+       TCHAR szBuffer [MAX_PATH * 16] = _T("");
+       dlg.m_ofn.lpstrFile = szBuffer;
+       dlg.m_ofn.nMaxFile = MAX_PATH * 16;
+       dlg.m_ofn.lpstrTitle = _T("Open eCos Package Files");
+       if (IDOK == dlg.DoModal ())
+       {
+               bool bRepositoryChanged = false;
+               POSITION posPathName = dlg.GetStartPosition ();
+               while (posPathName)
+               {
+                       // get an eCos package distribution file
+
+                       CString strPathName = dlg.GetNextPathName (posPathName);
+
+                       // extract the licence file
+
+                       CString strCommand;
+                       strCommand.Format (_T("add %s --extract_license"), strPathName);
+                       strCommand.Replace (_TCHAR('\\'), _TCHAR('/')); // backslashes -> forward slashes for Tcl_EvalFile
+                       EvalTclFile (3, strCommand);
+                       CString strLicenseFile = m_strRepository + _T("/pkgadd.txt");
+                       strLicenseFile.Replace (_TCHAR('/'), _TCHAR('\\')); // forward slashes -> backslashes for Win32
+
+                       // read the license file
+
+                       CFile fileLicenseFile;
+                       if (fileLicenseFile.Open (strLicenseFile, CFile::modeRead))
+                       {
+                               TRACE (_T("License file found at %s\n"), strLicenseFile);
+                               const DWORD dwLicenseLength = fileLicenseFile.GetLength ();
+                               char * pszBuffer = new char [dwLicenseLength + 1]; // allocate a buffer
+                               fileLicenseFile.Read (pszBuffer, dwLicenseLength);
+                               fileLicenseFile.Close ();
+                               CFile::Remove (strLicenseFile); // delete the license file when read
+                               pszBuffer [dwLicenseLength] = NULL; // terminate the string in the buffer
+                               CString strLicenseText (pszBuffer); // copy into a CString to convert to Unicode
+                               delete [] pszBuffer;
+                               if (-1 == strLicenseText.Find (_T("\r\n"))) // if the file has LF line endings...
+                                       strLicenseText.Replace (_T("\n"), _T("\r\n")); // ... replace with CRLF line endings
+
+                               // display the license text
+
+                               CPkgAdminLicenseDlg dlgLicense (this);
+                               dlgLicense.m_strLicense = strLicenseText;
+                               dlgLicense.SetCaption (strPathName + _T(" - Add Packages"));
+                               if (IDOK != dlgLicense.DoModal ()) // if license not accepted by user
+                                       continue; // try the next file
+                       }
+
+                       // add the contents of the package distribution file
+
+                       strCommand.Format (_T("add %s --accept_license"), strPathName);
+                       strCommand.Replace (_TCHAR('\\'), _TCHAR('/')); // backslashes -> forward slashes for Tcl_EvalFile
+                       if (! EvalTclFile (3, strCommand))  // if not successful
+                               continue; // try the next file
+
+                       bRepositoryChanged = true;
+               }
+
+               // refresh the package tree only if necessary
+
+               if (bRepositoryChanged && ! PopulatePackageTree (m_strRepository))
+                       DestroyWindow ();
+       }
+}
+
+bool CPkgAdminDlg::EvalTclFile(int nArgc, LPCTSTR pszArgv)
+{
+       CPkgAdminTclWaitDlg dlgWait;
+
+       TRACE (_T("Evaluating ecosadmin.tcl %s\n"), pszArgv);
+
+       // set up the data structure which is passed to the Tcl thread
+
+       CString strArgc;
+       strArgc.Format (_T("%d"), nArgc);
+       std::string argv0 = UnicodeToStdStr (m_strRepository) + "/ecosadmin.tcl";
+       std::string argv = UnicodeToStdStr (pszArgv);
+       std::string argc = UnicodeToStdStr (strArgc);
+       dlgWait.etsInfo.argv0 = (char *) argv0.c_str ();
+       dlgWait.etsInfo.argv = (char *) argv.c_str ();
+       dlgWait.etsInfo.argc = (char *) argc.c_str ();
+
+       // display the 'please wait' dialog
+       // the Tcl command is invoked from CPkgAdminTclWaitDlg::OnCreate()
+
+       CWaitCursor curWait;
+       dlgWait.DoModal ();
+       curWait.Restore ();
+
+       // retrieve status information from the data structure
+
+       int nStatus = dlgWait.etsInfo.status;
+       CString strErrorMessage (dlgWait.etsInfo.result);
+
+       // report any error
+
+       if (! strErrorMessage.IsEmpty ())
+       {
+               AfxMessageBox (_T("Command execution error:\n\n") + strErrorMessage);
+               return false;
+       }
+       else if (TCL_OK != nStatus)
+       {
+               AfxMessageBox (_T("Command execution error"));
+               return false;
+       }
+
+       return true;
+}
+
+bool CPkgAdminDlg::RemovePackageVersion(HTREEITEM hTreeItem)
+{
+       const HTREEITEM hParentItem = m_ctrlPackageTree.GetParentItem (hTreeItem);
+       ASSERT (hParentItem);
+       CString * pstrPackage = (CString *) m_ctrlPackageTree.GetItemData (hParentItem);
+       ASSERT (pstrPackage);
+       CString strCommand;
+       strCommand.Format (_T("remove %s --version %s"), * pstrPackage, m_ctrlPackageTree.GetItemText (hTreeItem));
+       if (! EvalTclFile (3, strCommand)) // if not successful
+               return false;
+       
+       m_ctrlPackageTree.DeleteItem (hTreeItem); // remove the selected item from the tree
+       return true;
+}
+
+void CPkgAdminDlg::OnPkgadminRepository() 
+{
+       CFileDialog dlg (TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, _T("eCos Package Database Files (ecos.db)|ecos.db||"), GetParent ());
+       dlg.m_ofn.lpstrTitle = _T("Open eCos Package Database File");
+
+       int nStatus;
+       do
+       {
+               nStatus = dlg.DoModal ();
+               if (IDOK == nStatus)
+               {
+                       const CString strPathName = dlg.GetPathName ();
+                       const int nPathNameIndex = strPathName.ReverseFind (_TCHAR('\\'));
+                       ASSERT (nPathNameIndex != -1);
+                       m_strRepository = strPathName.Mid (0, nPathNameIndex);
+                       m_strRepository.Replace (_TCHAR('\\'), _TCHAR('/'));
+               }
+       }
+       while ((IDOK == nStatus) && ! PopulatePackageTree (m_strRepository));
+}
+
+void CPkgAdminDlg::OnSelchangedPkgadminTree(NMHDR*, LRESULT* pResult) 
+{
+       //NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
+
+       // enable the remove button only if a node is selected
+       m_btnRemove.EnableWindow (NULL != m_ctrlPackageTree.GetSelectedItem ());
+
+       *pResult = 0;
+}
+
+std::string CPkgAdminDlg::UnicodeToStdStr(LPCTSTR str)
+{
+       int nLength = 1 + _tcslen (str);
+       char * pszString = new char [nLength];
+
+       #ifdef _UNICODE
+       WideCharToMultiByte (CP_ACP, 0, str, -1, pszString, nLength, NULL, NULL);
+       #else
+       strcpy (pszString, str);
+       #endif
+
+       std::string stdstr = std::string (pszString);
+       delete [] pszString;
+       return stdstr;
+}
+
+bool CPkgAdminDlg::FindUserToolsPath()
+{
+       HKEY hKey;
+       if (ERROR_SUCCESS != RegOpenKeyEx (HKEY_CURRENT_USER, _T("Software\\Red Hat\\eCos\\Configuration Tool\\User Tools"), 0, KEY_READ, &hKey))
+               return false;
+       
+       TCHAR szBuffer [MAX_PATH + 1];
+       DWORD dwBufferLength = MAX_PATH + 1;
+       LONG lStatus = RegQueryValueEx (hKey, _T("Folder"), NULL, NULL, (LPBYTE) szBuffer, &dwBufferLength);
+       RegCloseKey (hKey);
+       if (ERROR_SUCCESS != lStatus)
+               return false;
+
+       m_strUserTools = szBuffer;
+       TRACE (_T("User tools found at %s\n"), m_strUserTools);
+       return ! m_strUserTools.IsEmpty ();
+}