WinKill() source code - c++

Can somebody share source code of WinKill() from AutoIt?
I want to know how it works with messages (yes/no/cancel) to be sure it's handled properly. I want to use it to clean desktop from unexpected pop-up windows.

As we can see below in the source code taken from the latest open source release of AutoIt (when it used to be open-source) and available here, the function sends WM_CLOSE message to the window. If the window doesn't get closed on 500ms, then it kills the process that created the window.
///////////////////////////////////////////////////////////////////////////////
// WinKill()
// Closes a window - uses more force than WinClose
///////////////////////////////////////////////////////////////////////////////
AUT_RESULT AutoIt_Script::F_WinKill(VectorVariant &vParams, Variant &vResult)
{
Win_WindowSearchInit(vParams);
if (Win_WindowSearch() == false)
return AUT_OK; // Required window not found
Util_WinKill(m_WindowSearchHWND);
Util_Sleep(m_nWinWaitDelay); // Briefly pause before continuing
return AUT_OK;
} // WinKill()
///////////////////////////////////////////////////////////////////////////////
// Util_WinKill()
//
// Closes a window with extreme predjudice
//
///////////////////////////////////////////////////////////////////////////////
void Util_WinKill(HWND hWnd)
{
DWORD dwResult;
LRESULT lResult = SendMessageTimeout(hWnd, WM_CLOSE, 0, 0, SMTO_ABORTIFHUNG, 500, &dwResult); // wait 500ms
if( !lResult )
{
// Use more force - Mwuahaha
// Get the ProcessId for this window.
DWORD pid;
GetWindowThreadProcessId( hWnd, &pid );
// Open the process with all access.
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
// Terminate the process.
TerminateProcess(hProcess, 0);
CloseHandle(hProcess);
}
} // Util_WinKill()

It is not an open source function. You can not know the source. However it is not complicated to understand. It is a simple function with a lot of If...then... calls to check the standards and then a simple kill of the window. Very similar to what you would do with an cmd command.
AutoIt has native and standard functions. Native ones are open source and you can find them in your AutoIt installed directory in the Include folder.
Standard ones on the other way are not open source. They are written in C++.

Related

How to use run-time dll injecting to write into a Running and Temp notepad/txt file

