|
|
//*************************************************************
//
// Copyright (c) Microsoft Corporation 1998
// All rights reserved
//
// fdeploy.cxx
//
//*************************************************************
#include "fdeploy.hxx"
#include "rsopdbg.h"
#define ABORT_IF_NECESSARY if (pbAbort && *pbAbort) \
{ \ Status = ERROR_REQUEST_ABORTED; \ goto ProcessGPOCleanup; \ }
#define FLUSH_AND_ABORT_IF_NECESSARY if (pbAbort && *pbAbort) \
{ \ Status = ERROR_REQUEST_ABORTED; \ goto ProcessGPOFlush; \ }
CDebug dbgRsop( L"Software\\Microsoft\\Windows NT\\CurrentVersion\\winlogon", L"RsopDebugLevel", L"gpdas.log", L"gpdas.bak", TRUE );
//status callback function
PFNSTATUSMESSAGECALLBACK gpStatusCallback;
//saved per user per machine settings
CSavedSettings gSavedSettings[(int)EndRedirectable];
//if CSC is enabled or not
BOOL g_bCSCEnabled = FALSE;
// Used for LoadString.
HINSTANCE ghDllInstance = 0; HINSTANCE ghFileDeployment = 0; WCHAR gwszStatus[20]; WCHAR gwszNumber[20];
// User info.
CUsrInfo gUserInfo; const WCHAR * gwszUserName = NULL;
//+--------------------------------------------------------------------------
//
// Function: ReinitGlobals
//
// Synopsis: Reinitializes the global variables that should not carry
// over to the next run of folder redirection.
//
// Arguments: none.
//
// Returns: nothing.
//
// History: 12/17/2000 RahulTh created
//
// Notes: static members of classes and other global variables are
// initialized only when the dll is loaded. So if this dll
// stays loaded across logons, then the fact that the globals
// have been initialized based on a previous logon can cause
// problems. Therefore, this function is used to reinitialize
// the globals.
//
//---------------------------------------------------------------------------
void ReinitGlobals (void) { DWORD i; // First reset the static members of various classes.
CSavedSettings::ResetStaticMembers(); // Now reset members of various global objects.
gUserInfo.ResetMembers(); for (i = 0; i < (DWORD) EndRedirectable; i++) { gSavedSettings[i].ResetMembers(); gPolicyResultant[i].ResetMembers(); gAddedPolicyResultant[i].ResetMembers(); gDeletedPolicyResultant[i].ResetMembers(); } return; }
extern "C" DWORD WINAPI ProcessGroupPolicyEx ( DWORD dwFlags, HANDLE hUserToken, HKEY hKeyRoot, PGROUP_POLICY_OBJECT pDeletedGPOList, PGROUP_POLICY_OBJECT pChangedGPOList, ASYNCCOMPLETIONHANDLE pHandle, BOOL* pbAbort, PFNSTATUSMESSAGECALLBACK pStatusCallback, IN IWbemServices *pWbemServices, HRESULT *phrRsopStatus ) { CRsopContext DiagnosticModeContext( pWbemServices, phrRsopStatus, FDEPLOYEXTENSIONGUID );
if(! (dwFlags & GPO_INFO_FLAG_MACHINE)) { // Reinitialize all globals that should not get carried over from
// a previous run of folder redirection. This is necessary just in
// case this dll is not unloaded by userenv after each run. Also, we should
// do this before any other processing is done to ensure correct behavior.
ReinitGlobals(); }
return ProcessGroupPolicyInternal ( dwFlags, hUserToken, hKeyRoot, pDeletedGPOList, pChangedGPOList, pHandle, pbAbort, pStatusCallback, &DiagnosticModeContext ); }
extern "C" DWORD WINAPI GenerateGroupPolicy ( IN DWORD dwFlags, IN BOOL *pbAbort, IN WCHAR *pwszSite, IN PRSOP_TARGET pComputerTarget, IN PRSOP_TARGET pUserTarget ) { DWORD Status;
if(! (dwFlags & GPO_INFO_FLAG_MACHINE)) { // Reinitialize all globals that should not get carried over from
// a previous run of folder redirection. This is necessary just in
// case this dll is not unloaded by userenv after each run. Also, we should
// do this before any other processing is done to ensure correct behavior.
ReinitGlobals(); }
CRsopContext PlanningModeContext( pUserTarget, dwFlags & GPO_INFO_FLAG_REPORT, FDEPLOYEXTENSIONGUID );
Status = ERROR_SUCCESS;
//
// There is no machine policy, only user --
// process only user policy
//
if ( pUserTarget && pUserTarget->pGPOList ) { gUserInfo.SetPlanningModeContext( &PlanningModeContext );
Status = ProcessGroupPolicyInternal( dwFlags, NULL, NULL, NULL, pUserTarget->pGPOList, NULL, pbAbort, NULL, &PlanningModeContext); }
return Status; }
DWORD ProcessGroupPolicyInternal ( DWORD dwFlags, HANDLE hUserToken, HKEY hKeyRoot, PGROUP_POLICY_OBJECT pDeletedGPOList, PGROUP_POLICY_OBJECT pChangedGPOList, ASYNCCOMPLETIONHANDLE pHandle, BOOL* pbAbort, PFNSTATUSMESSAGECALLBACK pStatusCallback, CRsopContext* pRsopContext ) { BOOL bStatus; DWORD Status = ERROR_SUCCESS; DWORD RedirStatus; CFileDB CurrentDB; DWORD i; PGROUP_POLICY_OBJECT pCurrGPO = NULL; HANDLE hDupToken = NULL; BOOL fUpdateMyPicsLinks = FALSE; BOOL fPlanningMode; BOOL fWriteRsopLog = FALSE; BOOL bForcedRefresh = FALSE;
gpStatusCallback = pStatusCallback;
fPlanningMode = pRsopContext->IsPlanningModeEnabled();
//some basic initializations first.
InitDebugSupport();
//
// Even though this extension has indicated its preference for not
// handling machine policies, the admin. might still override these
// preferences through policy. Since, this extension is not designed to
// handled this situation, we need to explicitly check for these cases and
// quit at this point.
//
if (dwFlags & GPO_INFO_FLAG_MACHINE) { DebugMsg((DM_VERBOSE, IDS_INVALID_FLAGS)); Status = ERROR_INVALID_FLAGS; goto ProcessGPOCleanup; }
if ( dwFlags & GPO_INFO_FLAG_VERBOSE ) gDebugLevel |= DL_VERBOSE | DL_EVENTLOG;
gpEvents = new CEvents(); if (!gpEvents) { DebugMsg((DM_VERBOSE, IDS_INIT_FAILED)); Status = ERROR_OUTOFMEMORY; goto ProcessGPOCleanup; }
Status = gpEvents->Init(); if (Status != ERROR_SUCCESS) { gpEvents->Report (EVENT_FDEPLOY_INIT_FAILED, 0); goto ProcessGPOCleanup; } gpEvents->Reference();
DebugMsg((DM_VERBOSE, IDS_PROCESSGPO)); DebugMsg((DM_VERBOSE, IDS_GPO_FLAGS, dwFlags));
if ( ! fPlanningMode ) { bStatus = DuplicateToken (hUserToken, SecurityImpersonation, &hDupToken); if (!bStatus) { Status = GetLastError(); gpEvents->Report (EVENT_FDEPLOY_INIT_FAILED, 0); goto ProcessGPOCleanup; }
//impersonate the logged on user,
bStatus = ImpersonateLoggedOnUser( hDupToken ); //bail out if impersonation fails
if (!bStatus) { gpEvents->Report (EVENT_FDEPLOY_INIT_FAILED, 0); Status = GetLastError(); goto ProcessGPOCleanup; }
g_bCSCEnabled = CSCIsCSCEnabled ();
//try to get set ownership privileges. These will be required
//when we copy over ownership information
GetSetOwnerPrivileges (hDupToken);
//get the user name -- this is used for tracking name changes.
gwszUserName = gUserInfo.GetUserName (Status); if (ERROR_SUCCESS != Status) { DebugMsg ((DM_VERBOSE, IDS_GETNAME_FAILED, Status)); gpEvents->Report (EVENT_FDEPLOY_INIT_FAILED, 0); goto ProcessGPOCleanup; } }
//load the localized folder names and relative paths. (also see
//notes before the function LoadLocalizedNames()
Status = LoadLocalizedFolderNames (); if (ERROR_SUCCESS != Status) { gpEvents->Report (EVENT_FDEPLOY_INIT_FAILED, 0); goto ProcessGPOCleanup; }
//now initialize those values for the CFileDB object that are going to
//be the same across all the policies
if (ERROR_SUCCESS != (Status = CurrentDB.Initialize(hDupToken, hKeyRoot, pRsopContext ))) { gpEvents->Report (EVENT_FDEPLOY_INIT_FAILED, 0); goto ProcessGPOCleanup; }
if ( ! fPlanningMode ) {
//now load the per user per machine settings saved during the last logon
for (i = 0; i < (DWORD) EndRedirectable; i++) { Status = gSavedSettings[i].Load (&CurrentDB); if (ERROR_SUCCESS != Status) { gpEvents->Report (EVENT_FDEPLOY_INIT_FAILED, 0); goto ProcessGPOCleanup; } } }
//now if the GPO_NOCHANGES flag has been specified, make sure that it is
//okay not to do any processing
bStatus = TRUE; if ( (dwFlags & GPO_INFO_FLAG_NOCHANGES) && !fPlanningMode && !( dwFlags & GPO_INFO_FLAG_LOGRSOP_TRANSITION ) ) { for (bStatus = FALSE, i = 0; i < (DWORD)EndRedirectable && (!bStatus); i++) { bStatus = gSavedSettings[i].NeedsProcessing(); } }
if (!bStatus) //we are in good shape. No processing is required.
{ Status = ERROR_SUCCESS; DebugMsg ((DM_VERBOSE, IDS_NOCHANGES)); goto ProcessGPOCleanup; } else { if ((dwFlags & GPO_INFO_FLAG_BACKGROUND) || (dwFlags & GPO_INFO_FLAG_ASYNC_FOREGROUND)) { //
// Log an event only in the async. foreground case. In all other
// cases just output a debug message. Note: The Background flag
// will be set even in the async. foreground case. So we must
// explicitly make this check against the async. foreground
// flag.
//
if (dwFlags & GPO_INFO_FLAG_ASYNC_FOREGROUND) { gpEvents->Report (EVENT_FDEPLOY_POLICY_DELAYED, 0); } else { DebugMsg ((DM_VERBOSE, IDS_POLICY_DELAYED)); } Status = ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED; goto ProcessGPOCleanup; }
if ( ! fPlanningMode && (dwFlags & GPO_INFO_FLAG_NOCHANGES)) { // a user name or homedir change has occured and no gpo changes occurred,
// so in order to perform RSoP logging, we will need to get our own
// RSoP namespace since the GP engine does not give us the namespace
// if no changes occurred -- we note this below
bForcedRefresh = TRUE; fWriteRsopLog = TRUE; } }
//
// If we have changes or we are in planning mode, enable logging
//
if ( pChangedGPOList || pDeletedGPOList || fPlanningMode ) { fWriteRsopLog = TRUE; }
if ( fWriteRsopLog ) { //
// If RSoP logging should occur in logging mode, initialize
// the rsop context -- this is not necessary in planning mode
//
if ( pRsopContext->IsDiagnosticModeEnabled() ) { PSID pUserSid;
pUserSid = gpEvents->UserSid();
if ( pUserSid ) { // This call requires elevated privileges to succeed.
RevertToSelf(); (void) pRsopContext->InitializeContext( pUserSid ); // Re-impersonate the logged on user,
bStatus = ImpersonateLoggedOnUser( hDupToken ); // Bail out if impersonation fails
if (!bStatus) { gpEvents->Report (EVENT_FDEPLOY_INIT_FAILED, 0); Status = GetLastError(); goto ProcessGPOCleanup; } } else { pRsopContext->DisableRsop( ERROR_OUTOFMEMORY ); } }
CurrentDB.InitRsop( pRsopContext, bForcedRefresh ); }
//first process any user name changes.
for (i = 0; i < (DWORD) EndRedirectable; i++) { Status = gSavedSettings[i].HandleUserNameChange( &CurrentDB, &(gPolicyResultant[i])); if (ERROR_SUCCESS != Status) { // Failure events will be reported while processing the name change
goto ProcessGPOCleanup; } }
//first process the deleted GPOs
//we need to do this in reverse, because removed policies are sent
//in reverse, that is the closest policy is sent last. So if you have
//two policies that redirect the same folder and both of them are removed
//simultaneously, then, the code gets the wrong value for the redirection
//destination of the resultant set of removed policies and therefore
//assumes that someone else must have modified it and therefore leaves it
//alone
if (pDeletedGPOList) { //go all the way to the end
for (pCurrGPO = pDeletedGPOList; pCurrGPO->pNext; pCurrGPO = pCurrGPO->pNext) ; //now pCurrGPO points to the last policy in the removed list, so go at
//it in the reverse order.
for (; pCurrGPO; pCurrGPO = pCurrGPO->pPrev) { DebugMsg((DM_VERBOSE, IDS_GPO_NAME, pCurrGPO->szGPOName)); DebugMsg((DM_VERBOSE, IDS_GPO_FILESYSPATH, pCurrGPO->lpFileSysPath)); DebugMsg((DM_VERBOSE, IDS_GPO_DSPATH, pCurrGPO->lpDSPath)); DebugMsg((DM_VERBOSE, IDS_GPO_DISPLAYNAME, pCurrGPO->lpDisplayName));
//if we are unable to process even a single policy, we must abort
//immediately otherwise we may end up with an incorrect resultant
//policy.
if (ERROR_SUCCESS != (Status = CurrentDB.Process (pCurrGPO, TRUE))) goto ProcessGPOCleanup;
ABORT_IF_NECESSARY } }
//update the descendants
Status = gDeletedPolicyResultant[(int) MyPics].UpdateDescendant ();
if ( ERROR_SUCCESS != Status ) { goto ProcessGPOCleanup; }
//now process the other GPOs
for (pCurrGPO = pChangedGPOList; pCurrGPO; pCurrGPO = pCurrGPO->pNext) { DebugMsg((DM_VERBOSE, IDS_GPO_NAME, pCurrGPO->szGPOName)); DebugMsg((DM_VERBOSE, IDS_GPO_FILESYSPATH, pCurrGPO->lpFileSysPath)); DebugMsg((DM_VERBOSE, IDS_GPO_DSPATH, pCurrGPO->lpDSPath)); DebugMsg((DM_VERBOSE, IDS_GPO_DISPLAYNAME, pCurrGPO->lpDisplayName));
//if we are unable to process even a single policy, we must abort
//immediately otherwise we may end up with an incorrect resultant
//policy.
if (ERROR_SUCCESS != (Status = CurrentDB.Process (pCurrGPO, FALSE))) { goto ProcessGPOCleanup; }
ABORT_IF_NECESSARY }
if ( fPlanningMode ) { goto ProcessGPOCleanup; }
//now update the My Pics data. UpdateDescendant will derive the settings for
//My Pics from My Docs if it is set to derive its settings from My Docs.
gAddedPolicyResultant[(int) MyPics].UpdateDescendant ();
//now merge the deleted policy resultant and added policy resultants
for (i = 0; i < (DWORD) EndRedirectable; i++) { gPolicyResultant[i] = gDeletedPolicyResultant[i]; gPolicyResultant[i] = gAddedPolicyResultant[i]; //check to see if any group membership change has caused a policy to
//be effectively removed for this user.
Status = gPolicyResultant[i].ComputeEffectivePolicyRemoval (pDeletedGPOList, pChangedGPOList, &CurrentDB); if ( ERROR_SUCCESS != Status ) { goto ProcessGPOCleanup; } }
//do the final redirection
//we ignore errors that might occur in redirection
//so that redirection of other folders is not hampered.
//however, if there is a failure, we save that information
//so that we can inform the group policy engine
if (ERROR_SUCCESS == Status) { for (i = 0; i < (int)EndRedirectable; i++) { RedirStatus= gPolicyResultant[i].Redirect(hDupToken, hKeyRoot, &CurrentDB);
if ((ERROR_SUCCESS != RedirStatus) && (ERROR_SUCCESS == Status)) Status = RedirStatus;
FLUSH_AND_ABORT_IF_NECESSARY //abort if necessary, but first, flush the shell's special folder cache
///as we may have redirected some folders already.
}
//update shell links to MyPics within MyDocuments if policy specified
//the location of at least one of MyDocs and MyPics and succeeded in
//redirection. For additional details see comments at the beginning of
//the function UpdateMyPicsShellLinks.
if ( ( (!(gPolicyResultant[(int)MyDocs].GetFlags() & REDIR_DONT_CARE)) && (ERROR_SUCCESS == gPolicyResultant[(int)MyDocs].GetRedirStatus()) ) || ( (!(gPolicyResultant[(int)MyPics].GetFlags() & REDIR_DONT_CARE)) && (ERROR_SUCCESS == gPolicyResultant[(int)MyPics].GetRedirStatus()) ) ) { fUpdateMyPicsLinks = TRUE; //note:we do not invoke the shell link update function here since
//we need to flush the shell special folder cache or we may not
//get the true current location of MyDocs or MyPics. Therefore,
//the function is actually invoked below.
} } else { DebugMsg((DM_VERBOSE, IDS_PROCESSREDIRECTS, Status)); }
//
// Do not try to update the link (shell shortcut) in planning mode since
// planning mode takes no real action, just records results
//
if ( fPlanningMode ) { fUpdateMyPicsLinks = FALSE; }
//flush the shell's special folder cache. we may have successfully redirected
//some folders by the time we reach here. So it is always a good idea to let
//the shell know about it.
ProcessGPOFlush: if (fUpdateMyPicsLinks) UpdateMyPicsShellLinks(hDupToken, gPolicyResultant[(int)MyPics].GetLocalizedName());
ProcessGPOCleanup: //don't leave any turds behind.
if ( (ERROR_SUCCESS == Status) && !fPlanningMode ) { //we have successfully applied all the policies, so remove any cached
//ini files for removed policies.
//any errors in deletion are ignored.
DeleteCachedConfigFiles (pDeletedGPOList, &CurrentDB); }
//we are done, so we stop running as the user
if ( ! fPlanningMode ) { RevertToSelf(); } // In logging (aka diagnostic) mode, we need to ensure that
// we reset the saved namespace before logging so that in the
// no changes case where we need to log ( i.e. username / homedir change ),
// we only log rsop data if RSoP was enabled at the last change
if ( fWriteRsopLog ) { (void) pRsopContext->DeleteSavedNameSpace();
if ( pRsopContext->IsRsopEnabled() ) { HRESULT hrLog; hrLog = CurrentDB.WriteRsopLog(); if ( SUCCEEDED( hrLog ) ) { (void) pRsopContext->SaveNameSpace(); } } }
if ( ! fPlanningMode ) { if (hDupToken) CloseHandle (hDupToken); } else { Status = CurrentDB.GetPlanningSimulatedErrorIfNecessary( Status ); }
if (gpEvents) gpEvents->Release();
//restore the status message
DisplayStatusMessage (IDS_DEFAULT_CALLBACK);
// CPolicyDatabase::FreeDatabase();
return Status; }
extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { switch (dwReason) { case DLL_PROCESS_ATTACH : ghDllInstance = hInstance; DisableThreadLibraryCalls(hInstance); break; case DLL_PROCESS_DETACH : break; }
return TRUE; }
/////////////////////////////////////////////////////////////////////////////
// DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServer(void) { DWORD dwDisp; LONG lResult; HKEY hkSource = NULL; HKEY hKey = NULL; TCHAR EventFile[] = TEXT("%SystemRoot%\\System32\\fdeploy.dll"); TCHAR ParamFile[] = TEXT("%SystemRoot%\\System32\\kernel32.dll"); WCHAR EventSources[] = TEXT("(Folder Redirection,Application)\0" ); DWORD dwTypes = 0x7; DWORD dwSet = 1; DWORD dwReset = 0; HRESULT hr = S_OK;
//register the dll as an extension of the policy engine
lResult = RegCreateKeyEx (HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\GPExtensions\\{25537BA6-77A8-11D2-9B6C-0000F8080861}"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dwDisp);
if (lResult != ERROR_SUCCESS) { hr = SELFREG_E_CLASS; goto DllRegisterServer_exit; }
lResult = RegSetValueEx (hKey, NULL, 0, REG_SZ, (LPBYTE) TEXT("Folder Redirection"), (lstrlen (TEXT("Folder Redirection")) + 1) * sizeof (TCHAR)); if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto DllRegisterServer_exit; }
lResult = RegSetValueEx (hKey, TEXT("ProcessGroupPolicyEx"), 0, REG_SZ, (LPBYTE)TEXT("ProcessGroupPolicyEx"), (lstrlen(TEXT("ProcessGroupPolicyEx")) + 1) * sizeof(TCHAR)); if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto DllRegisterServer_exit; }
lResult = RegSetValueEx (hKey, TEXT("DllName"), 0, REG_EXPAND_SZ, (LPBYTE)TEXT("fdeploy.dll"), (lstrlen(TEXT("fdeploy.dll")) + 1) * sizeof(TCHAR)); if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto DllRegisterServer_exit; }
lResult = RegSetValueEx (hKey, TEXT("NoMachinePolicy"), 0, REG_DWORD, (LPBYTE)&dwSet, sizeof (dwSet)); if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto DllRegisterServer_exit; }
lResult = RegSetValueEx (hKey, TEXT("NoSlowLink"), 0, REG_DWORD, (LPBYTE)&dwSet, sizeof (dwSet)); if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto DllRegisterServer_exit; }
lResult = RegSetValueEx (hKey, TEXT("PerUserLocalSettings"), 0, REG_DWORD, (LPBYTE)&dwSet, sizeof (dwSet)); if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto DllRegisterServer_exit; }
//we want the folder redirection extension to get loaded each time.
lResult = RegSetValueEx (hKey, TEXT("NoGPOListChanges"), 0, REG_DWORD, (LPBYTE)&dwReset, sizeof (dwReset)); if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto DllRegisterServer_exit; }
//
// New perf. stuff. We also want to get called in the background and
// async. foreground case.
//
lResult = RegSetValueEx (hKey, TEXT("NoBackgroundPolicy"), 0, REG_DWORD, (LPBYTE)&dwReset, sizeof (dwReset)); if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto DllRegisterServer_exit; }
lResult = RegSetValueEx (hKey, TEXT("GenerateGroupPolicy"), 0, REG_SZ, (LPBYTE)TEXT("GenerateGroupPolicy"), (lstrlen (TEXT("GenerateGroupPolicy")) + 1) * sizeof(TCHAR)); if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto DllRegisterServer_exit; }
// Need to register event sources for RSoP
lResult = RegSetValueEx (hKey, TEXT("EventSources"), 0, REG_MULTI_SZ, (LPBYTE)EventSources, sizeof(EventSources) ); if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto DllRegisterServer_exit; }
//register the dll as a source for event log messages
lResult = RegCreateKeyEx (HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\Folder Redirection"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkSource, &dwDisp);
if (lResult != ERROR_SUCCESS) { hr = SELFREG_E_CLASS; goto DllRegisterServer_exit; }
lResult = RegSetValueEx (hkSource, TEXT("EventMessageFile"), 0, REG_EXPAND_SZ, (LPBYTE) EventFile, (lstrlen(EventFile) + 1) * sizeof (TCHAR)); if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto DllRegisterServer_exit; }
lResult = RegSetValueEx (hkSource, TEXT("ParameterMessageFile"), 0, REG_EXPAND_SZ, (LPBYTE) ParamFile, (lstrlen(ParamFile) + 1) * sizeof (TCHAR)); if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto DllRegisterServer_exit; }
lResult = RegSetValueEx (hkSource, TEXT("TypesSupported"), 0, REG_DWORD, (LPBYTE) &dwTypes, sizeof(DWORD)); if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto DllRegisterServer_exit; }
hr = S_OK;
DllRegisterServer_exit:
if ( hKey ) { RegCloseKey (hKey); }
if ( hkSource ) { RegCloseKey (hkSource); }
return hr; }
/////////////////////////////////////////////////////////////////////////////
// DllUnregisterServer - Removes entries from the system registry
STDAPI DllUnregisterServer(void) { RegDelnode (HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\GPExtensions\\{25537BA6-77A8-11D2-9B6C-0000F8080861}")); RegDelnode (HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\Folder Redirection"));
return S_OK; }
|