A windows service creates a registry value (for an Excel add-in) under HKEY_CURRENT_USER registry key for each logged on user (by calling ImpersonateLoggedOnUser() and RegSetValueEx()).
I need to delete this registry value when a user logs off, including system shutdown.
If it is not deleted at log off, and the software is uninstalled by one user then the entry in the registry remains for any other user that logged on during the lifetime of the service which causes a message box error to be displayed each time Excel begins because it is attempting to load an add-in that no longer exists.
Considered but rejected the following:
SetConsoleCtrlHandler() because there is no indication of what user is logging off.
REG_OPTION_VOLATILE because it is effective only when creating keys and I am only creating a value (did not thoroughly investigate so may not have been solution even if I was creating a key).
Are there any other mechanisms that would provide a solution to this? Windows versions are XP, Vista and 7.
Since you are already on a service, your life (should be) is easy.
In fact you can register yourself to receive the SERVICE_CONTROL_SESSIONCHANGE event. In particular, you will want to look for the WTS_SESSION_LOGOFF reason.
You have to register for these events in your service control routine, at startup, adding SERVICE_ACCEPT_SESSIONCHANGE. When the event is SERVICE_CONTROL_SESSIONCHANGE, the lpEventData parameter is a pointer to a WTSSESSION_NOTIFICATION structure, with information about the session currently terminating (thus, about the user logging off).
Check out the details on MSDN1, MSDN2, MSDN3 - the data structure that contains the dwSessionId of the interesting session
Check out this related (but not duplicate) question too
That said, I find João Augusto solution cleaner; I would use that for a similar problem; however, I wanted to add this solution for having an answer to the wider question (for future reference readers)
EDIT: Another method is to use SENS, check this MSDN article
An easier approach would be to put a command removing the value in question into the user's RunOnce key, e.g.,
reg.exe delete HKCU\Software\xyzzy /v myvalue /f
so that the unwanted value will be removed when the user next logs in. Note, however, that this might interfere with the creation of the value depending on how you are handling that.
Related
I have created a category file to the Event Logger, but the category names do not show up in Event Logger.
If I however open the log from C:\Windows\System32\winevt\Logs, the category names show up. The category name also show up if I use following PowerShell.
$eventlog = New-Object System.Diagnostics.EventLog("MyLog")
Write-Host $eventlog.Entries[0].Category
The .mc file looks like this:
MessageIdTypedef = WORD
LanguageNames=(
English=0x0409:MSG00409
Swedish=0x041D:MSG0041D
)
MessageId=1
SymbolicName=CAT_1
Language=English
Category 1
.
Language=Swedish
Kategori 1
.
MessageId=2
SymbolicName=CAT_2
Language=English
Category 2
.
Language=Swedish
Kattegori 2
.
; // Up to 22 categorys
In the registry, I have following:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog\MyLog\MySource]
"CategoryCount"=dword:00000016
"TypesSupported"=dword:00000007
"CategoryMessageFile"="C:\\path\\Messages.dll"
I have found https://social.msdn.microsoft.com/forums/windowsdesktop/en-us/3fed3069-ce0f-4168-8132-4d19d66fdd7e/windows-7eventlog-creating-custom-categories with the same problem, but no answer to the problem.
I have tried this in both Windows 7, 8 and Windows Server 2008 R2
Edit
I have created a test project to show what I have done. download it here
Try adding the machine's Authenticated Users or Users group to the message folder's security level. Keep the default permissions. Then either reboot or try to restart the EventLog service.
At an administrator command prompt: net stop eventlog
You will likely be prompted to shutdown other services. You must enter Y to continue. The services being shutdown will normally restart on their own so you just need to wait a few seconds. The eventlog service may fail to shutdown because another service has restarted, it may take a couple of tries to get everything down. Watch the resulting text closely for status.
I ran into this same issue while pointing the source registry information to my message folder in my VS project. I found that it started to work after I created a C:\Test folder with an admin user and referenced that instead. The only difference between this and the project folder was the two groups. Adding either of the two groups made things work. Taking them both away from either folder made it stop.
I also found that if I had matching MessageId's in my CategoryMessageFile and my EventMessageFile it ignored the CategoryMessageFile.
Another possibility, though obviously not the OP's issue (or language), that exhibits similar symptoms is when the EventMessageFile and the CategoryMessageFile have overlapping MessageIds. I am assuming this is a bug in the event log viewer utility when looking at a 'live' source, as the symptoms do not exist when using powershell, .NET, or directly opening the event log file in Event Viewer to parse the event logs.
In my situation, I have a .NET application and am using .NET APIs to create the event source using EventSourceCreationData to specify the CategoryResourceFile and CategoryCount. By default, the MessageResourceFile will be set to C:\Windows\Microsoft.NET\Framework\v4.0.30319\EventLogMessages.dll. The effect of these APIs causes the creation of the appropriate registry keys CategoryMessageFile, CategoryCount, and EventMessageFile. Important to note here is the message file from .NET helpfully adds messages from 0x0 to 0x000FFFF that are all defined as %1\r\n\x00 - essentially meaning when you create an event message in the default way, using EventLog.WriteEntry you see the string message that was logged regardless of the event id. If instead you use EventLog.WriteEvent, you pretty much need to use a specialized messages file (see docs on the EventInstance class). More Info
The symptoms are when looking at the live Event Viewer the Category as defined with the MessageId that was passed into the event log shows up as the integer instead of the string from the resource file. Note this is different behavior from if you had misconfigured the category resource file, permission issues, etc where you see the 'Task Category' as the integer but in parenthesis.
So for example, if you specified category id 8 and are expecting the localized category name 'My Category' the Event Viewer can show one of three things: (8) meaning the CategoryMessageFile or CategoryCount registry keys are misconfigured or there is a problem with the dll. My Category if everything is working as expected. 8 if you hit the issue I am describing.
Thanks to Rich Shealer's answer for the pointer. The problem is rather than getting the Category string from the CategoryMessageFile as one would expect, it is getting it from the MessageResourceFile - and since the .NET resource file merely is a formatting string that returns the first element of source data the numeric category id is generated.
There is no 'good' workaround, but in my use case of using metadata provided to log messages via a logging framework, and some filtering, messages generally have category and event id of zero, except for where I want to specifically set one when logging for a small subset of log messages. This means the logging framework is what is calling the APIs to write the log entries. A workaround is to declare MessageId of 0x0 to be %1 in the .mc file, and only start your event ids at a number higher than the number of categories you expect to have. Then configure the EventMessageFile in the registry or via the property MessageResourceFile to first specify the category file, the semicolon delimiter, then the .NET default resource file. This will properly show and messages logged with 0's for event id and category id, and for event ids greater than your category file the same behavior you previously had. However, any eventid with a number defined that conflicts with the category - well, you get the category name as the log message. You could also remove the message resource file but then you get the annoying 'resource cannot be found' message. I confirmed the behavior here but refuse to do this - will live with the missing text, as I mostly use APIs for analysis and it is correct there.
Sadly, I can't locate any open issue with the Windows Event Viewer - I see it broken in Windows 10 build 1909.
A similar question got asked by others here at least twice already (see links below) but never properly answered, perhaps because it wasn't put the right way. Let me have a go:
I have a process running under the local account on Windows and I need locale information about the user who is logged into the interactive session if there is one or any interactive session if there is more than one.
I need to know the user's language and country settings and it has to work on all kinds of Windows starting XP Service Pack 3.
I very much appreciate your answers!
The previous related questions that didn't really get answered:
C# window xp current user when using run as
https://stackoverflow.com/questions/5778378/creating-a-process-as-logged-on-user
I would do it in the following way:
Enumerate logon sessions using LsaEnumerateLogonSessions
Call LsaGetLogonSessionData to get logged on user SID identifier.
Call ConvertSidToStringSid function to get a string representation of a sid.
Look up registry setting HKEY_USERS[USER_SID_STRING]\Control Panel\International
This key has all sorts of information needed, and looks like all listed WINAPI finctions are available starting at Windows XP.
So this should work.
I have been tasked with writing entries to the Windows security log. The entire project is Win32 C++ code. I have already written (with help from various online resources) a logging class that handles registration, deregistration, and code for executing the ReportEvent() call. Also, I've done the mc.exe and rc.exe steps for my event logging, if that helps establish where I'm at in the project.
My question is a multi-parter:
I've noticed at Filling Windows XP Security Event Log that there are some who believe this is not allowed by Windows. Others ( How to write log to SECURITY event Log in C#? ) imply otherwise. Possible or not?
If it is possible, how to get it to write to the security log. Is it as simple as specifying "Security" as my source name when calling RegisterEventSource()?
As far as deregistration, when should that occur? When the app is uninstalled? When the app closes? When the log entry is written?
How do I look up my log entries? I look in the Windows Event Viewer, but I don't see the entries I add with my test app, despite all the appropriate return values from the system calls. Where would I look up the events that I specified with a source name of "yarp" when I made my call to RegisterEventSource()?
For the moment, I'll just deal with the first question, because the answer to that probably renders the rest irrelevant.
Only Local Security Authority (lsass.exe) can write to the security log. This isn't a matter that something else attempting to get the privilege will fail -- it's a matter of there not being a way for anything else to even request the privilege at all (and this is by design).
From there, about the only answer to your other questions is "Sorry!"
I'm quite confused as to what should and should not be done in QApplication::commitData. The name implies that I should just store the state, and the docs say it should not close the application. However, the default implementation indeed closes all windows thereby closing the application. Also, if this is not the way to detect windows shutdown, I don't see any other way to tell that windows is indeed being shutdown.
There is also the related saveState. The function name means about the same and the documentation is also quite similar.
How am I supposed to properly detect when the system is being shutdown and both save my state and close my application? Is commitData indeed the correct way and just suffering from a very poor name and bad documentation?
In my practice to detect an application shutdown I usually connect to the slot void QCoreApplication::aboutToQuit (). As it says in the docu:
The signal is particularly useful if your application has to do some last-second cleanup. Note that no user interaction is possible in this state.
So far so good this has worked for me properly
commitData() and saveState() may seem redundant.
But the documentation
says
Futhermore, most session managers will very likely request a saved state immediately after the application has been started. This permits the session manager to learn about the application's restart policy.
Maybe that explains why the notion of 'data' and 'state' are separated. During that initial call, it would not be user friendly to interact with the user.
The default response to shutdown the application seems like a good design, because if you don't reimplement, then the safest thing to do is to close the app (as if the user had chosen the Quit action), which should also save the user's data.
Is the OS shutting down, or only the session? As far as your app should be concerned, it is only the session (since technically, the user could be logging off and the OS continues to run.) And the user might consider the app to be not 'shut down', just 'paused with data safed.'
Also consider mobile platforms like iOS, where an application seeming runs forever.
I have a C++ program that launches various MS Access databases (.mdb files), some of which have Startup Restrictions applied to them.
Right now, the only way I know to disable those restrictions is to hold down the shift key until the database finishes loading.
I want my program to simulate the same end result of opening the database with those restrictions disabled, but I don't want to have to make the user hold down the shift key, and I don't want to simulate the shift key myself in the program. It's been my experience that you have to hold the shift key down until the database finishes loading, and that doesn't always take the same amount of time (in my environment anyways). So, I don't see that as a very reliable option.
Does anyone know another approach I could take besides simulating the shift key?
I have looked into the AllowBypassKey property in Access, but even if you set that to true, it still requires the user to hold down the shift key in order to disable the startup options.
I currently use ShellExecute() to launch the database, but I'm open to using another method.
Note: The solution needs to work in Access 2000, 2003, 2007, and 2010