What is the difference between WTS_SESSIONSTATE_UNKNOWN and WTS_SESSIONSTATE_LOCK? - winapi

I am trying to determine the current session state using the Win32 API ::WTSQuerySessionInformation function by querying for SessionFlags of the WTSINFOEX_LEVEL1 structure according to the answers to C++: check if computer is locked.
On my machine (Windows 10 1703) SesssionFlags can reach only two (of three documented) values: WTS_SESSIONSTATE_UNLOCK and WTS_SESSIONSTATE_UNKNOWN. The latter seems to mean the same as the expected WTS_SESSIONSTATE_LOCK which I cannot reach, neither through <WinKey>+<L> nor by programmatically locking the session through ::LockWorkStation.
So my questions are:
Does WTS_SESSIONSTATE_LOCK exist?
If yes, then how can I reach that state?
If yes, what is the difference between both states (LOCK and UNKNOWN)?
According to SessionChangeReason Enumeration the .NET Framework distinguishes (correctly?) between just two corresponding states SessionUnlock and SessionUnlock. So the state of a session is triple or binary?

One would think that WTS_SESSIONSTATE_UNKNOWN means that the state is unknown and you should not interpret it as locked nor unlocked. It seems this member has a sorry history, MSDN says
Windows Server 2008 R2 and Windows 7: Due to a code defect, the usage of the WTS_SESSIONSTATE_LOCK and WTS_SESSIONSTATE_UNLOCK flags is reversed. That is, WTS_SESSIONSTATE_LOCK indicates that the session is unlocked, and WTS_SESSIONSTATE_UNLOCK indicates the session is locked.
Because the member is named SessionFlags and MSDN says "This can be one or more of the following values" one could imagine that more flags could be added over time and you should actually be doing:
isUnlocked = SessionFlags & WTS_SESSIONSTATE_UNLOCK;
(and the logic reversed on Windows 7). I don't think anyone does this so I doubt Microsoft will ever add more flags but you never know.
On my Windows 8 and 10.0.17134 machines it returns WTS_SESSIONSTATE_UNLOCK normally and WTS_SESSIONSTATE_LOCK when I press Win+L so it is possible you are doing something wrong?
I don't know what happens if a Windows 7+ machine tries to ask a Vista machine, maybe you get WTS_SESSIONSTATE_UNKNOWN or maybe the entire call fails because Vista does not support WTSSessionInfoEx.
The accepted answer in the question you linked to tells you to use WTSRegisterSessionNotification and it will provide you with the same values as SessionChangeReason and you don't have to pull to detect changes.

Related

Debugging Visual Basic Runtime Error 5

