How to create a win32 application without window in background with C? - c

The application do not need any window or console. It can be a console application if the console window can be removed or can be put into background. The application will do some simple tasks(such as cleaning rubbish files) and exit.
I hope that the application should not be a windows service if possible.
I hope that the application can be started with double-click in explorer window and run silently.
When the application is running, I hope that the mouse cursor should not be changed to hourglass shape. That is to say, do not disturb the user when the application is running. Just run and exit silently.
DO NOT NEED to run it when windows starts or user logins.
I hope this can be done in C if possible. What should I do?
task_finished = 0;
CreateThread(NULL, 65535, task_thread, para, 0, NULL);
MSG msg;
while(!task_finished){
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if(task_finished)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

IIRC, you can do this by just writing a WinMain function that doesn't create or display a window or console. Lambert's answer about using a message loop will help you if you want your program to be able to send or receive messages from other programs, but if you're just doing simple background processing all you should need is a WinMain that doesn't make a window.

All you need is a message loop -- just use this code (modified from here):
MSG msg;
BOOL bRet;
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Edit:
For I/O or other tasks, you can either (1) create another thread, and do everything from there, or (2) Use MsgWaitForMultipleObjects inside the loop (before the next GetMessage() call) to simultaneously wait on your I/O and on messages, so that you can be notified when there's either a message, or when your I/O is finished.
Warning:
I haven't figured out how to make the application not bring up the hourglass shape when starting. If you need that functionality, consider creating a Windows service instead. You can also compile as a console application, then use FreeConsole to hide the window.

Related

Get message from other window

I try to get some messages from other windows. I need to find window by name, I used FindWindowW(). How can I get active window and get message from its?
When I add hwnd in GetMessage(), it doesn't work.
//WndProc
case WM_KEYDOWN:
OutputDebugStringW(L"Key down");
break;
//main.c
//WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
hwnd = FindWindowW(NULL, L"Sublime Text");
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
Only the thread that creates a window can directly receive and dispatch messages for that window. GetMessage() retrieves messages from the calling thread's message queue, so it can only be used with windows that are owned by the calling thread.
Since you are trying to catch messages for a window that is not yours, you will have to use SetWindowsHookEx() or SetWinEventHook() to install a hook callback into that window's owning thread, and then that callback can intercept the desired messages/events for that window. You can use GetWindowThreadProcessId() to get the IDs of the Process and Thread that own the window.
If you use SetWindowsHookEx() and are trying to hook a window in another process, your callback must reside in a DLL so it can be injected into that process. You do not need to do that with SetWinEventHook().

Click button of other window from other process

I'm new to WinAPI and I already created an empty window. Now I want to make a little hack for the tutorial program of Cheat Engine. I already know, how to change values in the memory of other processes. But as soon as I changed a value in the tutorial program, I'm forced to click a "next" button. So my question is: Is it possible to send a click command to a window of another process? I have a handle of the window, a handle of the process and the process id (if it is not the same).
The only thing I know about the buttons is, that their text is always "next".
Here is a shortened version of my code:
HWND hWnd = FindWindow (NULL, L"Window's title"); // Search startup window
DWORD pid; // Get process id
GetWindowThreadProcessId (hWnd, &pid);
HANDLE hProc = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid); // Get access to process
DWORD base = 0x789ABCDE; // Get value of static pointer
ReadProcessMemory (hProc, &base, &base, 4, NULL);
WORD offset = 0xBCDE; // Write to memory
WriteProcessMemory (hProc, (void *)(base + offset), (void *)5000, 4, NULL);
// Send click command (???)
Sorry, if my english and/or some technical terms aren't correct, but I'm new to Win32.
EDIT:
I discovered, that the tutorial forbits every memory access, so my project will never work. In addition, GetLastError(); always returns ERROR_INVALID_PARAMETER when I try to install a second windows procedure for the tutorial program. Do I have to use hProc instead of pid in SetWindowsHookEx (WH_CALLWNDPROC, &fnHook, NULL, pid);?
The simplest way to do this is to use SendMessage() to send an WM_LBUTTONDOWN and then a WM_LBUTTONUP message to the given window, something like
// x, y are the coords
SendMessage(hWnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(x, y));
SendMessage(hWnd, WM_LBUTTONUP, MK_LBUTTON, MAKELPARAM(x, y));
This may or may not work in your particular case; if the spot that you're trying to click is actually in a child window or a popup you've just "clicked" the wrong window, and a lot of apps rely on other messages.
The more reliable way to do it is to call SetWindowsHookEx(WH_MOUSE, ...), and "play" the mouse messages through the given hook procedure. I haven't done that in a couple of decades so can't really talk about it in detail.