Basically I created a simple Dll injection code with a basic Dll that shows a message box and my question is how can I now use the Dll file to make it write text into the Notepad while its running and it hasn't been saved/is temporary?
Is there a way to find a path to the file?
(i don't think so because its still writing into the ram and is untitled so doesn't have a save on any drives)
Or is there a stream i can write into?
Like Timo said in the comment, you can get the handle to the Notepad's Window, and then use it to write text into it, and it even wouldn't require from you to inject your DLL into the Notepad Process.
In Windows, every window is receiving messages from the Operating System (or from other programs, like what you're going to try out), those messages tell the window what action was made, for instance - Pressing down a key, or pressing a mouse button. That way, the program controlling the Window will know what kind of action it's supposed to do.
You can use the Spy++ Tool (spyxx.exe, comes builtin in every Visual Studio) to track what Windows does when you press a key down the keyboard into the Notepad's Window.
You can read further about the topic of window messages here:
https://learn.microsoft.com/en-us/windows/win32/learnwin32/window-messages
And working with Spy++ here:
https://learn.microsoft.com/en-us/visualstudio/debugger/introducing-spy-increment?view=vs-2019
Opening Spy++, we can see all the Windows in the our session, and we look for the Notepad's:
how it looks
Small POC I made for searching the appropriate Window, according to what found by Spy++ (forgive me for the globals, and make sure you are aware of what I did here):
HWND notepad_window;
HWND notepad_edit;
BOOL CALLBACK GetEditWindow(HWND hWnd, LPARAM lParam)
{
wchar_t window_text[MAX_PATH] = { 0 };
if (0 != GetClassNameW(hWnd, window_text, MAX_PATH))
{
std::wstring text(window_text);
if (std::wstring::npos != text.find(L"Edit"))
{
std::wcout << "Found it" << text << std::endl;
notepad_edit = hWnd;
return false;
}
}
return true;
}
BOOL CALLBACK GetNotepadWindow(HWND hWnd, LPARAM lParam)
{
wchar_t window_text[MAX_PATH] = { 0 };
// Fun fact - The GetWindowTextW also posts a window message to the window, the WM_GETTEXT message
if (0 != GetWindowTextW(hWnd, window_text, MAX_PATH))
{
std::wstring text(window_text);
if (std::wstring::npos != text.find(L"Notepad"))
{
std::wcout << "Found it" << text << std::endl;
notepad_window = hWnd;
return false;
}
}
return true;
}
int wmain()
{
EnumWindows(GetNotepadWindow, 0);
EnumChildWindows(notepad_window, GetEditWindow, 0);
}
After you have the HWND, you can start dealing with the message posting. You can use Spy++ again to 'tap' on the Notepad's Edit Window, and see every Window Message sent when pressing down a key, you will see the WM_KEYDOWN, followed by a WM_KEYUP most likely.
Then, you can use the PostMessage WinAPI function to post your own WM_KEYDOWN/KEYUP messages to the Notepad Window, hence controlling the input it gets.

EnableWindow(hWnd, false) doesn't disable keyboard input

I am attempting to disable a window under certain conditions using EnableWindow(hWnd, false);
According to the documentation, this should "disable mouse and keyboard input to the specified window".
The problem I am seeing is that it does, in fact, disable like it says, except if the cursor is currently inside of a text box in the window and the window has the focus that does not get disabled. I was thinking of doing some sort of code to take the focus off of the window as well.
Is there a better way to go about this?
Note: The window being disabled is a binary ran via _spawnl().
I'm not sure if this is a Windows feature or a bug. Either way, disabling the foreground window is not a good idea.
If you are able to modify the program you start with _spawnl() then that is a better solution. You could make it respond to WM_APP or something like that when you need to control it.
If it is a 3rd-party application then you are left with hacks.
You could try to change the foreground window with SetForegroundWindow but this will only work if you do it very soon after _spawnl() before your thread loses the foreground lock. Using LockSetForegroundWindow before _spawnl() might be able to help you keep the lock longer. There are also various other hacks to change the foreground with AttachThreadInput etc.
If you don't want to change the foreground I was able to come up with a workaround:
ShellExecute(NULL, NULL, TEXT("Notepad"), NULL, NULL, SW_SHOW);
Sleep(2000);
HWND hNP = FindWindow(TEXT("Notepad"), NULL);
Sleep(2000); // Start typing in Notepad now...
if (hNP)
{
DWORD tid = GetWindowThreadProcessId(hNP, NULL);
GUITHREADINFO gti;
gti.cbSize = sizeof(gti);
if (tid && GetGUIThreadInfo(tid, &gti))
{
HWND hChild = NULL;
if (gti.hwndFocus != hNP && gti.hwndFocus)
{
EnableWindow(hChild = gti.hwndFocus, false);
}
if (GetForegroundWindow() == hNP)
{
SendNotifyMessage(hNP, WM_ACTIVATE, WA_INACTIVE, NULL);
SendNotifyMessage(hNP, WM_ACTIVATE, WA_ACTIVE, NULL);
SendNotifyMessage(hNP, WM_SETFOCUS, NULL, NULL);
// SendNotifyMessage(hNP, WM_NCACTIVATE, false, NULL); // Uncomment to make it look like it is inactive
}
EnableWindow(hNP, false);
if (hChild)
{
EnableWindow(hChild, true);
}
}
MessageBox(NULL, TEXT("Done?"), NULL, MB_TOPMOST);
SetForegroundWindow(hNP);
PostMessage(hNP, WM_CLOSE, 0, 0);
}
This is certainly not optimal, it leaves Notepad in a state where it looks like it is enabled but it is really not. The idea is to disable the focused child window and trigger a fake activation change and forcing the focus to change. It might not work with other applications, who knows.
If you are willing to risk a deadlock you can do this instead:
DWORD tid = GetWindowThreadProcessId(hNP, NULL);
GUITHREADINFO gti;
gti.cbSize = sizeof(gti);
if (tid && GetGUIThreadInfo(tid, &gti))
{
if (GetForegroundWindow() == hNP)
{
if (AttachThreadInput(GetCurrentThreadId(), tid, true))
{
SetFocus(NULL);
AttachThreadInput(GetCurrentThreadId(), tid, false);
}
}
EnableWindow(hNP, false);
}

How to display a modal dialog window from another process?

I have a 32-bit MFC application that uses a custom library that would be a nightmare to re-compile into x64. In general the app doesn't really need to run as 64-bit, except in one case -- and that is to render contents to display in a dialog window, which can benefit from a larger addressing space.
So my goal is to "imitate" CDialog::DoModal method but for a dialog in another process.
I built that dialog window as a standalone x64 MFC dialog-based application. It takes a file path as it's input parameter, does all the work internally, and returns simple user selection: OK, Cancel.
So I do the following from my main parent process:
//Error checks omitted for brevity
CString strCmd = L"D:\\C++\\MyDialogBasedApp.exe";
HWND hParWnd = this->GetSafeHwnd();
SHELLEXECUTEINFO sei = {0};
sei.cbSize = sizeof(sei);
sei.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_UNICODE | SEE_MASK_NOCLOSEPROCESS;
sei.nShow = SW_SHOW;
sei.lpVerb = _T("open");
sei.lpFile = strCmd.GetBuffer();
sei.hwnd = hParWnd;
BOOL bInitted = SUCCEEDED(::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE));
ShellExecuteEx(&sei);
DWORD dwProcID = ::GetProcessId(sei.hProcess);
//Try to get main Wnd handle for the child process
HWND hMainChildWnd = NULL;
for(;; ::Sleep(100))
{
hMainChildWnd = getHwndFromProcID(dwProcID);
if(hMainChildWnd)
break;
}
HWND hPrevParWnd = ::SetParent(hMainChildWnd, hParWnd);
if(hPrevParWnd)
{
//Wait for child process to close
::WaitForSingleObject(sei.hProcess, INFINITE);
//Reset parent back
::SetParent(hMainChildWnd, hPrevParWnd);
}
::CloseHandle(sei.hProcess);
if(bInitted)
::CoUninitialize();
where getHwndFromProcID is taken from here.
This kinda works, except of the following:
(1) There are two icons on the taskbar: one for my main app, and one for the child app. Is there a way not to show a child icon?
(2) I can switch focus from child window to parent and vice versa. In actual modal dialog window one cannot switch back to parent while child is open. Is there a way to do that?
(3) If I start interacting with the parent, it appears to be "hung up" and the OS will even show it on its title bar.
So I was curious if there's a way to resolve all these?
you need pass pointer of own window to child process
you need process windows messages, while you wait on child process
exit. WaitForSingleObject unacceptably here - need use
MsgWaitForMultipleObjectsEx
child process must set your window as self owner window at create
time - you not need call SetParent
with this all will be worked perfect. in your 32-bit MFC application you need use next code :
BOOL DoExternalModal(HWND hwnd, PCWSTR ApplicationName)
{
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
WCHAR CommandLine[32];
swprintf(CommandLine, L"*%p", hwnd);
if (CreateProcessW(ApplicationName, CommandLine, 0, 0, 0, 0, 0, 0, &si, &pi))
{
CloseHandle(pi.hThread);
MSG msg;
for (;;)
{
switch (MsgWaitForMultipleObjectsEx(1, &pi.hProcess, INFINITE, QS_ALLINPUT, 0))
{
case WAIT_OBJECT_0:
CloseHandle(pi.hProcess);
return TRUE;
case WAIT_OBJECT_0 + 1:
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
continue;
default: __debugbreak();
}
}
}
return FALSE;
}
in MyDialogBasedApp.exe let use MessageBox as demo dialog. we will be use your MFC window as first argument to it.
void ExeEntry()
{
int ec = -1;
if (PWSTR CommandLine = GetCommandLine())
{
if (CommandLine = wcschr(CommandLine, '*'))
{
HWND hwnd = (HWND)(ULONG_PTR)_wcstoi64(CommandLine + 1, &CommandLine, 16);
if (hwnd && !*CommandLine && IsWindow(hwnd))
{
ec = MessageBoxW(hwnd, L"aaa", L"bbb", MB_OK);
}
}
}
ExitProcess(ec);
}
with this code:
(1) There are only one icon on the taskbar for your main app
(2) You can not switch focus from child window to parent and vice versa. all work as actual modal dialog window
(3) parent not "hung up" because it processing windows messages (MsgWaitForMultipleObjectsEx) - your code is "hung up" because you not do this, but wait in WaitForSingleObject
A modal dialog box does two things that make it "modal":
The dialog's "owner" is set to the parent window.
The parent window is disabled.
I played around with this a little bit and while you can do these manually, the easiest way is to just pass the parent window handle to the DialogBox function (or the CDialog constructor in MFC).
Instead of doing all the work after ShellExecuteEx in the parent process, your child process can use FindWindow (or a similar mechanism) to get the parent window handle and use that to display the dialog.
What you are trying to do cannot safely be done. The blog entry Is it legal to have a cross-process parent/child or owner/owned window relationship? explains, that installing a cross-process owner/owned window relationship causes the system to call AttachThreadInput, and - as we all know - AttachThreadInput is like taking two threads and pooling their money into a joint bank account, where both parties need to be present in order to withdraw any money. This creates a very real potential for a dead lock. You can only safely prevent this from happening, if you control both participating threads. Since at least one thread uses a 3rd party application framework (MFC in this case), this is off limits.
Since we have established, that your proposed solution cannot safely be implemented, you need to look into alternatives. One solution might be to delegate the work to a 64-bit process for computation, and have the results passed back to your 32-bit process for display.