I have a Visual Basic 4 32 bit application which results in a
Run-time error '5':
Invalid procedure call
I start WinDbg and do
sxe *
to break on all exceptions. However, it displays the message without breaking into the debugger before.
If I break at the time of the message, the callstack is not very useful. Is there a trick to break-in on Visual Basic 4 applications at the time the problem occurs?
Problem FAQ:
Can you run it in the IDE?
Yes I can and I can probably fix the bug when I do that. However, I'd like to get some more information at the time the end user runs the application so that I don't need to be able to reproduce it.
What do you want to do in case you find the cause of the error?
Well, it depends on the type of the error. Maybe I can fix it, maybe I can't. Usually I get some very helpful information out of WinDbg.
When does the error occur?
It occurs reproducibly when the user presses a close button on a form.
What does the application do?
Oh, that's a good question. I don't exactly know. It uses RS232 communication but it's not yet involved.
Do you know anything about the data the user can enter?
I almost know nothing about it. In this particular case, it's not necessary to enter data.
The error is from the VB virtual machine not from an API.
I can't see how WinDbg would be useful on VB4 which is interpreted and is in P-Code.
Visual Basic run-time error 5 Indicates one of the following:
An invalid collection or property name was entered.
An out parameter was NULL.
The value is not one of the supported values or falls outside the supported range.
The property is read-only.
The property cannot be changed after the object is created.
An invalid index was entered.
And in case it's an API call VB uses LoadLibrary and GetProcAddress.
Some controls have lost default values over time and this can cause the first.
The third can happen if modern technology exceeds the program's expection, e.g. disk space.
Also see (sorry no links, they are on my hard disk)
Q131007 HOWTO: Use Windows NT WinDbg.exe with Visual Basic (it's for NT 3.5)
Q166275 HOWTO: Debug a Native Code Visual Basic Component in VC++ (talks about what you can see in VB in a debugger)
VB4 can't make symbols
As the error occurs when the users presses the close button i assume there is a (very tight) loop running which doesn't receive the expected data (probably a nullstring)
I expect that that loop is continuously reading data from the RS232 device and the RS232 is on the form which is being closed, even though it is not involved the connection might already be open and polling
What you should do is exit that loop and close the connection with the RS232 device before closing the form. You might be able to do that in the Form_Unload() event, but it might also have to take place before that, so you might have to do it in the code of the close button ... make sure though that the user won't be using the X to close the form though
Personally i would run the program from within the IDE, this will point you to the errornous part of the code directly and gives you the opportunity to watch the contents of the variables involved and control states ... that is much faster than taking a guess based on the data of WinDbg

Windows Driver - How do I determine if Windows is in the process of booting, or has already booted?

I'm trying to develop a dual purpose driver that performs certain tasks at boot time, and other unrelated tasks after Windows has already started. It's developed as a boot start driver. I understand that the proper way to do this may be to develop 2 separate drivers, but I'd prefer to only go through the WinQual process once. There's also the added benefit of performing only one driver install in my app versus two. It needs to work on Vista through Win8 x86 & 64.
So what I'm really looking for is a safe way to determine in DriverInit if the system is in the process of booting, or if it's already up and running. The driver will initially be utilized when Windows has already started, then enabled at boot time after the next reboot. The DriverInit code needs to be different for both scenarios.
Is there a registry key that is or is not present?
Can I determine if a user is logged-in in DriverInit?
Is there a call I can make that will determine if Windows is booting?
I'm not an expert at driver writing, so thanks in advance for any advice.
Technically, glagolig's answer is probably the correct way to solve this.
The solution for my particular issue was a little different. There are 2 mutually exclusive use cases were the driver is either needed as a SERVICE_DEMAND_START driver after Windows is up and running, or as a SERVICE_BOOT_START driver with boot time functionality. The situation never arises were I need the functionality of both cases at the same time in the same Windows session.
The driver is initially installed as a SERVICE_DEMAND_START driver (this is the one that is going to WinQual). It is then changed to SERVICE_BOOT_START in the registry on the new drive that will be booted. All the driver entry points (DriverEntry, AddDevice, etc) that are different for each use case read the 'Start' value in the driver's service registry key to determine how it needs to operate.
It hasn't passed yet, but I'm fairly certain that I can change the start type of the driver in the registry without affecting Window's digital signature enforcement.
At the time boot-start drivers are loaded Windows has not created any user-mode processes yet. Try to acquire a handle to some process that is supposed to be created later on during Windows startup. For example, smss.exe, csrss.exe or wininit.exe . (Processes with these names existed for many years, it is very unlikely that Microdoft abandons them in the future while still allowing existing kernel mode modules to run.) Use ZwOpenProcess with POBJECT_ATTRIBUTES pointing to one of those process' names. If the call fails you are at boot time.
Also you may study Windows startup described in "Windows Internals" by Russinovich and Solomon. Most likely you will get a number of other ideas.
I've answered a similar question elsewhere on SO. The short version is that what you're asking is not normal driver behavior, so no API exists to support this. You can add in heuristics to tell you this, but they'll remain heuristics.
You can use IoGetBootDiskInformation to check if you are loaded post or, during boot. It will return STATUS_TOO_LATE if this API is called post reboot.

reason for crashing of the windows

I wrote some program which uses information about (reads via Windows) hardware of the current PC (big program, so I can't post here code) and sometimes my windows 7 crashes, the worst thing is that I have no idea why, and debug doesn't help me, is there any way to receive from windows 7 some kind of log, why it crashed? thanks in advance for any help
The correct (but somewhat ugly) answer:
Go to Computer->Properties, go to 'Advanced System Settings'.
Under startup and recovery, make sure it is set to "Kernel memory dump" and note the location of the dump file (on a completely default install, you are looking at C:\windows\memory.dmp)
You optimally want to install Windows Debugging tools (now in the Windows SDK) as well as setting the MS Symbol store in your symbol settings (http://msdn.microsoft.com/en-us/library/ff552208(v=vs.85).aspx)
Once youv'e done all that, wait for a crash and inspect memory.dmp in the debugger. Usually you will not see the exact crash because your driver vendors don't include symbols, but you will also generally get to see the DLL name that is involved in the crash, which should point you to what driver you are dealing with.
If you are not seeing a specific driver DLL name in the stack, it often indicates to me a hardware failure (like memory or overhead) that needs to be addressed.
MS has a good article here at technet that describes what I mentioned above (but step by step and in greater detail) http://blogs.technet.com/b/askcore/archive/2008/11/01/how-to-debug-kernel-mode-blue-screen-crashes-for-beginners.aspx
You can also look at the event log as someone else noted, but generally the information there is next to useless, beyond the actual kernel message (which can sometimes vaguely indicate whether the problem is driver or something else)

Delphi program & Windows 64-bit compatibility issue

I have some customers/candidate who complained that my program doesn't work on their Windows 7 64 bit version (confirmed with screenshots). The errors were strange, for example:
in the trial version i am
getting a error message whenever i
click on \"mark\" \"delete\" \"help\".
error msg is: Access violation at
address 0046C978 in module
\'ideduper.exe.\' read of address
00000004
windows 7 ultimate 64bit. i7 920
#2.67GHz 9gb or ram
'Mark', 'delete' and 'help' are just standard TToolButton on TToolbar.
The other example is failing to get a thumbnail from IExtractImage.
I have told them to try Compatibility mode but still doesn't work.
The problem is when I tested it on Windows 7 HP 64-bit on my computer (which I've done it before released it actually) it just works fine! So I don't know what causing it
Do you have any advice ?Are different Windows package (home basic,premium,ultimate,etc) treating 32 bit prog differently ?Are the newer version of Delphis (I use 2006) more compatible with 64 bit Windows ? Do I need to wait until 64 bit compiler out?
Thanks in advance
Your best bet in my opinion is to add MadExcept or EurekaLog or something similar to your application and give it to the customer to try again. MadExcept will generate log with stack trace, which will give you a clearer view of what is happening there.
To answer 2nd part of the question, 32bit Delphi programs work fine on 64bit Windows 7. I think it's more likely you have some memory management problems and the customer just happens to stumble upon them while you don't. Use FastMM4 to track those down.
Your applications is trying to access an invalid pointer. Changing environment may surface issues that are hidden in others. Check your application, and use FastMM + JCL+JCVL/MadExcept/EurekaLog to get a detailed trace of the issue. Some Windows APIs may have some stricter call requisites under 7 and/or 64 bit, but we would have to know what your app actually cals.
A free alternative to MadExcept is JCL Debug stuff. However it is less thorough and doesn't include the cool dialog box to send the stack trace to you via email, or as a file you can attach and manually email.
MadExcept is worth the money, and it is free for non-commercial use. You could try it first on your own PC, observe its functionality, and be sure it functions the way you want, and then buy it.
If buying Delphi is worth it (and it is!) then buying mad Except is a no brainer. But if you insist on rolling your own, JCLDebug (part of jedi code library) is also pretty nice.
Give them a stripped down version of your app and see when the problem goes away. I am betting it is your code as I never had any problems with my (hundreds of) W7/64 clients.
I'd be willing to bet it's an issue in your code. The reason it's failing on your customer's machine and not yours is that your machine probably has the default Data Execution Protection (DEP) enabled (which is turned on only for essential Windows programs and services), while your customer's computer is actually using DEP as intended (turned on for all programs and services).
The default setting (which is compatible with older versions of Windows, like 95/98/ME), allows software to execute code from what should be data segments. The more strict setting won't allow this, and raises a system-level exception instead.
You can check the settings between the two by looking at System Properties. I'm not at a Win7 machine right now, but on WinXP you get there by right-clicking on My Computer, choosing Properties, clicking on Performance Options, and then selecting the "Data Execution Prevention" tab. Find it on Vista/Win7 by using the Help; search for Data Execution Protection.
The solution, as previous answers have told you, is to install MadExcept or EurekaLog. You can also get a free version as part of JEDI, in JCLDebug IIRC. I haven't used it, so I can't vouch for it personally. I've heard it's pretty good, though.
If you don't want to go that route, set a breakpoint somewhere in the startup portion of your app (make sure to build with debugging info turned on). Run your app until the breakpoint is hit, and then use the IDE's Search->Goto Address (which is disabled until the breakpoint is hit). Enter the address from the exception dialog (not the one that's almost all zeros, but the 0046C978 address, prefixed with $ to indicate it's in hex) as in $0046C978. You'll probably end up in the CPU window looking at assembly code, but you can usually pick out a line of Delphi code of some sort that can sometimes give you a place to start looking.
In addition to all previous suggestions, I'll add the difference in accessing Registry under WOW64 compared to Win32. If your application is accessing Registry to read or write some settings, you should be aware of this. First, take a look at this and this page in the MSDN. On this page you will find 2 flags that determine the access you get to Registry from 32- or 64-bit application. KEY_WOW64_64KEY is the one that you should use.
In any case, I agree with others about using madExcept (or any other similar tool) to be able to find the exact cause of your problems.

Identify a reboot

Is there any "Boot session ID" or (reliable) "Boot timestamp"?
For an installation I need to detect that a scheduled reboot took place indeed.
I guess I could do a dummy MoveFileEx() with MOVEFILE_DELAY_UNTIL_REBOOT, but i did hope for something easier.
(We have to install a 3rd party package that sometimes behaves erratically after an repair/update. In that state, accessing the device may even lock up the system)
(Windows XP, Vista, 7)
For things like this, WMI (Windows Management Instrumentation) is often a good starting place. I know you can get current uptime directly through it, which may allow you to determine if a machine recently rebooted.
Here is a blog post with some code samples as well:
http://blogs.technet.com/heyscriptingguy/archive/2004/09/07/how-can-i-tell-if-a-server-has-rebooted.aspx
Depending on your implementation language, you probably just want to pull out the query code from the vbscript.
Apparently Windows has the equivalent of "uptime". Here's more info: http://support.microsoft.com/kb/555737
As I understand it, this should tell you how long ago the system was booted. Will that information solve your problem?
You could search the System event log for event 6009 from the EventLog source - this is the first event recorded after each reboot.
I think the best answer has already been given here: Find out if computer rebooted since the last time my program ran?
That seems to be the simplest way. Use GlobalFindAtom() to see if it exists and create it, with GlobalAddAtom(), if it doesn't. It will persist beyond the execution of your program. If your application runs again, and sees that the atom exists, then then it isn't the first run since reboot.
If the computer is restarted, then the atom won't exist, indicating that this is the first run of your program since the reboot.

Resources