Simple and effective way to stall a program

I have a program that sets a global keyboard hook and handles key presses. This is my WinMain:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nCmdShow)
{
MSG msg;
logFile = fopen("C:\\keylog.txt", "w");
hKeyHook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeyEvent, GetModuleHandle(NULL), 0);
GetMessage(&msg, NULL, 0, 0);
UnhookWindowsHookEx(hKeyHook);
fclose(logFile);
return 0;
}
Since it doesn't create any windows it won't ever receive a window message, so GetMessage would stall the program, and it is very light on CPU cycles. However, when it detects a certain key is pressed I want it to exit the program. I can't broadcast a message because it won't receive it. If I do something like:
while(State == true)
Sleep(500);
The program itself and the global hook would stall and this is undesirable. Making it Sleep(0) makes it consume an unmanageable amount of CPU cycles.
So, what is the best alternative for my problem? The only thing I can think of is going through the trouble to register my own window class and create a window to receive the message, but perhaps there is a better way?
Why not create synchronization object (maybe Event) and replace GetMessage with WaitForSingleObject?
You can easily make your keyboard hook routine trigger the object and your app will do the pre-termination stuff.
You can't broadcast a message using HWND_BROADCAST.
You don't need a window to receive messages. However, if you had some way to publish your thread id, then PostThreadMessage() could be used to send a message (probably a WM_QUIT) to your app.

Programmatically press a button on another application (C, Windows)

