Which control codes have be implemented in the control handler of a service - c

The SERVICE_STATUS documentation says this structure has to filled out when calling the SetServiceStatus() function.
The third field is dwControlsAccepted.
Unfortunately I have not found any information about which control codes MUST ALWAYS be implemented/react to, at least.
The page says:
By default, all services accept the SERVICE_CONTROL_INTERROGATE value.
But, is there a problem when the service control handler does not react to the SERVICE_CONTROL_STOP control code? Is there a problem when the service control handler does not at least call SetServiceStatus() in this case?

As far as dwControlsAccepted is concerned, there are no mandatory control codes. You can set this value to zero if that meets your needs. Apart from SERVICE_CONTROL_INTERROGATE your code does not need to handle any control codes that you have not specified as acceptable.
For example, if you have not set SERVICE_ACCEPT_STOP then Windows will never send you the SERVICE_CONTROL_STOP control. Any attempt to stop the service will result in error 1052, "The requested control is not valid for this service."
Note that unless you have a specific need to perform a clean shutdown (for example, because you have a database file that has to be properly closed) you do not need to accept shutdown controls either. Such a service will continue to run until the computer is actually powered down.
If you always set dwControlsAccepted to zero, this is all you need for a control handler:
static DWORD WINAPI ServiceHandlerEx(DWORD control, DWORD eventtype, LPVOID lpEventData, LPVOID lpContext)
{
if (control == SERVICE_CONTROL_INTERROGATE)
{
return NO_ERROR;
}
else
{
return ERROR_CALL_NOT_IMPLEMENTED;
}
}

Related

Detect Win+Tab Task View

On Windows 10, you can press Win+Tab to get a "Task View" view of all your windows. I'm trying to check if this is active at any given time. I have tried using a Low Level Keyboard Hook with WH_KEYBOARD_LL but this only allows me to detect the keypress, not if the switcher is active. I've looked at the Windows DWM API and haven't found anything else either.
I have also tried using EnumWindows() and EnumChildWindows(GetDesktopWindow(), ...) and did not find any difference in the output between having the task view shown and hidden.
Is there any accurate method to detect if this is being shown?
Here's a solution that works very consistently with my version of Windows (1709 build 16299.125) and doesn't require the processor-heavy approach of a call to EnumChildWindows:
bool isTaskView() {
//Get foreground window's name
HWND fgWindow = GetForegroundWindow();
TCHAR windowName[MAX_PATH] = L"";
GetWindowText(fgWindow, windowName, MAX_PATH);
//Compare with magic string name of Task View's window
std::wstring nameStr(windowName);
return nameStr == L"Task View";
}

WPF application continues even after explicit shutdown

I have a simple wpf application that continues to run even after I explicitly call it to shut down.
It integrates with a third party application and needs to check that a few documents of a certain type and with specific content are open as it initializes.
Here is a portion of the initialization code:
try
{
ActiveProductDoc = Automation.CATIA.ActiveDocument as ProductDocument;
}
catch
{
InvalidAssemblyShutdown("You must have an assembly open before you run the app");
}
if(ActiveProduct == null)
InvalidAssemblyShutdown("You must have one assembly open (not a part)");
ActiveProduct = ActiveProductDoc.Product;
And here is the InvalidAssemblyShutdown method:
private void InvalidAssemblyShutdown(string message)
{
MessageBox.Show(message);
Close();
Application.Current.Shutdown();
}
I have set the application's ShutdownMode property to OnMainWindowClose.
I am currently doing a use case test where the user has the wrong type of document open and so the ActiveProduct field is null. The InvalidAssemblyShutdown method is called as expected but despite this the line in the initialization method following the shutdown call still runs and throws an exception.
Any ideas what's going on?
Should I throw exceptions instead and use a global exception handler?
If you have a look at the source code for Application.Current.Shutdown (link to source), you'll see that it uses Dispatcher.BeginInvoke() to initiate the shutdown. In other words, the shutdown gets queued on the UI thread. It doesn't take effect during that precise method call, so the following code keeps executing.
You'll need to exit the code right after the call to Application.Current.Shutdown if you don't want some code to run while the shutdown request gets processed. Something like:
if(ActiveProduct == null)
{
InvalidAssemblyShutdown("You must have one assembly open (not a part)");
return; // prevent further code execution.
}
For what it's worth, this.Close() works in a similar way. So if you have proper flow control, you won't need to invoke Application.Current.Shutdown at all. Your call to this.Close() should be enough.

