1317 lines
37 KiB
C++
1317 lines
37 KiB
C++
//+----------------------------------------------------------------------------
|
|
//
|
|
// 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)
|
|
{
|
|
}
|
|
}
|