I'm trying to use the following code to press a button on my other application:
HWND ButtonHandle;
if( (wnd = FindWindow(0, "Do you want to save?")) )
{
ButtonHandle = FindWindowEx(wnd, 0, "SaveButton", "&Save");
SendMessage(wnd, WM_COMMAND, MAKEWORD(GetDlgCtrlID(ButtonHandle), BN_CLICKED ), (LPARAM)ButtonHandle);
}
It doesn't work. I tried passing different handles to MAKEWORD and to change the WPARM and LPARAM but nothing.
Any ideas on how to click a button on another application's window?
Code is appreciated.
Thanks.
EDIT:
The reason it doesn't seem to work permissions. I sent a PostMessage() and the result was an error with GetLastError() = 5 (or Access Denied).
Any ideas?
EDIT2 I don't mean to be rude but please please please, I already searched all the API's including getting and setting the regions for the button and then sending a button down and button up, getting the control ID, getting the class ID and a zillion more.
The reason I asked the question here in the first place is because I already exhausted my search on the internet.
If you know the answer PLEASE POST CODE, do not suggest an API and that's it, show me how does that API solves the problem. It's not hard.
thank you.
EDIT 3: The question's answer was selected automatically when the bounty finished. The question still remains without an answer.
Are you sure that "SaveButton" class name is valid? Do you get the button
handle?
Try to send messages to ButtonHandle window (directly to the button).
Update: I believe this should work,
SendMessage(ButtonHandle, BM_CLICK, 0, 0);
See the following solution, also you can use
SendMessage(ButtonHandle, WM_LBUTTONDOWN, 0, 0);
SendMessage(ButtonHandle, WM_LBUTTONUP, 0, 0);
Or
SendMessage(ButtonHandle, BM_CLICK, 0, 0);
HWND buttonHandle = 0;
BOOL CALLBACK GetButtonHandle(HWND handle, LPARAM)
{
char label[100];
int size = GetWindowTextA(handle,label,sizeof(label));
if(strcmp(label,"&Save") == 0)
{
buttonHandle = handle;
return false;
}
return true;
}
void main()
{
HWND windowHandle = FindWindowA(NULL,"Do you want to Save?");
if(windowHandle != 0)
{
BOOL ret = EnumChildWindows(windowHandle,GetButtonHandle,0);
if(buttonHandle != 0)
{
LRESULT res = SendMessage(buttonHandle,BM_CLICK,0,0);
//SendMessage(buttonHandle,WM_LBUTTONDOWN,0,0);
//SendMessage(buttonHandle,WM_LBUTTONUP,0,0);
}
}
}
Note:
Getting sure from the window text,button text (check if there is space at the end of the window title)
SendMessage(btnHandle, WM_LBUTTONDOWN, 0, 0);
SendMessage(btnHandle, WM_LBUTTONUP, 0, 0);
SendMessage(btnHandle, WM_LBUTTONDOWN, 0, 0);
SendMessage(btnHandle, WM_LBUTTONUP, 0, 0);
You have to send a button click twice. Not sure why (maybe the first click only activates the window of the button), but I'm using this code for a long time and it always worked for me.
maybe this can help:
http://www.cplusplus.com/forum/beginner/8806/
Access Denied errors on SendMessage or PostMessage make no sense unless the process sending the message is running at a lower integrity level than the target process.
This should not be happening unless the process that owns the target window is being run "asAdministrator" or is a service. And its damn hard for services to create windows on the interactive desktop with Windows 6 and up.
You can do some reading about Integrity Levels Here if they apply even remotely to this situation. Internet Explorer is about the only other application that 'opts in' to the integrity security model by purposely lowering the integrity level of itself in order to sandbox itself more effectively.
If you can raise the window containing the button you can send raw mouse event to a position within the boundaries of button.
There are two function to simulate mouse event SendInput and mouse_event. I recommend using mouse_event function. To raise a window you can use ShowWindow. I don't know how to get the handle of a button, but if you have its hWnd its easy to find its absolute position using GetWindowRect function. Try using these, if you run into any problems I will be glad to help.
Or define a custom WM within your application window to handle save request. WM_CUSTOM or WM_USER (cant remember which) marks the start of user defined window messages.
When I have to do these kind of things I use SendKeys. It is VB-ish and C# provides a nice interface to use but for C/C++ you'll have to do it <this way>. What is nice with it is that you could write scripts and run them instead of hard coding it in your code.
Microsoft is now pushing Active Accessibility (MSAA) for UI Automation,
(It has been renamed a number of times over the years)
see
UI Automation and Microsoft Active Accessibility
Using UI Automation for Automated Testing
UI Automation Clients for Managed Code
Sorry I don’t have any simple code to get you started. As “SendMessage()” does not seem to be working for you, I don’t know of another option apart from “UI Automation”
I am assuming you have check with Spy++ (installed with MsDev) that you message are being send to the correct button etc – and that the button is a standard windows buttons. My first instant would say use “SendMessage()" or "PostMessage()” but given the numbers of answers about “SendMessage()” and the fact it is not working for you. I expect someone is going on…
//Send digit 4 to the already opened calc.exe
HWND windowHandle;
windowHandle = FindWindowA(NULL,"Calculator");
if(windowHandle != 0)
ret = EnumChildWindows(windowHandle,GetButtonHandle,0);
BOOL CALLBACK GetButtonHandle(HWND handle, LPARAM)
{
char label[100];
int size = GetWindowTextA(handle,label,sizeof(label));
if(strcmp(label,"4") == 0)
{
PostMessage(handle ,WM_LBUTTONDOWN,(WPARAM)0x0001,0);
PostMessage(handle ,WM_LBUTTONUP,(WPARAM)0x0001,0);
PostMessage(handle ,WM_LBUTTONDOWN,(WPARAM)0x0001,0);
PostMessage(handle ,WM_LBUTTONUP,(WPARAM)0x0001,0);
return false;
}
return true;
}
You can use sendkeys (as tr3 said) to send mouse clicks, which is different than using SendMessage. It is also less direct and more hack-ish, but is useful for automation (in VBS).
Also, just a guess but the problem could be that your message handling is broken somewhere by not calling the base class member. Example:
void CMyClass::OnMessageY(CWnd *cwnd)
{
CBaseClass::OnMessageY(cwnd);
//... my code
}
if you sure ButtonHandle are valid handle you can use pair WM_LBUTTONDOWN and WM_LBUTTONUP message instead of BN_CLICKED
HWND ButtonHandle;
if( (wnd = FindWindow(0, "Do you want to save?")) )
{
SendMessage(ButtonHandle, WM_LBUTTONDOWN, MK_LBUTTON, 0);
SendMessage(ButtonHandle, WM_LBUTTONUP, MK_LBUTTON, 0);
}
A non-C approach: Use Java and the java.awt.Robot class to move the mouse around perform real clicks (I guess there is something in the Windows World for this, too).
Problem: You have to know where your button is :D