Creating Responsive Windows winapi c++

I am just learning to create a gui using the winapi, but i have run into an issue. I can create a window like this
#include "stdafx.h"
#include <windows.h>
int main()
{
HWND hwnd = CreateWindow(L"STATIC",NULL,WS_VISIBLE|WS_SYSMENU|WS_CAPTION,0,0,600,600,NULL,NULL,NULL,NULL);
UpdateWindow(hwnd);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
_gettch();
}
But the windows will not close when the close button is clicked, and the window can not be dragged around or moved. I was wondering how i would enable these features of the window.
Static windows are not there for normal windows, you should try and look up how to register and handle your own class with RegisterWindowEx then use the same class name to create a window. You have to have your own window procedure in order to handle messages.
All window classes registered by the system run their own default window procudure and as far as I know none of them handle WM_CLOSE ( that is the close button ) this is why you can't close it.
For you main windows always use something like WS_OVERLAPPEDWINDOW so it'll be clear if it's okay or not and from that eliminate the flags you don't need.
How you set it up :
WNDCLASSEX wndcls;
HWND hMainWnd;
// Register your own window class
ZeroMemory(&wndcls,sizeof(WNDCLASSEX));
wndcls.cbSize=sizeof(WNDCLASSEX);
wndcls.style=CS_VREDRAW+CS_HREDRAW;
wndcls.lpfnWndProc=&appWndFunc;
wndcls.hInstance=hInstance;
wndcls.hIcon=hMainIcon; // or just LoadIcon(hInstance,MAKEINTRESOURCE(IDI_MAIN_ICON))
wndcls.hIconSm=hMainIcon;
wndcls.hCursor=LoadCursor((HINSTANCE)NULL,IDC_ARROW);
wndcls.hbrBackground=(HBRUSH)COLOR_APPWORKSPACE;
wndcls.lpszClassName="myWndClass";
if (RegisterClassEx(&wndcls)==0)
{
// failed to register class name
return false;
}
// Create window with your own class
hMainWnd=CreateWindowEx(0,\
"myWndClass","widnow title",\
WS_OVERLAPPEDWINDOW|WS_VISIBLE,\
0,\
0,\
250,\
250,\
hMainWnd,NULL,hInstance,NULL);
if (hMainWnd==(HWND)NULL)
{
// failed to create main window
return false;
}
Then your main loop :
bool bAppMainLoop=false
while(!bAppMainLoop)
{
WaitMessage();
while(PeekMessage(&emsg,NULL,0,0,PM_NOREMOVE))
{
if(GetMessage(&emsg,NULL,0,0)==0)
{
bAppMainLoop=true;
break;
}
TranslateMessage(&emsg);
DispatchMessage(&emsg);
}
}
This is a bit more than usual setup, so let me explain , in order to not burn CPU, you wait for a message with WaitMessage, it'll block until something happens, like move window, click, paint etc. PeekMessage will return true if there is a message so calling it in a while loop will make sure it drains the message quene, GetMessage will obtain the message if it returns 0 it means that your app called the PostQuitMessage(0) so a WM_QUIT arrived was found in the message loop that means it's time to break out from the message loop. The rest Translate and Dispatch does what it name says.
Finally you need your own window procedure :
LRESULT CALLBACK appWndFunc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
if (uMsg==WM_CLOSE)
{
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
DefWindowProc is essential that handles all commonly occurring messages from the system, thus you don't need to handle those here. You simply respond to the WM_CLOSE message which is sent when you want to close the window and post a quit message into the message loop that you will catch and exit.
Additional info :
It's not required to release your stuff since windows does that for you so it wont be locked the next time you start your program , but it's a good practice to at least Unregister your window class after your main loop.
Btw that is the wrong main function : WinMain that is the correct one. Plus to avoid even more bugs make sure you compile a windows GUI application.

Abort thread properly when dialog box close button is clicked

Hello my fellow colleagues from StackOverflow!
I will try to be brief, so I will cut to the point:
I work on Windows XP, in C++, using pure Win32 to create a dialog box.
That dialog box has some edit controls, and OK button, which activates a thread when pressed.
Thread then gathers text from edit controls and writes them into MS Word document, using OLE Automation.
Everything works fine,when I press OK button, and wait for thread to show filled Word document.
However, when I push the OK button and then close the dialog, while thread is in the middle of the work, a blank Word document pops up.
To further illustrate my problem here are some code snippets:
This is snippet for thread function:
DWORD WINAPI TabelaSvihObjekata( LPVOID hWnd ) // hWnd is handle of the Dialog box
{
// obtain dialogs window handle
HWND hwnd = (HWND)hWnd;
// Initialize COM for this thread...
CoInitialize(NULL);
// Get CLSID for our server...
CLSID clsid;
HRESULT hr = CLSIDFromProgID(L"Word.Application", &clsid);
// do other Automation stuff and clean afterwards
}
In dialog box, this is the snippet for button handler:
case IDOK:
{
// create thread
DWORD threadID;
HANDLE threadHandle = CreateThread( NULL , 0 ,
(LPTHREAD_START_ROUTINE)TabelaSvihObjekata ,
(void*)hwnd , 0 , &threadID );
if( !threadHandle )
{
MessageBox( hwnd, L"Error", L"Error", MB_ICONERROR );
EndDialog( hwnd, IDCANCEL );
}
CloseHandle( threadHandle );
}
And this is the problematic handler:
case IDCANCEL:
EndDialog(hwnd, IDCANCEL);
break;
I have looked on MSDN for a clue, and have found only ExitThread as a solution, but I don't know how to use it properly since I am inexperienced with threads.
Browsing through SO archive, I have found some examples in C# where people introduce boolean variable and test it's value in while loop, so they can determine whether to abort the thread or let it work.The other way was suggested, where thread is placed in separate process and then killed.
My question is:
What should I add or change, so when I close the dialog box, Word application closes along with threads destruction ?
If there is anything else that I can do to help, ask and I will gladly do it.
Thanks to everybody who tries to help.
If you use WinApi you have to make threadhandle accesible by other part of code.
Then to terminate your thread you can use ExitThread - this is preferred option by MSDN. I show you how you can use it:
DWORD threadID;
HANDLE hthread;
void TerminateYourThread()
{
DWORD exitCode;
if(GetExitCodeThread(hThread,&exitCode) != 0) // check if your thread is active
{
ExitThread(exitCode); // terminating thread
if(CloseHandle(hThread)) // closing handle
{
//
}
}
}
void CreateYourThread()
{
hThread = CreateThread( NULL , 0 ,
(LPTHREAD_START_ROUTINE)TabelaSvihObjekata ,
(void*)hwnd , 0 , &threadID );
}
Now when you want to terminate the thread just call TerminateYourThread function. It waits until thread is closed. This is only suggestion not finally solution so you can refactor it in the future.