550 lines
16 KiB
C++
550 lines
16 KiB
C++
//+---------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1993 - 1997.
|
|
//
|
|
// File: creg.cpp
|
|
//
|
|
// Contents: Implements class CRegistry to wrap registry access
|
|
//
|
|
// Classes:
|
|
//
|
|
// Methods: CRegistry::CRegistry
|
|
// CRegistry::~CRegistry
|
|
// CRegistry::Init
|
|
// CRegistry::InitGetItem
|
|
// CRegistry::GetNextItem
|
|
// CRegistry::GetItem
|
|
// CRegistry::FindItem
|
|
// CRegistry::FindAppid
|
|
// CRegistry::AppendIndex
|
|
// CRegistry::GetNumItems
|
|
//
|
|
// History: 23-Apr-96 BruceMa Created.
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "resource.h"
|
|
#include "types.h"
|
|
#include "cstrings.h"
|
|
#include "creg.h"
|
|
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
CRegistry::CRegistry(void)
|
|
{
|
|
m_applications.RemoveAll();
|
|
}
|
|
|
|
|
|
CRegistry::~CRegistry(void)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
|
|
// Access and store all application names and associated appid's
|
|
BOOL CRegistry::Init(void)
|
|
{
|
|
int err;
|
|
HKEY hKey;
|
|
DWORD dwSubKey;
|
|
TCHAR szTitle[MAX_PATH];
|
|
TCHAR szAppid[MAX_PATH];
|
|
TCHAR szCLSID[MAX_PATH];
|
|
TCHAR szBuffer[MAX_PATH];
|
|
LONG lSize;
|
|
DWORD dwType;
|
|
DWORD dwDisposition;
|
|
|
|
// Cleanup any previous run
|
|
m_applications.RemoveAll();
|
|
|
|
|
|
// First enumerate HKEY_CLASSES_ROOT\CLSID picking up all .exe
|
|
|
|
// Open HKEY_CLASSES_ROOT\CLSID
|
|
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"), 0, KEY_READ | KEY_WRITE,
|
|
&hKey) != ERROR_SUCCESS)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Enumerate the CLSID subkeys
|
|
dwSubKey = 0;
|
|
while (RegEnumKey(hKey, dwSubKey, szCLSID, sizeof(szCLSID) / sizeof(TCHAR))
|
|
== ERROR_SUCCESS)
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
HKEY hKey2;
|
|
SRVTYPE srvType;
|
|
|
|
// Prepare for next key
|
|
dwSubKey++;
|
|
|
|
// Open this key
|
|
if (RegOpenKeyEx(hKey, szCLSID, 0, KEY_READ | KEY_WRITE,
|
|
&hKey2) == ERROR_SUCCESS)
|
|
{
|
|
// Check for subkeys "LocalServer32", "_LocalServer32",
|
|
// "LocalServer", and "_LocalServer"
|
|
lSize = MAX_PATH * sizeof(TCHAR);
|
|
err = RegQueryValue(hKey2, TEXT("LocalServer32"), szPath,
|
|
&lSize);
|
|
srvType = LOCALSERVER32;
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
lSize = MAX_PATH * sizeof(TCHAR);
|
|
err = RegQueryValue(hKey2, TEXT("_LocalServer32"), szPath,
|
|
&lSize);
|
|
srvType = _LOCALSERVER32;
|
|
}
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
lSize = MAX_PATH * sizeof(TCHAR);
|
|
err = RegQueryValue(hKey2, TEXT("LocalServer"), szPath,
|
|
&lSize);
|
|
srvType = LOCALSERVER;
|
|
}
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
lSize = MAX_PATH * sizeof(TCHAR);
|
|
err = RegQueryValue(hKey2, TEXT("_LocalServer"), szPath,
|
|
&lSize);
|
|
srvType = _LOCALSERVER;
|
|
}
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hKey2);
|
|
continue;
|
|
}
|
|
|
|
// Strip off any command line parameters -
|
|
// it's the executale path that determines an item. Because
|
|
// of quotes, embedded spaces, etc. we scan for ".exe"
|
|
int k = 0;
|
|
|
|
// szPath is executable path
|
|
while (szPath[k])
|
|
{
|
|
if (szPath[k] == TEXT('.') &&
|
|
szPath[k + 1] && (szPath[k + 1] == TEXT('e') ||
|
|
szPath[k + 1] == TEXT('E')) &&
|
|
szPath[k + 2] && (szPath[k + 2] == TEXT('x') ||
|
|
szPath[k + 2] == TEXT('X')) &&
|
|
szPath[k + 3] && (szPath[k + 3] == TEXT('e') ||
|
|
szPath[k + 3] == TEXT('E')))
|
|
{
|
|
break;
|
|
}
|
|
|
|
k++;
|
|
}
|
|
|
|
// Just continue if we don't have an .exe path
|
|
if (!szPath[k])
|
|
{
|
|
RegCloseKey(hKey2);
|
|
continue;
|
|
}
|
|
|
|
// Increment to the nominal end of the path
|
|
k += 4;
|
|
|
|
// In case the entire path is surrounded by quotes
|
|
if (szPath[k] == TEXT('"'))
|
|
{
|
|
k++;
|
|
}
|
|
szPath[k] = TEXT('\0');
|
|
|
|
// Read the AppID for this clsid (if any)
|
|
BOOL fUseThisClsid = FALSE;
|
|
|
|
lSize = MAX_PATH * sizeof(TCHAR);
|
|
if (RegQueryValueEx(hKey2, TEXT("AppID"), NULL, &dwType,
|
|
(UCHAR *) szAppid, (ULONG *) &lSize)
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
// Use this clsid as the appid
|
|
fUseThisClsid = TRUE;
|
|
}
|
|
|
|
// If this is a 16-bit server without an existing AppId
|
|
// named value then skip it
|
|
if ((srvType == LOCALSERVER || srvType == _LOCALSERVER) &&
|
|
fUseThisClsid == TRUE)
|
|
{
|
|
RegCloseKey(hKey2);
|
|
continue;
|
|
}
|
|
|
|
// Read the title for the item
|
|
BOOL fNoTitle = FALSE;
|
|
|
|
lSize = MAX_PATH * sizeof(TCHAR);
|
|
if (RegQueryValueEx(hKey2, NULL, NULL, &dwType,
|
|
(UCHAR *) szTitle, (ULONG *) &lSize)
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
fNoTitle = TRUE;
|
|
}
|
|
else if (szTitle[0] == TEXT('\0'))
|
|
{
|
|
fNoTitle = TRUE;
|
|
}
|
|
|
|
// If both the item (the executable path) and the title
|
|
// (the unnamed value on the CLSID) are empty, then skip
|
|
// this entry
|
|
if (szPath[0] == TEXT('\0') &&
|
|
(fNoTitle || szTitle[0] == TEXT('\0')))
|
|
{
|
|
RegCloseKey(hKey2);
|
|
continue;
|
|
}
|
|
|
|
// Check whether we already have this item in the table - we
|
|
// search differently depending on whether this clsid already
|
|
// has an associated appid
|
|
SItem *pItem;
|
|
|
|
if (fUseThisClsid)
|
|
{
|
|
// check if application is in list
|
|
pItem = FindItem(szPath);
|
|
}
|
|
else
|
|
{
|
|
pItem = FindAppid(szAppid);
|
|
}
|
|
|
|
if (pItem == NULL)
|
|
{
|
|
// Create a new item
|
|
// szPath is path, szCLSID is CLSID
|
|
pItem = m_applications.PutItem(szPath[0] ? szPath : szCLSID,
|
|
fNoTitle ? szCLSID : szTitle,
|
|
fUseThisClsid ? szCLSID : szAppid);
|
|
if (pItem == NULL)
|
|
{
|
|
RegCloseKey(hKey2);
|
|
RegCloseKey(hKey);
|
|
return FALSE;
|
|
}
|
|
|
|
// Note whether the clsid had an appid named value
|
|
pItem->fHasAppid = !fUseThisClsid;
|
|
}
|
|
|
|
// Write the AppId for this class if it doesn't exist
|
|
lSize = MAX_PATH * sizeof(TCHAR);
|
|
if (RegQueryValueEx(hKey2, TEXT("AppID"), 0, &dwType,
|
|
(BYTE *) szBuffer, (ULONG *) &lSize)
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
if (RegSetValueEx(hKey2, TEXT("AppID"), 0, REG_SZ,
|
|
(const BYTE *) (LPCTSTR)pItem->szAppid,
|
|
(pItem->szAppid.GetLength() + 1) * sizeof(TCHAR))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hKey2);
|
|
RegCloseKey(hKey);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// Now add this clsid to the table of clsid's for this .exe
|
|
if (!m_applications.AddClsid(pItem, szCLSID))
|
|
{
|
|
RegCloseKey(hKey2);
|
|
RegCloseKey(hKey);
|
|
return FALSE;
|
|
}
|
|
|
|
// Close the key
|
|
RegCloseKey(hKey2);
|
|
}
|
|
} // End of the enumeration over HKEY_CLASSES_ROOT\CLSID
|
|
|
|
// Close the key on HKEY_CLASSES_ROOT\CLSID
|
|
RegCloseKey(hKey);
|
|
|
|
|
|
|
|
// Create or open the key "HKEY_CLASSES_ROOT\AppID"
|
|
if (RegCreateKeyEx(HKEY_CLASSES_ROOT, TEXT("AppID"), 0, NULL,
|
|
REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey,
|
|
&dwDisposition) != ERROR_SUCCESS)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Enumerate keys under HKEY_CLASSES_ROOT\AppID
|
|
dwSubKey = 0;
|
|
while (RegEnumKey(hKey, dwSubKey, szCLSID, sizeof(szCLSID) / sizeof(TCHAR)) == ERROR_SUCCESS)
|
|
{
|
|
// Prepare for next key
|
|
dwSubKey++;
|
|
|
|
// Only look at entries having an AppId format
|
|
if (!(szCLSID[0] == TEXT('{') &&
|
|
_tcslen(szCLSID) == GUIDSTR_MAX &&
|
|
szCLSID[37] == TEXT('}')))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Check if this appid is already in the table
|
|
SItem *pItem = FindAppid(szCLSID);
|
|
|
|
// read title
|
|
TCHAR szTitle[MAX_PATH];
|
|
long lSize = MAX_PATH * sizeof(TCHAR);
|
|
|
|
// Read its unnamed value as the title
|
|
szTitle[0] = TEXT('\0');
|
|
err = RegQueryValue(hKey, szCLSID, szTitle, &lSize);
|
|
|
|
// If not create an item entry so it can be displayed in the UI
|
|
if (pItem == NULL)
|
|
{
|
|
// Store this item
|
|
pItem = m_applications.PutItem(NULL,
|
|
szTitle[0] ? szTitle : szCLSID,
|
|
szCLSID);
|
|
if (pItem == NULL)
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// ronans - bugfix for raided bug
|
|
// change existing item title to AppID title if there is one
|
|
if ((err == ERROR_SUCCESS) && szTitle[0])
|
|
{
|
|
pItem -> szTitle = (LPCTSTR)szTitle;
|
|
}
|
|
}
|
|
|
|
// Mark it so we don't rewrite it to HKEY_CLASSES_ROOT\AppID
|
|
pItem->fMarked = TRUE;
|
|
} // End enumeration of HKEY_CLASSES_ROOT\AppID
|
|
|
|
|
|
|
|
// Enumerate through the table of items, writing to HKEY_CLASSES_ROOT\AppID
|
|
// any items that are not marked
|
|
SItem *pItem;
|
|
|
|
m_applications.InitGetNext();
|
|
for (pItem = GetNextItem(); pItem; pItem = GetNextItem())
|
|
{
|
|
HKEY hKey2;
|
|
|
|
// If this item has an AppID but is unmarked, then ask the user
|
|
// whether he really wants to create the AppID
|
|
if (!pItem->fMarked && pItem->fHasAppid)
|
|
{
|
|
CString szMessage;
|
|
CString szDCOM_;
|
|
CString szNULL;
|
|
TCHAR szText[MAX_PATH*2];
|
|
TCHAR *szParms[3];
|
|
|
|
szMessage.LoadString(IDS_CLSID_);
|
|
szDCOM_.LoadString(IDS_DCOM_Configuration_Warning);
|
|
szNULL.LoadString(IDS_NULL);
|
|
|
|
szParms[0] = pItem->ppszClsids[0];
|
|
szParms[1] = !pItem->szItem.IsEmpty() ? (TCHAR *) ((LPCTSTR)pItem->szItem)
|
|
: (TCHAR *) ((LPCTSTR) szNULL);
|
|
szParms[2] = !pItem->szTitle.IsEmpty() ? (TCHAR *) ((LPCTSTR)pItem->szTitle)
|
|
: (TCHAR *) ((LPCTSTR) szNULL);
|
|
|
|
FormatMessage(FORMAT_MESSAGE_FROM_STRING |
|
|
FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
(TCHAR *) ((LPCTSTR) szMessage),
|
|
0,
|
|
0,
|
|
szText,
|
|
MAX_PATH*2 * sizeof(TCHAR),
|
|
(va_list *) szParms);
|
|
|
|
if (MessageBox(GetForegroundWindow(),
|
|
szText,
|
|
(TCHAR *) ((LPCTSTR) szDCOM_),
|
|
MB_YESNO) == IDNO)
|
|
{
|
|
pItem->fMarked = TRUE;
|
|
pItem->fDontDisplay = TRUE;
|
|
}
|
|
}
|
|
|
|
// If this item is not marked then, then create an appid key for
|
|
// it under HKEY_CLASSES_ROOT\AppID and, separately, write the
|
|
// .exe name under HKEY_CLASSES_ROOT\AppID
|
|
if (!pItem->fMarked)
|
|
{
|
|
if (RegCreateKeyEx(hKey, pItem->szAppid, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey2,
|
|
&dwDisposition) == ERROR_SUCCESS)
|
|
{
|
|
// Write the item title as the unnamed value
|
|
if (!pItem->szTitle.IsEmpty())
|
|
{
|
|
RegSetValueEx(hKey2, NULL, 0, REG_SZ,(BYTE *) (LPCTSTR) pItem->szTitle,
|
|
(pItem->szTitle.GetLength() + 1) * sizeof(TCHAR));
|
|
}
|
|
|
|
// Close it
|
|
RegCloseKey(hKey2);
|
|
|
|
|
|
// Write the .exe name if it's not empty
|
|
if (!(pItem->szItem.IsEmpty()))
|
|
{
|
|
// Extract the .exe name
|
|
int k = pItem->szItem.ReverseFind(TEXT('\\'));
|
|
CString szExe = pItem->szItem.Mid((k != -1) ? k+1 : 0);
|
|
|
|
// remove trailing quotes on executable name if necessary
|
|
k = szExe.GetLength();
|
|
if (k && (szExe.GetAt(k-1) == TEXT('\"')))
|
|
szExe = szExe.Left(k-1);
|
|
|
|
// Write the .exe name as a key
|
|
if (RegCreateKeyEx(hKey, (LPCTSTR)szExe, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey2,
|
|
&dwDisposition) == ERROR_SUCCESS)
|
|
{
|
|
// Now write the associated AppId as a named value
|
|
RegSetValueEx(hKey2, TEXT("AppId"), 0, REG_SZ,
|
|
(BYTE *)(LPCTSTR) pItem->szAppid,
|
|
(pItem->szAppid.GetLength() + 1) * sizeof(TCHAR));
|
|
|
|
RegCloseKey(hKey2);
|
|
}
|
|
}
|
|
}
|
|
else // dont continue on failure
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Close the key on HKEY_CLASSES_ROOT\AppID
|
|
RegCloseKey(hKey);
|
|
|
|
|
|
// We display applications by their titles (e.g. "Microsoft Word 6.0")
|
|
// which have to be unique because we're going to uniquely associate
|
|
// an entry in the list box with the index of its associated SItem
|
|
// structure. So here we make sure all the titles are unique.
|
|
DWORD cbItems = m_applications.GetNumItems();
|
|
|
|
// Compare all non-empty titles of the same length. If they are
|
|
// not unique, then append "(<index>)" to make them unique
|
|
for (DWORD k = 0; k < cbItems; k++)
|
|
{
|
|
DWORD dwIndex = 1;
|
|
SItem *pItem = m_applications.GetItem(k);
|
|
|
|
if (!(pItem->szTitle.IsEmpty()) && !pItem->fChecked)
|
|
{
|
|
for (DWORD j = k + 1; j < cbItems; j++)
|
|
{
|
|
SItem *pItem2 = m_applications.GetItem(j);
|
|
|
|
if (!pItem2->fChecked &&
|
|
(pItem->szTitle == pItem2->szTitle))
|
|
{
|
|
if (dwIndex == 1)
|
|
{
|
|
AppendIndex(pItem, 1);
|
|
dwIndex++;
|
|
}
|
|
AppendIndex(pItem2, dwIndex++);
|
|
pItem2->fChecked = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Prepare for the UI enumerating item entries
|
|
m_applications.InitGetNext();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL CRegistry::InitGetItem(void)
|
|
{
|
|
return m_applications.InitGetNext();
|
|
}
|
|
|
|
|
|
|
|
|
|
// Enumerate the next application name
|
|
SItem *CRegistry::GetNextItem(void)
|
|
{
|
|
return m_applications.GetNextItem();
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get a specific item
|
|
SItem *CRegistry::GetItem(DWORD dwItem)
|
|
{
|
|
return m_applications.GetItem(dwItem);
|
|
}
|
|
|
|
|
|
|
|
SItem *CRegistry::FindItem(TCHAR *szPath)
|
|
{
|
|
return m_applications.FindItem(szPath);
|
|
}
|
|
|
|
|
|
|
|
SItem *CRegistry::FindAppid(TCHAR *szAppid)
|
|
{
|
|
return m_applications.FindAppid(szAppid);
|
|
}
|
|
|
|
|
|
|
|
|
|
void CRegistry::AppendIndex(SItem *pItem, DWORD dwIndex)
|
|
{
|
|
CString szTmp;
|
|
szTmp.Format(TEXT(" (%d)"),dwIndex);
|
|
|
|
pItem->szTitle += szTmp;
|
|
}
|
|
|
|
|
|
|
|
DWORD CRegistry::GetNumItems(void)
|
|
{
|
|
return m_applications.GetNumItems();
|
|
}
|