Smooth animations using Win32 API - without controlling the message pump

I'm currently trying to integrate some animation drawing code of mine into a third party application, under the form of an external plugin.
This animation code in realtime 3d, based on OpenGL, and is supposed to render as fast as it can, usually at 60 frames per second.
In my base application, where I'm the king of the world, I control the application message pump, so that drawing occurs whenever possible. Like that :
for (;;)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
do
{
if (msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE));
}
draw();
}
Now that I'm no more king in the world, I have to play nice with the application messages, so that it keeps being responsive. To my knowledge, as I'm a plugin, I can't hijack the whole application message pump ; so I tried various things, doing my drawing in WM_PAINT message handler :
Use WM_TIMER, which doesn't work :I don't know in advance which time step I need (often not fixed) and the timing in not accurate.
Call InvalidateRect as soon as I'm done drawing, doesn't work : completely prevents the rest of the application of being responsive and doing its own refreshing.
Create a 'worker' thread, whose only job is to post a user message to the plugin window. This message is posted as soon as the drawing is finished (signaled by an event). The user message handler, in turn, calls InvalidateRect (see there).
So far, my last attempt is the better, and sometimes work fine.
DWORD WINAPI PaintCommandThreadProc(LPVOID lpParameter)
{
Plugin* plugin = static_cast<Plugin*>(lpParameter);
HANDLE updateEvent = plugin->updateEvent();
while (updateEvent == plugin->updateEvent())
{
::WaitForSingleObject(updateEvent, 100);
::Sleep(0);
if (updateEvent == plugin->updateEvent())
{
::PostMessage(plugin->hwnd(), WM_USER+0x10, 0, 0);
}
}
return 0;
}
...
LRESULT CALLBACK PluginWinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
bool processDefault = true;
LRESULT result = 0;
Plugin* plugin = reinterpret_cast<Plugin*>( GetWindowLong(hWnd, GWL_USERDATA) );
switch (msg) {
...
case WM_GL_MESSAGE:
{
::InvalidateRect( hWnd, NULL, FALSE );
processDefault = false;
result = TRUE;
}
break;
case WM_PAINT:
{
draw(hWnd);
::SetEvent( plugin->updateEvent() );
processDefault = false;
result = TRUE;
}
break;
...
}
if (processDefault && plugin && plugin->m_wndOldProc)
result = ::CallWindowProc(plugin->m_wndOldProc, hWnd, msg, wParam, lParam);
return result;
}
On some occasions, the host application still seems to miss messages. The main characteristics of the problem are that I have to press the 'Alt' key for modal dialogs to show up ; and I have to move the mouse to give some processing time to the host application !...
Is there any 'industry standard' solution for this kind of as-often-as-you-can animation repaint problem ?
Each thread has its own message queue, and messages sent to a window arrive in the queue of the thread that created the window. If you create your plugin window yourself, you can create it in a separate thread, and that way you will have complete control over its message pump.
An alternative solution (which imho is better), is to only have OpenGL rendering in a separate thread. All OpenGL calls must occur in the thread that created the OpenGL context. However, you can create a window in one thread (your application main thread), but create the OpenGL context in another thread. That way the original application message pumps stays intact, and in your rendering thread you can loop forever doing rendering (with calls to SwapBuffers to vsync).
The main problem with that second solution is that communication between the plugin WindowProc and the rendering loop must take into account threading (ie. use locks when accessing shared memory). However since the message pump is separate from rendering, it can be simultaneous, and your message handling is as responsive as it can get.

Resources