(Why) Does Windows "Calc.exe" lack a WndProc?

I am fiddling with wndprocs and WinSpy++ and i stumbled upon a strange thing with calc.exe.
It appears to lack a WndProc.
Here is my screenshot: a test program I made, the WinSpy++ window,, showing N/A, and the culprit.
Maybe the tool is a bit outdated, but the empirical evidence proves no WndProc is there.
I don't know if this is by design(this would be strange), or if I am missing something...
Here is referenced code:
Function FindWindow(title As String) As IntPtr
Return AutoIt.AutoItX.WinGetHandle(title)
End Function
Function GetWindowProc(handle As IntPtr) As IntPtr
Return GetWindowLong(handle, WindowLongFlags.GWL_WNDPROC)
End Function
In short (about your code): GetWindowLong() fails because you're trying to read an address in target process address space.
EXPLANATION
When GetWindowLong() returns 0 it means there is an error, from MSDN:
If the function fails, the return value is zero. To get extended error information, call GetLastError.
Check Marshal.GetLastWin32Error() and you probably see error code is ERROR_ACCESS_DENIED (numeric value is 0x5).
Why? Because GetWindowLong() is trying to get address (or handle) of window procedure (not in your code, but in target process, in theory it may even be default window procedure but I never saw an application main window that doesn't hanle at least few messages). You may use this trick (but I never tried!) to see if a window is using default procedure (you have an address or not), I don't know...someone should try.
Now think what WNDPROC is:
LRESULT (CALLBACK* WNDPROC) (HWND, UINT, WPARAM, LPARAM);
An address (valid in process A) is not callable in process B (where it makes no sense at all). Windows DLLs code segments are shared across processes (I assume, I didn't check but it's reasonable in the game between safety and performance).
Moreover CallWindowProc(NULL, ...) will understand that NULL as a special value to invoke window procedure for that window class (on HWND owner). From MSDN:
...If this value is obtained by calling the GetWindowLong function ...the address of a window or dialog box procedure, or a special internal value meaningful only to CallWindowProc.
How Microsoft Spy++ does it (and maybe WinSpy++ does not)? Hard to say without WinSpy++ source code. For sure it's not such easy like GetWindowLong() and right way should involve CreateRemoteThread() and to do LoadLibrary() from that but both Microsoft Spy++ and WinSpy++ source code aren't available (AFAIK) for further inspection...
UPDATE
WinSpy++ inspection/debugging is pretty off-topic with the question (you should post a ticket to developers, your source code may fail for what I explained above, you should - always - check error codes) but we may take a look for fun.
In InjectThread.c we see it uses WriteProcessMemory + CreateRemoteThread then ReadProcessMemory to read data back (not relevant code omitted):
// Write a copy of our injection thread into the remote process
WriteProcessMemory(hProcess, pdwRemoteCode, lpCode, cbCodeSize, &dwWritten);
// Write a copy of the INJTHREAD to the remote process. This structure
// MUST start on a 32bit boundary
pRemoteData = (void *)((BYTE *)pdwRemoteCode + ((cbCodeSize + 4) & ~ 3));
// Put DATA in the remote thread's memory block
WriteProcessMemory(hProcess, pRemoteData, lpData, cbDataSize, &dwWritten);
hRemoteThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)pdwRemoteCode, pRemoteData, 0, &dwRemoteThreadId);
// Wait for the thread to terminate
WaitForSingleObject(hRemoteThread, INFINITE);
// Read the user-structure back again
if(!ReadProcessMemory(hProcess, pRemoteData, lpData, cbDataSize, &dwRead))
{
//an error occurred
}
Window procedure in "General" tab and in "Class" tab differs (in "Class" tab it correctly display a value). From DisplayClassInfo.c:
//window procedure
if(spy_WndProc == 0)
{
wsprintf(ach, _T("N/A"));
}
else
{
wsprintf(ach, szHexFmt, spy_WndProc);
if(spy_WndProc != spy_WndClassEx.lpfnWndProc)
lstrcat(ach, _T(" (Subclassed)"));
}
//class window procedure
if(spy_WndClassEx.lpfnWndProc == 0)
wsprintf(ach, _T("N/A"));
else
wsprintf(ach, szHexFmt, spy_WndClassEx.lpfnWndProc);
As you see they're different values (obtained in different ways). Code to fill spy_WndProc is in WinSpy.c and GetRemoteWindowInfo.c. Extracted code from GetRemoteInfo() in WinSpy.c:
GetClassInfoEx(0, spy_szClassName, &spy_WndClassEx);
GetRemoteWindowInfo(hwnd, &spy_WndClassEx, &spy_WndProc, spy_szPassword, 200);
Now in GetRemoteWindowInfo() we see a call to GetClassInfoExProc (injected in the other process):
pInjData->wndproc = (WNDPROC)pInjData->fnGetWindowLong(pInjData->hwnd, GWL_WNDPROC);
pInjData->fnGetClassInfoEx(pInjData->hInst,
(LPTSTR)pInjData->szClassName, &pInjData->wcOutput);
As you can see (please follow using source code) wcOutput is what is displayed in "Class" tab and wndproc what is displayed in "General" tab. Simply GetWindowLong() fails but GetClassInfoEx does not (but they do not necessarily retrieve same value because (if I'm not wrong) what you have in WNDCLASSEX is what you registered with RegisterClassEx but what you get with GetWindowLong() is what you hooked with SetWindowLong().
You are right. It does not have a WndProc(...) function. It is just simply using a DlgProc to process the dialog events. I now this as I have written 'server/thin client' code in C/C++ to capture direct calls into windows API functions like WndProc(...). Any Windows GUI function really - BeginPaint(...) as an example. I used CALC.EXE as a test and executable runs on server while GUI calls are relayed/returned to/from the thin client. Have only tested calc.exe versions thru Vista. There is a chance the newer versions have been 'programmed' differently - meaning not using Win32 SDK. But, even MFC is just a shell to the Win32 SDK,

Silverlight CaptureDeviceConfiguration.RequestDeviceAccess() - how does it know?

CaptureDeviceConfiguration.RequestDeviceAccess() method must be invoked by user interaction, otherwise it fails. My question is how does Silverlight know the invocation came from user (i.e. via Button.Click())?
Have a look at this: http://liviutrifoi.wordpress.com/2011/05/18/silverlight-isolatedstoragefile-increasequotato/
Quote:
I was curios though how exactly does silverlight know what a user
initiated event is, but after digging through .net framework source
code I’ve got to a dead end:
if ((browserService == null) || !browserService.InPrivateMode())
{
//..
}
return false; //means that IncreaseQuota will fail
where browser.IsInPrivateMode is:
[SecuritySafeCritical]
public bool InPrivateMode()
{
bool privateMode = false;
return (NativeMethods.SUCCEEDED(UnsafeNativeMethods.DOM_InPrivateMode(this._browserServiceHandle, out privateMode)) && privateMode);
}
where DOM_InPrivateMode is in a DllImport["agcore"], which according
to microsoft is confidential :( So it looks like I won’t find out soon
how they’re detecting user initiated events, although I’m guessing
they have some centralized private method that detects clicks for
example, and then probably sets a flag that this was indeed “a user
initiated event”, and since you can’t forge clicks or keypresses using
javascript and since you can’t call those private methods using
reflection, it’s “safe”.

How do I get the selected text from the focused window using native Win32 API?

My app. will be running on the system try monitoring for a hotkey; when the user selects some text in any window and presses a hotkey, how do I obtain the selected text, when I get the WM_HOTKEY message?
To capture the text on to the clipboard, I tried sending Ctrl + C using keybd_event() and SendInput() to the active window (GetActiveWindow()) and forground window (GetForegroundWindow()); tried combinations amongst these; all in vain. Can I get the selected text of the focused window in Windows with plain Win32 system APIs?
TL;DR: Yes, there is a way to do this using plain win32 system APIs, but it's difficult to implement correctly.
WM_COPY and WM_GETTEXT may work, but not in all cases. They depend on the receiving window handling the request correctly - and in many cases it will not. Let me run through one possible way of doing this. It may not be as simple as you were hoping, but what is in the adventure filled world of win32 programming? Ready? Ok. Let's go.
First we need to get the HWND id of the target window. There are many ways of doing this. One such approach is the one you mentioned above: get the foreground window and then the window with focus, etc. However, there is one huge gotcha that many people forget. After you get the foreground window you must AttachThreadInput to get the window with focus. Otherwise GetFocus() will simply return NULL.
There is a much easier way. Simply (miss)use the GUITREADINFO functions. It's much safer, as it avoids all the hidden dangers associated with attaching your input thread with another program.
LPGUITHREADINFO lpgui = NULL;
HWND target_window = NULL;
if( GetGUIThreadInfo( NULL, lpgui ) )
target_window = lpgui->hwndFocus;
else
{
// You can get more information on why the function failed by calling
// the win32 function, GetLastError().
}
Sending the keystrokes to copy the text is a bit more involved...
We're going to use SendInput instead of keybd_event because it's faster, and, most importantly, cannot be messed up by concurrent user input, or other programs simulating keystrokes.
This does mean that the program will be required to run on Windows XP or later, though, so, sorry if your running 98!
// We're sending two keys CONTROL and 'V'. Since keydown and keyup are two
// seperate messages, we multiply that number by two.
int key_count = 4;
INPUT* input = new INPUT[key_count];
for( int i = 0; i < key_count; i++ )
{
input[i].dwFlags = 0;
input[i].type = INPUT_KEYBOARD;
}
input[0].wVK = VK_CONTROL;
input[0].wScan = MapVirtualKey( VK_CONTROL, MAPVK_VK_TO_VSC );
input[1].wVK = 0x56 // Virtual key code for 'v'
input[1].wScan = MapVirtualKey( 0x56, MAPVK_VK_TO_VSC );
input[2].dwFlags = KEYEVENTF_KEYUP;
input[2].wVK = input[0].wVK;
input[2].wScan = input[0].wScan;
input[3].dwFlags = KEYEVENTF_KEYUP;
input[3].wVK = input[1].wVK;
input[3].wScan = input[1].wScan;
if( !SendInput( key_count, (LPINPUT)input, sizeof(INPUT) ) )
{
// You can get more information on why this function failed by calling
// the win32 function, GetLastError().
}
There. That wasn't so bad, was it?
Now we just have to take a peek at what's in the clipboard. This isn't as simple as you would first think. The "clipboard" can actually hold multiple representations of the same thing. The application that is active when you copy to the clipboard has control over what exactly to place in the clipboard.
When you copy text from Microsoft Office, for example, it places RTF data into the clipboard, alongside a plain-text representation of the same text. That way you can paste it into wordpad and notepad. Wordpad would use the rich-text format, while notepad would use the plain-text format.
For this simple example, though, let's assume we're only interested in plaintext.
if( OpenClipboard(NULL) )
{
// Optionally you may want to change CF_TEXT below to CF_UNICODE.
// Play around with it, and check out all the standard formats at:
// http://msdn.microsoft.com/en-us/library/ms649013(VS.85).aspx
HGLOBAL hglb = GetClipboardData( CF_TEXT );
LPSTR lpstr = GlobalLock(hglb);
// Copy lpstr, then do whatever you want with the copy.
GlobalUnlock(hglb);
CloseClipboard();
}
else
{
// You know the drill by now. Check GetLastError() to find out what
// went wrong. :)
}
And there you have it! Just make sure you copy lpstr to some variable you want to use, don't use lpstr directly, since we have to cede control of the contents of the clipboard before we close it.
Win32 programming can be quite daunting at first, but after a while... it's still daunting.
Cheers!
Try adding a Sleep() after each SendInput(). Some apps just aren't that fast in catching keyboard input.
Try SendMessage(WM_COPY, etc. ).

Resources