Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1316 lines
37 KiB

//+----------------------------------------------------------------------------
//
// Windows NT Directory Service Property Pages
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2001
//
// File: misc.cxx, this file is #include'd into the two dllmisc.cxx files.
//
// Contents: DS property pages class objects handler DLL fcns. Also, error
// reporting, message, and miscelaneous functions.
//
// History: 10-May-01 EricB created
//
//-----------------------------------------------------------------------------
#include "pch.h"
#include "proppage.h"
#include "objlist.h"
#if defined(DSPROP_ADMIN)
# include "chklist.h"
# include "fpnw.h"
#endif
#include <time.h>
DECLARE_INFOLEVEL(DsProp);
HINSTANCE g_hInstance = NULL;
ULONG CDll::s_cObjs = 0;
ULONG CDll::s_cLocks = 0;
UINT g_uChangeMsg = 0;
int g_iInstance = 0;
#ifndef DSPROP_ADMIN
CRITICAL_SECTION g_csNotifyCreate;
#endif
ULONG g_ulMemberFilterCount = DSPROP_MEMBER_FILTER_COUNT_DEFAULT;
ULONG g_ulMemberQueryLimit = DSPROP_MEMBER_QUERY_LIMIT_DEFAULT;
#define DIRECTORY_UI_KEY TEXT("Software\\Policies\\Microsoft\\Windows\\Directory UI")
#define MEMBER_QUERY_VALUE TEXT("GroupMemberFilterCount")
#define MEMBER_LIMIT_VALUE TEXT("GroupMemberQueryLimit")
#if defined(DSPROP_ADMIN)
Cache g_FPNWCache;
#endif
HRESULT GlobalInit(void);
void GlobalUnInit(void);
void ReportErrorFallback(HWND hWndMsg, HRESULT hr = ERROR_SUCCESS)
{ ReportError( hr, 0, hWndMsg ); }
//+----------------------------------------------------------------------------
// To set a non-default debug info level outside of the debugger, create the
// below registry key and in it create a value whose name is the component's
// debugging tag name (the "comp" parameter to the DECLARE_INFOLEVEL macro) and
// whose data is the desired infolevel in REG_DWORD format.
//-----------------------------------------------------------------------------
#define SMDEBUGKEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AdminDebug"
#ifndef DSPROP_ADMIN
//+----------------------------------------------------------------------------
//
// Class: CNotifyCreateCriticalSection
//
// Purpose: Prevents creation race conditions. Without this protection,
// a second call to CNotifyObj::Create that comes in before the
// first has created the hidden window will get NULL back from
// FindSheetNoSetFocus and then go on to create a second hidden
// window.
//
//-----------------------------------------------------------------------------
CNotifyCreateCriticalSection::CNotifyCreateCriticalSection()
{
TRACE(CNotifyCreateCriticalSection, CNotifyCreateCriticalSection);
EnterCriticalSection(&g_csNotifyCreate);
};
CNotifyCreateCriticalSection::~CNotifyCreateCriticalSection()
{
TRACE(CNotifyCreateCriticalSection, ~CNotifyCreateCriticalSection);
LeaveCriticalSection(&g_csNotifyCreate);
};
#endif
#define MAX_STRING 1024
//+----------------------------------------------------------------------------
//
// Function: LoadStringToTchar
//
// Synopsis: Loads the given string into an allocated buffer that must be
// caller freed using delete.
//
//-----------------------------------------------------------------------------
BOOL LoadStringToTchar(int ids, PTSTR * pptstr)
{
TCHAR szBuf[MAX_STRING];
if (!LoadString(g_hInstance, ids, szBuf, MAX_STRING - 1))
{
return FALSE;
}
*pptstr = new TCHAR[_tcslen(szBuf) + 1];
CHECK_NULL(*pptstr, return FALSE);
_tcscpy(*pptstr, szBuf);
return TRUE;
}
//+----------------------------------------------------------------------------
// Function: LoadStringReport
// Purpose: attempts to load a string, returns FALSE and gives error message
// if a failure occurs.
//-----------------------------------------------------------------------------
BOOL LoadStringReport(int ids, PTSTR ptz, int len, HWND hwnd)
{
if (!LoadString(g_hInstance, ids, ptz, len - 1))
{
DWORD dwErr = GetLastError();
dspDebugOut((DEB_ERROR, "LoadString of %d failed with error %lu\n",
ids, dwErr));
ReportError(dwErr, 0, hwnd);
return FALSE;
}
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Function: LoadErrorMessage
//
// Synopsis: Attempts to get a user-friendly error message from the system.
//
//-----------------------------------------------------------------------------
void LoadErrorMessage(HRESULT hr, int nStr, PTSTR* pptsz) // free with delete[]
{
dspAssert( NULL != pptsz && NULL == *pptsz );
PTSTR ptzFormat = NULL, ptzSysMsg;
int cch;
if (nStr)
{
LoadStringToTchar(nStr, &ptzFormat);
}
cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(PTSTR)&ptzSysMsg, 0, NULL);
if (!cch)
{
// Try ADSI errors.
//
cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_HMODULE,
GetModuleHandle(TEXT("activeds.dll")), hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(PTSTR)&ptzSysMsg, 0, NULL);
}
if (!cch)
{
PTSTR ptzMsgTemplate = NULL;
BOOL fDelMsgTemplate = TRUE;
LoadStringToTchar(IDS_DEFAULT_ERROR_MSG, &ptzMsgTemplate);
if (NULL == ptzMsgTemplate)
{
ptzMsgTemplate = TEXT("The operation failed with error code %d (0x%08x)");
fDelMsgTemplate = FALSE;
}
*pptsz = new TCHAR[ lstrlen(ptzMsgTemplate)+10 ];
dspAssert( NULL != *pptsz );
if (NULL != *pptsz)
{
wsprintf(*pptsz, ptzMsgTemplate, hr, hr);
}
if (fDelMsgTemplate)
{
delete ptzMsgTemplate;
}
}
else
{
PTSTR ptzMsg;
BOOL fDelMsg = FALSE;
if (ptzFormat)
{
ptzMsg = new TCHAR[lstrlen(ptzFormat) + lstrlen(ptzSysMsg) + 1];
if (ptzMsg)
{
wsprintf(ptzMsg, ptzFormat, ptzSysMsg);
fDelMsg = TRUE;
}
else
{
ptzMsg = ptzSysMsg;
}
}
else
{
ptzMsg = ptzSysMsg;
}
*pptsz = new TCHAR[ lstrlen(ptzMsg)+1 ];
if (NULL != *pptsz)
{
lstrcpy( *pptsz, ptzMsg );
}
dspAssert( NULL != *pptsz );
LocalFree(ptzSysMsg);
if (fDelMsg)
{
delete[] ptzMsg;
}
if (ptzFormat)
{
delete ptzFormat;
}
}
}
//+----------------------------------------------------------------------------
//
// Function: CheckADsError
//
// Synopsis: Checks the result code from an ADSI call.
//
// Returns: TRUE if no error.
//
//-----------------------------------------------------------------------------
BOOL CheckADsError(HRESULT * phr, BOOL fIgnoreAttrNotFound, PSTR file,
int line, HWND hWnd)
{
if (SUCCEEDED(*phr))
{
return TRUE;
}
if (((E_ADS_PROPERTY_NOT_FOUND == *phr) ||
(HRESULT_FROM_WIN32(ERROR_DS_NO_ATTRIBUTE_OR_VALUE) == *phr)) &&
fIgnoreAttrNotFound)
{
*phr = S_OK;
return TRUE;
}
HWND hWndMsg = hWnd;
if (!hWndMsg)
{
hWndMsg = GetDesktopWindow();
}
DWORD dwErr;
WCHAR wszErrBuf[MAX_PATH+1];
WCHAR wszNameBuf[MAX_PATH+1];
ADsGetLastError(&dwErr, wszErrBuf, MAX_PATH, wszNameBuf, MAX_PATH);
if ((LDAP_RETCODE)dwErr == LDAP_NO_SUCH_ATTRIBUTE && fIgnoreAttrNotFound)
{
*phr = S_OK;
return TRUE;
}
if (dwErr)
{
dspDebugOut((DEB_ERROR,
"Extended Error 0x%x: %ws %ws <%s @line %d>.\n", dwErr,
wszErrBuf, wszNameBuf, file, line));
ReportError(dwErr, IDS_ADS_ERROR_FORMAT, hWndMsg);
}
else
{
dspDebugOut((DEB_ERROR, "Error %08lx <%s @line %d>\n", *phr, file, line));
ReportError(*phr, IDS_ADS_ERROR_FORMAT, hWndMsg);
}
return FALSE;
}
//+----------------------------------------------------------------------------
//
// Function: ReportError
//
// Synopsis: Displays an error using a user-friendly error message from the
// system.
//
//-----------------------------------------------------------------------------
void ReportErrorWorker(HWND hWnd, PTSTR ptzMsg)
{
HWND hWndMsg = hWnd;
if (!hWndMsg)
{
hWndMsg = GetDesktopWindow();
}
PTSTR ptzTitle = NULL;
if (!LoadStringToTchar(IDS_MSG_TITLE, &ptzTitle))
{
MessageBox(hWndMsg, ptzMsg, TEXT("Active Directory"), MB_OK | MB_ICONEXCLAMATION);
return;
}
MessageBox(hWndMsg, ptzMsg, ptzTitle, MB_OK | MB_ICONEXCLAMATION);
delete ptzTitle;
}
void ReportError(HRESULT hr, int nStr, HWND hWnd)
{
PTSTR ptzMsg = NULL;
LoadErrorMessage(hr, nStr, &ptzMsg);
if (NULL == ptzMsg)
{
TCHAR tzBuf[80];
wsprintf(tzBuf, TEXT("Active Directory failure with code '0x%08x'!"), hr);
ReportErrorWorker( hWnd, tzBuf );
return;
}
ReportErrorWorker( hWnd, ptzMsg );
delete ptzMsg;
}
#if defined(DSADMIN)
//+----------------------------------------------------------------------------
//
// Function: SuperMsgBox
//
// Synopsis: Displays a message obtained from a string resource with
// the parameters expanded. The error param, dwErr, if
// non-zero, is converted to a string and becomes the first
// replaceable param.
//
// Note: this function is UNICODE-only.
//
//-----------------------------------------------------------------------------
int SuperMsgBox(
HWND hWnd, // owning window.
int nMessageId, // string resource ID of message. Must have replacable params to match nArguments.
int nTitleId, // string resource ID of the title. If zero, uses IDS_MSG_TITLE.
UINT ufStyle, // MessageBox flags.
DWORD dwErr, // Error code, or zero if not needed.
PVOID * rgpvArgs, // array of pointers/values for substitution in the nMessageId string.
int nArguments, // count of pointers in string array.
BOOL fTryADSiErrors,// If the failure is the result of an ADSI call, see if an ADSI extended error.
PSTR szFile, // use the __FILE__ macro. ignored in retail build.
int nLine // use the __LINE__ macro. ignored in retail build.
)
{
CStrW strTitle;
PWSTR pwzMsg = NULL;
strTitle.LoadString(g_hInstance, (nTitleId) ? nTitleId : IDS_MSG_TITLE);
if (0 == strTitle.GetLength())
{
ReportErrorFallback(hWnd, dwErr);
return 0;
}
DspFormatMessage(nMessageId, dwErr, rgpvArgs, nArguments,
fTryADSiErrors, &pwzMsg, hWnd);
if (!pwzMsg)
{
return 0;
}
if (dwErr)
{
dspDebugOut((DEB_ERROR,
"*+*+*+*+* Error <%s @line %d> -> 0x%08x, with message:\n\t%ws\n",
szFile, nLine, dwErr, pwzMsg));
}
else
{
dspDebugOut((DEB_ERROR,
"*+*+*+*+* Message <%s @line %d>:\n\t%ws\n",
szFile, nLine, pwzMsg));
}
int retval = MessageBox(hWnd, pwzMsg, strTitle, ufStyle);
LocalFree(pwzMsg);
return retval;
}
//+----------------------------------------------------------------------------
//
// Function: DspFormatMessage
//
// Synopsis: Loads a string resource with replaceable parameters and uses
// FormatMessage to populate the replaceable params from the
// argument array. If dwErr is non-zero, will load the system
// description for that error and include it in the argument array.
//
//-----------------------------------------------------------------------------
void
DspFormatMessage(
int nMessageId, // string resource ID of message. Must have replacable params to match nArguments.
DWORD dwErr, // Error code, or zero if not needed.
PVOID * rgpvArgs, // array of pointers/values for substitution in the nMessageId string.
int nArguments, // count of pointers in string array.
BOOL fTryADSiErrors,// If the failure is the result of an ADSI call, see if an ADSI extended error.
PWSTR * ppwzMsg, // The returned error string, free with LocalFree.
HWND hWnd // owning window, defaults to NULL.
)
{
int cch;
PWSTR pwzSysErr = NULL;
if (dwErr)
{
if (fTryADSiErrors)
{
DWORD dwStatus;
WCHAR Buf1[256], Buf2[256];
ADsGetLastError(&dwStatus, Buf1, 256, Buf2, 256);
dspDebugOut((DEB_ERROR,
"ADsGetLastError returned status of %lx, error: %s, name %s\n",
dwStatus, Buf1, Buf2));
if ((ERROR_INVALID_DATA != dwStatus) && (0 != dwStatus))
{
dwErr = dwStatus;
}
}
cch = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(PWSTR)&pwzSysErr, 0, NULL);
if (!cch)
{
ReportErrorFallback(hWnd, dwErr);
return;
}
}
PWSTR * rgpvArguments = new PWSTR[nArguments + 1];
if (!rgpvArguments)
{
ReportErrorFallback(hWnd, dwErr);
return;
}
int nOffset = 0;
if (dwErr)
{
rgpvArguments[0] = pwzSysErr;
nOffset = 1;
}
if (0 != nArguments)
{
CopyMemory(rgpvArguments + nOffset, rgpvArgs, nArguments * sizeof(PVOID));
}
CStrW strFormat;
strFormat.LoadString(g_hInstance, nMessageId);
if (0 == strFormat.GetLength())
{
ReportErrorFallback(hWnd, dwErr);
return;
}
cch = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_STRING |
FORMAT_MESSAGE_ARGUMENT_ARRAY, strFormat, 0, 0,
(PWSTR)ppwzMsg, 0, (va_list *)rgpvArguments);
if (pwzSysErr) LocalFree(pwzSysErr);
if (!cch)
{
ReportErrorFallback(hWnd, dwErr);
}
delete[] rgpvArguments;
return;
}
#endif // defined(DSADMIN)
//+----------------------------------------------------------------------------
//
// Function: ErrMsg
//
// Synopsis: Displays an error message obtained from a string resource.
//
//-----------------------------------------------------------------------------
void ErrMsg(UINT MsgID, HWND hWndParam)
{
PTSTR ptz = TEXT("");
ErrMsgParam(MsgID, (LPARAM)ptz, hWndParam);
}
//+----------------------------------------------------------------------------
//
// Function: ErrMsgParam
//
// Synopsis: Displays an error message obtained from a string resource with
// an insertion parameter.
//
// Note: fixed-size stack buffers are used for the strings because trying to
// report an allocation failure using dynamically allocated string
// buffers is not a good idea.
//-----------------------------------------------------------------------------
void ErrMsgParam(UINT MsgID, LPARAM param, HWND hWndParam)
{
HWND hWnd;
if (hWndParam == NULL)
{
hWnd = GetDesktopWindow();
}
else
{
hWnd = hWndParam;
}
TCHAR szTitle[MAX_TITLE+1];
TCHAR szFormat[MAX_ERRORMSG+1];
TCHAR szMsg[MAX_ERRORMSG+1];
LOAD_STRING(IDS_MSG_TITLE, szTitle, MAX_TITLE, MessageBeep(MB_ICONEXCLAMATION); return);
LOAD_STRING(MsgID, szFormat, MAX_ERRORMSG, MessageBeep(MB_ICONEXCLAMATION); return);
wsprintf(szMsg, szFormat, param);
MessageBox(hWnd, szMsg, szTitle, MB_OK | MB_ICONEXCLAMATION);
}
//+----------------------------------------------------------------------------
//
// Function: MsgBox
//
// Synopsis: Displays a message obtained from a string resource.
//
//-----------------------------------------------------------------------------
void MsgBox(UINT MsgID, HWND hWnd)
{
MsgBox2(MsgID, 0, hWnd);
}
//+----------------------------------------------------------------------------
//
// Function: MsgBox2
//
// Synopsis: Displays a message obtained from a string resource which is
// assumed to have a replacable parameter where the InsertID
// string is inserted.
//
//-----------------------------------------------------------------------------
void MsgBox2(UINT MsgID, UINT InsertID, HWND hWnd)
{
CStr strMsg, strFormat, strInsert, strTitle;
if (!strTitle.LoadString(g_hInstance, IDS_MSG_TITLE))
{
REPORT_ERROR(GetLastError(), hWnd);
return;
}
if (!strFormat.LoadString(g_hInstance, MsgID))
{
REPORT_ERROR(GetLastError(), hWnd);
return;
}
if (InsertID)
{
if (!strInsert.LoadString(g_hInstance, InsertID))
{
REPORT_ERROR(GetLastError(), hWnd);
return;
}
strMsg.Format(strFormat, strInsert);
}
else
{
strMsg = strFormat;
}
MessageBox(hWnd, strMsg, strTitle, MB_OK | MB_ICONINFORMATION);
}
//+----------------------------------------------------------------------------
//
// DLL functions
//
//-----------------------------------------------------------------------------
//+----------------------------------------------------------------------------
//
// Function: DllMain
//
// Synopsis: Provide a DllMain for Win32
//
// Arguments: hInstance - HANDLE to this dll
// dwReason - Reason this function was called. Can be
// Process/Thread Attach/Detach.
//
// Returns: BOOL - TRUE if no error, FALSE otherwise
//
// History: 24-May-95 EricB created.
//
//-----------------------------------------------------------------------------
extern "C" BOOL
DllMain(HINSTANCE hInstance, DWORD dwReason, PVOID)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
dspDebugOut((DEB_ITRACE, "DllMain: DLL_PROCESS_ATTACH\n"));
//
// Get instance handle
//
g_hInstance = hInstance;
//
// Disable thread notification from OS
//
//DisableThreadLibraryCalls(hInstance);
HRESULT hr;
//
// Initialize the global values.
//
hr = GlobalInit();
if (FAILED(hr))
{
ERR_OUT("GlobalInit", hr);
return FALSE;
}
break;
case DLL_PROCESS_DETACH:
dspDebugOut((DEB_ITRACE, "DllMain: DLL_PROCESS_DETACH\n"));
GlobalUnInit();
break;
}
return(TRUE);
}
//+----------------------------------------------------------------------------
//
// Function: DllGetClassObject
//
// Synopsis: Creates a class factory for the requested object.
//
// Arguments: [cid] - the requested class object
// [iid] - the requested interface
// [ppvObj] - returned pointer to class object
//
// Returns: HRESULTS
//
//-----------------------------------------------------------------------------
STDAPI
DllGetClassObject(REFCLSID cid, REFIID iid, void **ppvObj)
{
IUnknown *pUnk = NULL;
HRESULT hr = S_OK;
for (int i = 0; i < g_DsPPClasses.cClasses; i++)
{
if (cid == *g_DsPPClasses.rgpClass[i]->pcid)
{
pUnk = CDsPropPagesHostCF::Create(g_DsPPClasses.rgpClass[i]);
if (pUnk != NULL)
{
hr = pUnk->QueryInterface(iid, ppvObj);
pUnk->Release();
}
else
{
return E_OUTOFMEMORY;
}
return hr;
}
}
return E_NOINTERFACE;
}
//+----------------------------------------------------------------------------
//
// Function: DllCanUnloadNow
//
// Synopsis: Indicates whether the DLL can be removed if there are no
// objects in existence.
//
// Returns: S_OK or S_FALSE
//
//-----------------------------------------------------------------------------
STDAPI
DllCanUnloadNow(void)
{
dspDebugOut((DEB_ITRACE, "DllCanUnloadNow: CDll::CanUnloadNow()? %s\n",
(CDll::CanUnloadNow() == S_OK) ? "TRUE" : "FALSE"));
return CDll::CanUnloadNow();
}
TCHAR const c_szServerType[] = TEXT("InProcServer32");
TCHAR const c_szThreadModel[] = TEXT("ThreadingModel");
TCHAR const c_szThreadModelValue[] = TEXT("Apartment");
//+----------------------------------------------------------------------------
//
// Function: DllRegisterServer
//
// Synopsis: Adds entries to the system registry.
//
// Returns: S_OK or error code.
//
// Notes: The keys look like this:
//
// HKC\CLSID\clsid <No Name> REG_SZ name.progid
// \InPropServer32 <No Name> : REG_SZ : adprop.dll/dsprop.dll
// ThreadingModel : REG_SZ : Apartment
//-----------------------------------------------------------------------------
STDAPI
DllRegisterServer(void)
{
HRESULT hr = S_OK;
HKEY hKeyCLSID, hKeyDsPPClass, hKeySvr;
long lRet = RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"), 0,
KEY_WRITE, &hKeyCLSID);
if (lRet != ERROR_SUCCESS)
{
dspDebugOut((DEB_ITRACE, "RegOpenKeyEx failed: %d", lRet));
return (HRESULT_FROM_WIN32(lRet));
}
LPOLESTR pszCLSID;
PTSTR ptzCLSID;
DWORD dwDisposition;
for (int i = 0; i < g_DsPPClasses.cClasses; i++)
{
hr = StringFromCLSID(*g_DsPPClasses.rgpClass[i]->pcid, &pszCLSID);
if (FAILED(hr))
{
DBG_OUT("StringFromCLSID failed");
continue;
}
if (!UnicodeToTchar(pszCLSID, &ptzCLSID))
{
DBG_OUT("Memory Allocation failure!");
CoTaskMemFree(pszCLSID);
hr = E_OUTOFMEMORY;
continue;
}
CoTaskMemFree(pszCLSID);
lRet = RegCreateKeyEx(hKeyCLSID, ptzCLSID, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
&hKeyDsPPClass, &dwDisposition);
delete ptzCLSID;
if (lRet != ERROR_SUCCESS)
{
dspDebugOut((DEB_ITRACE, "RegCreateKeyEx failed: %d", lRet));
hr = HRESULT_FROM_WIN32(lRet);
continue;
}
TCHAR szProgID[MAX_PATH];
_tcscpy(szProgID, c_szDsProppagesProgID);
_tcscat(szProgID, g_DsPPClasses.rgpClass[i]->szProgID);
lRet = RegSetValueEx(hKeyDsPPClass, NULL, 0, REG_SZ,
(CONST BYTE *)szProgID,
sizeof(TCHAR) * (static_cast<DWORD>(_tcslen(szProgID) + 1)));
if (lRet != ERROR_SUCCESS)
{
RegCloseKey(hKeyDsPPClass);
dspDebugOut((DEB_ITRACE, "RegSetValueEx failed: %d", lRet));
hr = HRESULT_FROM_WIN32(lRet);
continue;
}
lRet = RegCreateKeyEx(hKeyDsPPClass, c_szServerType, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
&hKeySvr, &dwDisposition);
RegCloseKey(hKeyDsPPClass);
if (lRet != ERROR_SUCCESS)
{
dspDebugOut((DEB_ITRACE, "RegCreateKeyEx failed: %d", lRet));
hr = HRESULT_FROM_WIN32(lRet);
continue;
}
lRet = RegSetValueEx(hKeySvr, NULL, 0, REG_SZ,
(CONST BYTE *)c_szDsProppagesDllName,
sizeof(TCHAR) * (static_cast<DWORD>(_tcslen(c_szDsProppagesDllName) + 1)));
if (lRet != ERROR_SUCCESS)
{
dspDebugOut((DEB_ITRACE, "RegSetValueEx failed: %d", lRet));
hr = HRESULT_FROM_WIN32(lRet);
}
lRet = RegSetValueEx(hKeySvr, c_szThreadModel, 0, REG_SZ,
(CONST BYTE *)c_szThreadModelValue,
sizeof(TCHAR) * (static_cast<DWORD>(_tcslen(c_szThreadModelValue) + 1)));
if (lRet != ERROR_SUCCESS)
{
dspDebugOut((DEB_ITRACE, "RegSetValueEx failed: %d", lRet));
hr = HRESULT_FROM_WIN32(lRet);
}
RegCloseKey(hKeySvr);
}
RegCloseKey(hKeyCLSID);
return hr;
}
//+----------------------------------------------------------------------------
//
// Function: DllUnregisterServer
//
// Synopsis: Removes the entries from the system registry.
//
// Returns: S_OK or S_FALSE
//
// Notes: The keys look like this:
//
// HKC\CLSID\clsid <No Name> REG_SZ name.progid
// \InPropServer32 <No Name> : REG_SZ : dsprop.dll
// ThreadingModel : REG_SZ : Apartment
//-----------------------------------------------------------------------------
STDAPI
DllUnregisterServer(void)
{
HRESULT hr = S_OK;
HKEY hKeyCLSID, hKeyClass;
long lRet = RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"), 0,
KEY_ALL_ACCESS, &hKeyCLSID);
if (lRet != ERROR_SUCCESS)
{
dspDebugOut((DEB_ITRACE, "RegOpenKeyEx failed: %d", lRet));
return (HRESULT_FROM_WIN32(lRet));
}
LPOLESTR pszCLSID;
PTSTR ptzCLSID;
for (int i = 0; i < g_DsPPClasses.cClasses; i++)
{
hr = StringFromCLSID(*g_DsPPClasses.rgpClass[i]->pcid, &pszCLSID);
if (FAILED(hr))
{
DBG_OUT("StringFromCLSID failed");
continue;
}
if (!UnicodeToTchar(pszCLSID, &ptzCLSID))
{
DBG_OUT("CLSID string memory allocation failure!");
CoTaskMemFree(pszCLSID);
hr = E_OUTOFMEMORY;
continue;
}
CoTaskMemFree(pszCLSID);
lRet = RegOpenKeyEx(hKeyCLSID, ptzCLSID, 0, KEY_ALL_ACCESS, &hKeyClass);
if (lRet != ERROR_SUCCESS)
{
dspDebugOut((DEB_ITRACE, "Failed to open key %S\n", ptzCLSID));
lRet = ERROR_SUCCESS;
hr = S_FALSE;
}
else
{
lRet = RegDeleteKey(hKeyClass, c_szServerType);
RegCloseKey(hKeyClass);
dspDebugOut((DEB_ITRACE, "Delete of key %S returned code %d\n",
c_szServerType, lRet));
if (lRet != ERROR_SUCCESS)
{
lRet = ERROR_SUCCESS;
hr = S_FALSE;
}
}
lRet = RegDeleteKey(hKeyCLSID, ptzCLSID);
dspDebugOut((DEB_ITRACE, "Delete of key %S returned code %d\n",
ptzCLSID, lRet));
delete ptzCLSID;
if (lRet != ERROR_SUCCESS)
{
lRet = ERROR_SUCCESS;
hr = S_FALSE;
}
}
RegCloseKey(hKeyCLSID);
return hr;
}
//+----------------------------------------------------------------------------
//
// Function: GlobalInit
//
// Synopsis: Sets up the global environment.
//
// Returns: S_OK or S_FALSE
//
//-----------------------------------------------------------------------------
inline HRESULT
GlobalInit(void)
{
//
// Initialize common controls
//
InitCommonControls();
INITCOMMONCONTROLSEX icce;
icce.dwSize = sizeof(icce);
icce.dwICC = ICC_DATE_CLASSES;
InitCommonControlsEx(&icce);
#if defined(DSPROP_ADMIN)
//
// Register the "CHECKLIST" control
//
RegisterCheckListWndClass();
#endif
#ifndef DSPROP_ADMIN
//
// Register the window class for the notification window.
//
RegisterNotifyClass();
#endif
//
// Register the attribute-changed message.
//
g_uChangeMsg = RegisterWindowMessage(DSPROP_ATTRCHANGED_MSG);
CHECK_NULL(g_uChangeMsg, ;);
//
// Major cheesy hack to allow locating windows that are unique to this
// instance (since hInstance is invariant).
//
srand((unsigned)time(NULL));
g_iInstance = rand();
#ifndef DSPROP_ADMIN
ExceptionPropagatingInitializeCriticalSection(&g_csNotifyCreate);
#endif
HRESULT hr = CheckRegisterClipFormats();
dspAssert( SUCCEEDED(hr) );
// If found, read the value of the Member class query clause count and
// number-of-members limit.
//
HKEY hKey;
LONG lRet;
lRet = RegOpenKeyEx(HKEY_CURRENT_USER, DIRECTORY_UI_KEY, 0, KEY_READ, &hKey);
if (lRet == ERROR_SUCCESS)
{
DWORD dwSize = sizeof(ULONG);
RegQueryValueEx(hKey, MEMBER_QUERY_VALUE, NULL, NULL,
(LPBYTE)&g_ulMemberFilterCount, &dwSize);
RegQueryValueEx(hKey, MEMBER_LIMIT_VALUE, NULL, NULL,
(LPBYTE)&g_ulMemberQueryLimit, &dwSize);
RegCloseKey(hKey);
}
dspDebugOut((DEB_ITRACE | DEB_USER14, "GroupMemberFilterCount set to %d\n", g_ulMemberFilterCount));
dspDebugOut((DEB_ITRACE | DEB_USER14, "GroupMemberQueryLimit set to %d\n", g_ulMemberQueryLimit));
return S_OK;
}
//+----------------------------------------------------------------------------
//
// Function: GlobalUnInit
//
// Synopsis: Do resource freeing.
//
//-----------------------------------------------------------------------------
inline void
GlobalUnInit(void)
{
#if defined(DSPROP_ADMIN)
if (!g_FPNWCache.empty())
{
for (Cache::iterator i = g_FPNWCache.begin(); i != g_FPNWCache.end(); i++)
{
if ((*i).second)
LocalFree((*i).second);
}
g_FPNWCache.clear();
}
#endif
g_ClassIconCache.ClearAll();
#ifndef DSPROP_ADMIN
DeleteCriticalSection(&g_csNotifyCreate);
#endif
}
//+----------------------------------------------------------------------------
//
// Debugging routines.
//
//-----------------------------------------------------------------------------
#if DBG == 1
//////////////////////////////////////////////////////////////////////////////
unsigned long SmAssertLevel = ASSRT_MESSAGE | ASSRT_BREAK | ASSRT_POPUP;
BOOL fInfoLevelInit = FALSE;
//////////////////////////////////////////////////////////////////////////////
static int _cdecl w4dprintf(const char *format, ...);
static int _cdecl w4smprintf(const char *format, va_list arglist);
//////////////////////////////////////////////////////////////////////////////
static int _cdecl w4dprintf(const char *format, ...)
{
int ret;
va_list va;
va_start(va, format);
ret = w4smprintf(format, va);
va_end(va);
return ret;
}
static int _cdecl w4smprintf(const char *format, va_list arglist)
{
int ret;
char szMessageBuf[DSP_DEBUG_BUF_SIZE];
ret = wvnsprintfA(szMessageBuf, DSP_DEBUG_BUF_SIZE - 1, format, arglist);
OutputDebugStringA(szMessageBuf);
return ret;
}
//+---------------------------------------------------------------------------
//
// Function: _asdprintf
//
// Synopsis: Calls smprintf to output a formatted message.
//
// History: 18-Oct-91 vich Created
//
//----------------------------------------------------------------------------
inline void __cdecl
_asdprintf(
char const *pszfmt, ...)
{
va_list va;
va_start(va, pszfmt);
smprintf(DEB_FORCE, "Assert", pszfmt, va);
va_end(va);
}
//+---------------------------------------------------------------------------
//
// Function: SmAssertEx, private
//
// Synopsis: Display assertion information
//
// Effects: Called when an assertion is hit.
//
//----------------------------------------------------------------------------
void APINOT
SmAssertEx(
char const * szFile,
int iLine,
char const * szMessage)
{
if (SmAssertLevel & ASSRT_MESSAGE)
{
DWORD tid = GetCurrentThreadId();
_asdprintf("%s File: %s Line: %u, thread id %d\n",
szMessage, szFile, iLine, tid);
}
if (SmAssertLevel & ASSRT_POPUP)
{
int id = PopUpError(szMessage,iLine,szFile);
if (id == IDCANCEL)
{
DebugBreak();
}
}
else if (SmAssertLevel & ASSRT_BREAK)
{
DebugBreak();
}
}
//+------------------------------------------------------------
// Function: PopUpError
//
// Synopsis: Displays a dialog box using provided text,
// and presents the user with the option to
// continue or cancel.
//
// Arguments:
// szMsg -- The string to display in main body of dialog
// iLine -- Line number of file in error
// szFile -- Filename of file in error
//
// Returns:
// IDCANCEL -- User selected the CANCEL button
// IDOK -- User selected the OK button
//-------------------------------------------------------------
int APINOT
PopUpError(
char const *szMsg,
int iLine,
char const *szFile)
{
int id;
static char szAssertCaption[128];
static char szModuleName[128];
DWORD tid = GetCurrentThreadId();
DWORD pid = GetCurrentProcessId();
char * pszModuleName;
if (GetModuleFileNameA(NULL, szModuleName, 128))
{
pszModuleName = szModuleName;
}
else
{
pszModuleName = "Unknown";
}
wsprintfA(szAssertCaption,"Process: %s File: %s line %u, thread id %d.%d",
pszModuleName, szFile, iLine, pid, tid);
id = MessageBoxA(NULL,
szMsg,
szAssertCaption,
MB_SETFOREGROUND
| MB_DEFAULT_DESKTOP_ONLY
| MB_TASKMODAL
| MB_ICONEXCLAMATION
| MB_OKCANCEL);
//
// If id == 0, then an error occurred. There are two possibilities
// that can cause the error: Access Denied, which means that this
// process does not have access to the default desktop, and everything
// else (usually out of memory).
//
#ifdef DSPROP_ADMIN
if (0 == id)
{
if (GetLastError() == ERROR_ACCESS_DENIED)
{
//
// Retry this one with the SERVICE_NOTIFICATION flag on. That
// should get us to the right desktop.
//
id = MessageBoxA(NULL,
szMsg,
szAssertCaption,
MB_SETFOREGROUND
| MB_SERVICE_NOTIFICATION
| MB_TASKMODAL
| MB_ICONEXCLAMATION
| MB_OKCANCEL);
}
}
#endif
return id;
}
//+------------------------------------------------------------
// Function: smprintf
//
// Synopsis: Prints debug output using a pointer to the
// variable information. Used primarily by the
// xxDebugOut macros
//
// Arguements:
// ulCompMask -- Component level mask used to determine
// output ability
// pszComp -- String const of component prefix.
// ppszfmt -- Pointer to output format and data
//
//-------------------------------------------------------------
void APINOT
smprintf(
unsigned long ulCompMask,
char const *pszComp,
char const *ppszfmt,
va_list pargs)
{
if ((ulCompMask & DEB_FORCE) == DEB_FORCE ||
(ulCompMask | DEF_INFOLEVEL))
{
DWORD tid = GetCurrentThreadId();
DWORD pid = GetCurrentProcessId();
if ((DEF_INFOLEVEL & (DEB_DBGOUT | DEB_STDOUT)) != DEB_STDOUT)
{
if (! (ulCompMask & DEB_NOCOMPNAME))
{
w4dprintf("%x.%03x> %s: ", pid, tid, pszComp);
}
SYSTEMTIME st;
GetLocalTime(&st);
w4dprintf("%02d:%02d:%02d ", st.wHour, st.wMinute, st.wSecond);
w4smprintf(ppszfmt, pargs);
}
}
}
//+----------------------------------------------------------------------------
// Function: CheckInit
//
// Synopsis: Performs debugging library initialization
// including reading the registry for the desired infolevel
//
//-----------------------------------------------------------------------------
void APINOT
CheckInit(char * pInfoLevelString, unsigned long * pulInfoLevel)
{
HKEY hKey;
LONG lRet;
DWORD dwSize;
if (fInfoLevelInit) return;
fInfoLevelInit = TRUE;
lRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, SMDEBUGKEY, 0, KEY_READ, &hKey);
if (lRet == ERROR_SUCCESS)
{
dwSize = sizeof(unsigned long);
lRet = RegQueryValueExA(hKey, pInfoLevelString, NULL, NULL,
(LPBYTE)pulInfoLevel, &dwSize);
if (lRet != ERROR_SUCCESS)
{
*pulInfoLevel = DEF_INFOLEVEL;
}
RegCloseKey(hKey);
}
}
#endif // DBG == 1
// This wrapper function required to make prefast shut up when we are
// initializing a critical section in a constructor.
void
ExceptionPropagatingInitializeCriticalSection(LPCRITICAL_SECTION critsec)
{
__try
{
::InitializeCriticalSection(critsec);
}
//
// propagate the exception to our caller.
//
__except (EXCEPTION_CONTINUE_SEARCH)
{
}
}