it is acceptable to declare/define a variable in the WndProc function. as this code:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
...
the question whether it's good.
Because the program enters into this function, thousands of times every minute, and every time these variables are redefined, and again destroyed, maybe it is better to define these variables outside the WndProc function, in the class, thus saving time and resources?
Because the program enters into this function, thousands of times every minute, and every time these variables are redefined, and again destroyed, maybe it is better to define these variables outside the WndProc function, in the class, thus saving time and resources?
As far as time and resources go, it makes little difference. These are local variables, stored on the stack. The entire stack is already reserved when your thread is created, and the memory for these variables is committed no later than the first time this procedure is executed. So this means that, for switch conditions that don't refer to these variables, you likely won't be able to measure the difference in runtime or resource needs caused by the presence of the variables.
Raymond points out that WndProc can be called recusively. If you have a lot of local variables in your WndProc, the resulting stack usage can be sub-optimal. I still can't imagine any real world application where the bottleneck was stack usage of WndProc.
Having said that, a WndProc method which is one big switch statement containing all the variables is bad practice. You don't want to pollute the local namespace of this function with lots of different variables. I suggest you make a separate handler function for each message that you want to handle in the window procedure.
Finally, you suggest declaring these variables in the class. Don't do this. Local variables are always preferred where possible. It's certainly going to be possible to declare these variables as locals. Although they should be locals of the separate handler functions that WndProc calls.
When local variables are 'created', room is allocated to fit all of them onto the stack and their constructor is called. If there is no constructor, I believe the default action is to 'zero' the fields, although I'm not 100% sure about that.
However, this can be achieved in perhaps a dozen of instructions. This effect is negligible in comparison to other operations and especially system calls. If you are still concerned about the time spent by different routines in your program, I'd advise you to use a tool like gprof.
Related
I was wondering if I had to close the handle if for example I were to call GetModuleHandle this way
GetProcAddress(GetModuleHandle("modulename"), "nameoftheexportedfunction")
what would be the proper way to close the handle? Do I need to do
HMODULE hModule = GetModuleHandle("modulename");
GetProcAddress(hModule, "nameoftheexportedfunction")
CloseHandle(hModule);
Or does it get deleted automatically if the value returned by GetModuleHandle isn't stored into a variable?
GetModuleHandle returns an HMODULE (aka HINSTANCE - see What is the difference between HINSTANCE and HMODULE?). This data type cannot be passed to CloseHandle.
The HMODULE could be passed to FreeLibrary but that is not required either, since GetModuleHandle doesn't increase the reference count on the module. In fact, calling FreeLibrary might cause the module to get unmapped prematurely, leading to a spectacular crash.
In short: GetModuleHandle returns a read-only value, that doesn't need to be disposed off in any way. The first line of code in your question is fine.
The Windows API can be very confusing in this respect, as there are multiple things called a handle, and they all have different rules.
In this case, CloseHandle closes kernel handles, which typically refer to files or other kernel resources such as synchronization objects that are created with a name—which all are identified by being returned as a HANDLE.
GetModuleHandle returns an HMODULE—actually the base address of a loaded EXE or DLL—and, as it is not a HANDLE, does not need to be, and must not be, released with CloseHandle.
As #David Heffernan points out, this does not mean other handle types never have their own destroy/release/un-acquire semantics, and it also does not mean that every HANDLE you get from an API must be passed to CloseHandle either. There is just no substitute for knowing the specific API you are dealing with and its particular handle management requirements.
I wanted to figure out what the syscalls behind GetWindowText are. I wrote a simple program to call GetWindowText with a handle to a window in a different process.
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MessageBox(0,"Attach debugger and set bp","on GetWindowTextA",0);
HWND winmine = FindWindow(NULL,"Minesweeper");
if(winmine != NULL)
{
char buf[255] = "";
GetWindowTextA(winmine, buf, 254);
MessageBox(0,buf,"Found",0);
}
else
{
MessageBox(0,"?","Found nothing",0);
}
return 0;
}
I attached a debugger and stepped through the GetWindowTextA call, manually stepping through everything except these API calls (in order):
GetWindowThreadProcessId (in GetWindowLong)
InterlockedIncrement
WCSToMBEx (which is basically WideCharToMultiByte)
InterlockedDecrement
None of these API calls seem to be able to read a string in memory not owned by the calling process. I used a usermode debugger so I certainly didn't end up in kernelmode while stepping without realizing it. This means that GetWindowText got the window name without performing a context switch. Which seems to imply that the text for every window that exists is accessible without a context switch.. and that can't be right because there's no way Windows keeps a copy of the text for every single window/control on the system, on every single process.
I have read this article. It mentions that window names are stored in quote "a special place", but does not explain how this "special place" can be accessed from a different process without a syscall/context switching.
So I'm looking for any explanations as to how this is done. Any information you can provide is greatly appreciated.
GetWindowText got the window name without performing a context switch. Which seems to imply that the text for every window that exists is accessible without a context switch.
This info is stored in memory that is shared between all the processes that use user32.dll. You may try to search virtual space of your process for unicode names of other processes' windows.
It gets mapped into the process address space during user32.dll loading. There are some kernel structures/sections involved: win32k!gSharedInfo, win32k!ghSectionShared, win32k!gpsi and others (which I don't know of).
Actually, the lower 16 bits of HWND represents index into window info array with base address *(&user32!gSharedInfo + 1). The first field of this window info is the kernel address of another structure which contains all the shared window information. Subtracting the difference between kernel address of the section and its user-space mapping (which is stored in TEB!Win32ClientInfo) you can get relevant info.
user32!ValidateHwnd is the function that converts window handle into this address which can be used by inner user32 functions like user32!DefWindowProcWorker.
Pseudocode of GetWindowTextW looks like (excluding error-handling):
GetWindowTextW(HWND hwnd, wchar_t* buf, int size)
{
inner_hwnd = ValidateHwnd(hwnd);
if (TestWindowProcess(inner_hwnd))
SendMessageWorker(inner_hwnd, WM_GETTEXT, size, buf, FALSE);
else
DefWindowProcWorker(inner_hwnd, WM_GETTEXT, size, buf, FALSE);
}
DefWindowProcWorker which is called in your case with WM_GETTEXT will just parse the structure referenced by inner_hwnd and copy window's name into buf.
it seems that the text for EDITTEXT controls are not stored in this manner
I never knew all the info that was stored in there though it seems like a good choice to not pollute processes' virtual space with all kinds of user/gdi params. Besides, lower integrity processes should not be able to get higher integrity processes sensitive information.
because there's no way Windows keeps a copy of the text for every single window
The text most certainly exists, just not as a copy. The text for a window is stored in the virtual memory of the process that owns the window. Might be in RAM, not terribly likely if the process has been dormant for a while, definitely on disk in the paging file. Which doesn't stop GetWindowText() from making a copy. On-the-fly, when you call it.
GetWindowText() is limited, it is documented to only being capable of copying the caption text of a window, so it probably uses the desktop heap for the session to retrieve the text. Not otherwise a restriction to a winapi function like SendMessage(), you can use WM_GETTEXT to obtain a gigabyte from an Edit control. That certainly crosses the process boundary.
As an operating system function, SendMessage can of course break all the rules that apply to normal processes. The OS has no trouble addressing the VM of an arbitrary process. Rules that are routinely broken, your debugger does it as well. With functions that you can use to also break the rules, ReadProcessMemory() and WriteProcessMemory().
I've always been curious on what nCmdShow means in WinMain of a C program using Windows API.
I looked up the formal explanation: "Controls how the window is to be shown. This parameter can be one of the following values.".
I do not understand what that means, as a Windows program can contain more than one window, or no windows at all. In addition, as program begins, there is no window to be shown to begin with, which makes me question this argument even more.
Also from what I read, it always stays 10, which isn't even on the list of options in "http://msdn.microsoft.com/en-us/library/windows/desktop/ms633559%28v=vs.85%29.aspx"...
Is it obsolete? Can somebody explain its purpose, or provide any references explaining its use? I tried googling but saw nothing.
Thanks!
REVISITED:
When you right click a shortcut and go to properties, there is an option to start the window Minimized, Maximized, or Normal(ly).
Windows provides an nCmdShow to your program in case it wants to act in a special way if it was launched in any of these three ways. For example, it may hide itself inside notification bar if it was requested to be started minimized.
For exhaustiveness:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms633548(v=vs.85).aspx describes all the different ways that may be passed.
It is basically a hint to the application how it should show its main window. Although it is legacy, it is not as legacy as the hPrevInstance parameter. But, I digress...
The value of the nCmdShow parameter will be one of the constants specified in ShowWindow's API reference. It can be set by another process or system launching your application via CreateProcess. The STARTUPINFO struct that can optionally be passed to CreateProcess contains a wShowWindow member variable that will get passed to WinMain through the nCmdShow parameter.
Another way the nCmdShow parameter is passed is via calls to ShellExecute.
Off the top of my head, I can't think of any scenario (in recent versions of Windows) in which the operating system will explicitly pass a value other than SW_SHOW when launching an application.
It's not uncommon nor bad for an application to ignore the nCmdShow flag passed to WinMain[?].
Note this section from the ShowWindow documentation:
nCmdShow: This parameter is ignored the first time an application calls ShowWindow, if the program that launched the application provides a STARTUPINFO structure.
Even though your program has no window when it starts, the specified value gets implicitly used the first time you eventually call ShowWindow. (It's not read directly from WinMain's local nCmdShow variable, though, so you can't change its value within WinMain and expect to get different results. In that sense, it's not particularly useful unless your program needs to do something special if it's started minimized or maximized.)
The "n" in nCmdShow means "Short int".
(This is what I wanted to know when I came to this stack overflow page)
Source:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa378932(v=vs.85).aspx
nCmdShow is integer type,this parameter specifies how the application windows should be display( to O.S.)
If no value is specified by you than by default Windows O.S. say SW_NORMAL value of this param.
You can specify values of this parameter , but those who passed to WinMain() only for Windows O.S
This will require some background. I am using Detours to intercept system calls. For those of who don't know what Detours is - it is a tool which redirects call to system functions to a detour function which allows us to do whatever we want to do before and after the actual system call is made. What I want to know is that if it is possible to find out somehow any info about the dll/module which has made this system call? Does any win32 api function help me do this?
Lets say traceapi.dll makes a system call to GetModuleFileNameW() inside kernel32.dll. Detour will intercept this call and redirect control to a detour function (say Mine_GetModuleFileNameW()). Now inside Mine_GetModuleFileNameW(), is it possible to find out that this call originated from traceapi?
call ZwQuerySystemInformation with first argument SystemProcessesAndThreadsInformation.
once you have the returned buf, typecast it to PSYTSTEM+PROCESS_INFORMATION and use its field to extract your info.
status = ZwQuerySystemInformation (
SystemProcessesAndThreadsInformation, buf, bufsize, NULL);
PSYSTEM_PROCESS_INFORMATION proc_info = (PSYSTEM_PROCESS_INFORMATION) buf;
proc_info->ProcessName, which is a UNICODE_STRING will give you the calling process name.
Please note that the structure and field I am talking about is not documented and might change in future release of windows. However, I am using it and it works fine on WIN XP and above.
I don't know how many stack frames will be on the stack that are owned by Detours code. Easy to find out in the debugger, the odds are good that there are none. That makes it easy, use the _ReturnAddress intrinsic to get the caller's address. VirtualQuery() to get the base address, cast it to HMODULE and use GetModuleFileName(). Well, the non-detoured one :)
If there are Detours stack frames then it gets a lot harder. StackWalk64() to skip them, perilous if there are FPO frames present.
I have customer that uses older, custom built ERP application for which they don't have source code and company that developed it does not exist any more. Application is developed in 2000 and it's built with Delphi. Since last executable is from 2003, it could be D6 or D7.
On one important form there are some fields where customer would like to display additional data from other databases and asked me if it's possible to "duct tape" data over existing form.
First idea I got is to build application that will:
browse list of windows target application creates and find controls on form
attach "some" event when to get notified when target form is displayed
attach "some" event when to get notified when field on target form is changed
display additional information in small window overlaying target form
Are there any examples on how to do something like this. I searched google with variations of this question title, but without success.
Note - rewriting of ERP application is not planned.
About language - I can do it with C# or Delphi.
I'm going to answer this from a purely C & Win32 point of view, because I don't know Delphi or its libraries. Converting this to C# can be accomplished via p/invoke, but some parts may/will need to be unmanaged.
First off, no guarantees. If the target application is doing windows-less controls (if there isn't an HWND under every on-screen control) you're pretty much out of luck. This isn't all that uncommon, so yeah...
Step 1, register a window hook listening for new windows created by the target process*:
//dllHMod is an HMODULE that refers to the DLL containing ShellHookProc
HHOOK hook = SetWindowsHookEx(WH_SHELL, ShellHookProc, dllHMod, 0);
// error handling, stashing hook away for unregistering later, etc...
LRESULT CALLBACK ShellHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode < 0) return CallNextHookEx(NULL, nCode, wParam, lParam);
if(nCode == HSHELL_WINDOWCREATED)
{
WindowCreate((HWND)wParam);
}
return 0;
}
WindowCreated(HWND) should stash the HWND away if the correct process (determined via GetWindowThreadProcessId) owns it. At this point, you'll be able to get every top-level window owned by the target process. Note that registering a global hook carries a notable performance penalty, not that it really matters in your case but you should expect it.
Now for the fun part. There's no reliable way to tell when a window is fully constructed, or when its done rendering (there are ways to tell when it STARTS rendering, but that doesn't really help). My advice, guess. Just throw some arbitrary wait in there and then try and enumerate all the child windows.
To enumerate child windows (if you know enough about the target window, there are better ways to do this; but I'm assuming a search is easiest):
//targetHWND is an HWND of one of the top-level windows you've found
EnumChildWindows(targetHWND, ChildWindowCallback, NULL);
//more code...
BOOL ChildWindowCallback(HWND window, LPARAM ignored)
{
if(IsTargetWindow(window)) { /* Do something */ }
return TRUE;
}
Implementing IsTargetWindow is another tricky part. Hopefully you'll find some reliable test for doing so (like checking the class name, window name, style, something; look at GetWindowInfo).
Once you have the window you want to monitor, you can use SetWindowLongPtr and GWLP_WNDPROC to watch all messages it receives. This will require code injection (and thus unmanaged code) and is awfully low level. I'd advise against it if you could possibly avoid it, but lacking the source...
I think this answers is a decent starting point, but once again this is going to be incredibly painful if its even possible at all. Good luck.
*Alternatively, if you know that the target app doesn't create windows except at startup (or at detectable/predictable points in time) you can use EnumWindows.