I am writing a program that automates saving data to a specific location, based on the common Save/Save As dialog.
There are two attacking approaches. Both approaches require monitoring handles for messages under Spyxx (so essentially we are trying to replicate the SendMessage)
The first approach to set the File Name with target path, using Win32 SendMessage API. The HWnd in this case is the Edit field next to the File name.
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, [MarshalAs(UnmanagedType.LPStr)] string lParam);
SendMessage(HWnd, (int)WindowMessage.WM_SETTEXT, IntPtr.Zero, #"Address: %UserProfile%\Desktop\Target.txt");
The problem with this approach is that, it does not always set the text under Windows 7 and Windows 8.1 (I do have better luck with Windows 10). I tried to set some waiting time, but no matter how long I wait, it doesn't seem to matter (besides SendMessage is synchronous operation, so text should be set, or not set at all)
The second approach is to set the Location at the top of the dialog box. Again, we are using SendMessage to accomplish this, and HWnd in this case, references the ToolbarWindow32 object, which is the child of Breadcrumb Parent object.
SendMessage(HWnd, (int)WindowMessage.WM_SETTEXT, IntPtr.Zero, #"Address: %UserProfile%\Desktop");
or
SendMessage(HWnd, (int)WindowMessage.WM_SETTEXT, IntPtr.Zero, #"Address: Desktop"); // replicated message found on Spyxx
Unfortunately, this approach does not seem to work (i.e. I can send the message, but Dialog doesn't change its location), and I have yet to figure out what steps I am missing.
My question, how do you use Win32 API to interact with the 3rd party app's Save As dialog, so that you can guarantee saving the file in the desired location? Much appreciated and thanks for reading!
Related
I'm sending keystrokes to an inactive Adobe Flash Projector window with PostMessage, that part works perfectly. I leave it running in the background and it interferes very little with my normal computer usage, which is the intent. The problem comes when I programmatically send the W (or less frequently Q) key while I happen to be holding Ctrl intended for a different windows shortcut. This triggers Ctrl-Q or Ctrl-W, both of which immediately close the Adobe Flash Projector. Ctrl-F and Ctrl-O have some undesirable effects as well.
EDIT: I'm not interested in solutions that briefly release the Ctrl key.
Is there anyway I can unhook shortcut keys from a third party window? It uses a standard OS menubar across the top of the window which is where the shortcuts are listed, so surely there's a way to reassign, unassign, or block it, right?
In the past I tried using these dlls to break the menu. It made it disappear but didn't break the shortcuts.
DllCall("SetMenu", uint, this.id, uint, 0)
hMenu := DllCall("GetSystemMenu", "UInt",this.id, "UInt",1)
DllCall("DestroyMenu", "Uint",hMenu)
Sorry for the strange syntax, this is from an early version of my program written in autohotkey.
The language I'm using now is C#, but I assume the solution uses a .dll, so that's not as important. Feel free to suggest or change my tags.
You can try to make inactive (WS_DISABLED - use GetWindowStyle and SetWindowStyle) the main window of destination application (the Window that contains menu).
You can try to find which functions are used by application and rewrite them in local copy of application with VirtualProtect and injecting assembler (dangerous if you have no knowledge about virtualization of memory). Check the application use GetKeyState or GetAsyncKeyState (it will be visible after opening the application in text editor).
You can try:
HMENU hMenu=GetMenu(applicationMainWindow);
SetMenu(applicationMainWindow,0);
// here send your input with SendMessageW instead of PostMessageW
SetMenu(applicationMainWindow,hMenu);
Each program can use various methods to handle user keyboard input. In this case probably is used GetAsyncKeyState or GetKeyState (for Ctrl) if you didn't send it and Ctrl is detected.
If it won't help you, please add code with your PostMessage to your question.
BTW. Instead of destroying GetSystemMenu you can clear appropriate window style and after sending input restore it (if the problem is System Menu - probability near 1%).
Using the program Resource Tuner's free trial, I opened up flashplayer_28_sa.exe, went to Accelerator Table (Apparently accelerator means shortcut in the context of Menus), and deleted the offending shortcuts. Then I saved it, and it failed to save, and I saved it again, and again, and again, and then it worked, although I did nothing differently that time.
I think it would work with other shortcuts for programs with standard windows menus.
Although I didn't end up using this method, (because changing the menus was ineffectual for blocking the shortcuts for those menu items), I found various interesting ways to modify a third party window's menus. I'll leave some of what I found here because while it relate to my question, it doesn't solve my problem. Comments are based on my fallible understanding of what they do.
Various externals:
[DllImport("user32.dll")]
//get hMenu of the window's menu
static extern IntPtr GetMenu(IntPtr hWnd);
[DllImport("user32.dll")]
//Attach hMenu to a window. if hMenu is 0, attach no menu (remove menu)
static extern bool SetMenu(IntPtr hWnd, IntPtr hMenu);
[DllImport("user32.dll")]
//Destroy hMenu
private static extern bool DestroyMenu(IntPtr hMenu);
[DllImport("user32.dll")]
//Destroy Destroy submenu at position within menu
private static extern bool DeleteMenu(IntPtr hMenu, uint uPosition, uint uFlags);
[DllImport("user32.dll")]
//Like GetMenu, but gets the restore/move/size/minimize/etc menu that you get when clicking on the little icon in the top left of a window (not the window's menu
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
//Adds a menu to a menu
private static extern bool AppendMenu(IntPtr hMenu, int uFlags, int uIDNewItem, string lpNewItem);
[DllImport("user32.dll")]
//Removes a menu from a menu
private static extern bool RemoveMenu(IntPtr hMenu, uint uPosition, int uFlags);
[DllImport("user32.dll")]
//Like AppendMenu, but specifies position
private static extern bool InsertMenu(IntPtr hMenu, int uPosition, int uFlags, int uIDNewItem, string lpNewItem);
[DllImport("user32.dll")]
//Lets you set various properties of a menu (grayed out, checked, etc)
private static extern bool ModifyMenu(IntPtr hMenu, uint uPosition, uint uFlags, IntPtr uIDNewItem, string lpNewItem);
[DllImport("user32.dll")]
//gets the hMenu for a submenu
private static extern IntPtr GetSubMenu(IntPtr hMenu, int pos);
Notes on their parameters:
hWnd is the handle of a window with a standard menu.
hMenu is the menu handle, which can be the handle of the root level menu (Like File, Edit, Help) or a submenu item (Like open, copy, About ...). You can get these with GetSubMenu or GetSystemMenu or
uPosition is an integer position, 0 being the first one.
uFlags can be found on each function's individual page which you can find at https://msdn.microsoft.com/en-us/library/ff468865%28v=vs.85%29.aspx
lpNewItem refers to the string of text shown on the menu item.
uIDNewItem is a pointer like hMenu that will get inserted at the defined location
I need some help. I wrote my questions at the end and will first explain what exactly my code is supposed to do:
I am making a program that will communicate with other programs. What I need my software to do is be able to click on a button on another program, and I believe the appropriate code to do this would be:
SendMessage(hWnd, Msg, wParam, lParam);
with
Msg = B_Click
wParam = 0;
lParam = 0;
however I am not sure how to get the hWnd which is the handle of a specific button on a specific window of another program that is running at the same time. I have read somewhere that I could possibly do the following:
HWND buttonHandle = FindWindowEx(hwndParent, hwndChildAfter, lpszClass, lpszWindow);
where:
HWND hwndParent = A handle to the parent window whose child windows are to be searched
HWND hwndChildAfter = if its null child windows are of the parent window are looked through
LPCTSTR lpszClass = (NOT SURE WHAT THIS IS)
LPCTSTR lpszWindow = (NOT SURE WHAT THIS IS)
I have a few issues with the FindWindowEX() function however.
Question 1: The window I am looking at has various buttons, so how would the function know which one of the 3 i am looking at?
Question 2: What are the lpszClass and lpszWindow variables and how might I get them?
Question 3: Is this even the right approach? If it's not, please point me to the right direction!
You don't need the handle of the button, you need the handle of its parent window. The button sends BN_CLICKED to its parent window. Look up the button's ID with spy++. Then use EnumChildWindows of the parent to look at all the child windows. For each child use GetWindowLong with GWL_ID to check its ID.
Im trying to scroll other program (PowerPoint 2013) by sending WM_HSCROLL,
and it will work only if I offer the correct LPARAM (not NULL) to SendMessage.
The value of LPARAM is dynamic, it will change if you close and open a new program.
Now I can only get its value by hooking WM_HSCROLL and clicking scroll bar manually.
// This is my code:
LPARAM lParam = 0x0a616c38; // Found by hooking WM_HSCROLL
SendMessage(hTarget, WM_HSCROLL, SB_LINERIGHT, lParam);
So is it possible to get the correct LPARAM programatically?
Many thanks!
p.s. The scroll bar is not a real window in PowerPoint 2013.
p.s. It returns 1 if I use GetScrollInfo(hTarget, SB_CTL, &scrollinfo), but all values inside scrollinfo are zero.
p.s. Office Home and Student 2013 Official Site
Did you try to call GetLastError?
GetScrollInfo will probably not work across process boundaries, so I would say that's why you're not getting valid values back.
The lParam value of a WM_HSCROLL message is either NULL for the standard window scroll bar, or the handle of the scroll control. The handle of the scroll control will obviously change every time the program is run, so you need to find that out yourself before you can reliably simulate scroll input.
To do this, you can use the FindWindowEx function to search the parent window (hTarget in your example) for child windows of class "SCROLLBAR". As you will probably find more than one scrollbar child window you'll need some way to tell them apart - most probably, via the window's GWL_ID value as this will probably not change from run to run.
I am using spy++ and see that the control I have has the decimal that matches the hex(after conversion of course) in spy++ and I see the parent window matches as well so I have the IntPtr for a Label and IntPtr for the form/window but my SendMessage is not working to change the text in the target application.
Another approach may be may be to do something like this post but what is the control id and how do I get that
SetText of textbox in external app. Win32 API
I assume the hWnd here needs to be the controls hWnd, correct?
SendMessageCall(hWnd, WM_SETTEXT, (IntPtr)value.Length, value);
I notice that getting the text IS WORKING
SendMessageCall(hWnd, WM_GETTEXT, (IntPtr)sb.Capacity, sb);
and I notice that I get the test, see the correct value, set the text yet it doesn't change and then get the text again using SendMessage AND it is the new value but the application still shows the wrong value....hmmm, do I need to send a repaint message maybe and if so, what is the code for that?
thanks,
Dean
You don't send a window message to force repaint, instead you call InvalidateRect(hWnd, NULL, TRUE).
I'm writing an object-oriented window API wrapper for Windows in D, and I'm having a (non-language-specific) design problem.
Windows requires that all windows be previously registered with RegisterClass; extending an existing class requires replacing the window procedure. Furthermore, there seem to be two kinds of window handles: HWNDs that need to be disposed (via DestroyWindow), and HWNDs that don't (e.g. from other applications).
I have created a Window class, and so long as I'm just wrapping the ShowWindow, UpdateWindow, FindWindow, and other such methods, everything is fine and dandy. But as soon as I try to add a constructor with a className parameter to my class that calls CreateWindow, I run across a problem:
The given className must already have been registered by RegisterClass.
In order to register a new window class, I would need to make my subclasses of Window to somehow call RegisterClass before trying to create a new Window, either directly or indirectly.
In order for my design (and inheritance) to make sense, i would need to make sure that, for any given subclass of Window, all instances are actually instances of the same window class; namely, that all classNames from a particular subclass are identical. (This is because the window procedures for all instances of a particular window class need to be the same.)
The problem is, there's no way to have an abstract static method (in order for Window to be able to ask the subclasses for their class info, and to register them once), and so I am forced to say something like CreateWindow(this.className, ...) in order to create a new window, which easily becomes problematic if my subclasses don't respect this rule, and give me a different class name per instance of the window.
Furthermore, I need a one-to-one mapping between the WNDCLASS.lpfnWndProc field and my Window subclass's (overridden) WndProc method. This doesn't exactly work, though, if I'm forced to get the method pointer on a per-instance basis, since it breaks the entire OOP design and messes everything up.
While it's possible for me to enforce this consistency at run-time, it's a bit ugly, and so it's not a great solution.
So, long story short, does anyone have any idea of an elegant solution to the problem of creating an abstract static method? I'm thinking of some design patterns like Factory and whatnot, but I'm not sure if they fit here... if someone thinks they might , I would really appreciate a little explanation on how it would fit into the design.
Thank you!
The standard solution for this is to give the base class two window procedures, a static one and a virtual one.
The base class registers its class with the static window procedure. The static window procedure then invokes the virtual window procedure. Many people omit the HWND parameter from the virtual version since it can be obtained from the this pointer, but I'll leave it in just to simplify the story.
class Window
{
public:
virtual LRESULT WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ return DefWindowProc(hwnd, uMsg, wParam, lParam); }
private:
static LRESULT CALLBACK StaticWndProc(
HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_NCCCREATE) {
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(
reinterpret_cast<LPCREATESTRUCT>(lParam)->lpCreateParams);
}
Window *pThis = reinterpret_cast<Window*>(
GetWindowLongPtr(hwnd, GWLP_USERDATA));
LRESULT lres = pThis ? pThis->WndProc(hwnd, uMsg, wParam, lParam)
: DefWindowProc(hwnd, uMsg, wParam, lParam);
}
};
Derived classes override Window::WndProc.
The window proc doesn't have to be the same for all instances of a particular class name.
Typically, you'd use the RegisterClass function to set the default window proc for windows of that class. When you create a new window that uses the class but you want it to override the default handling, you create the window and then call SetWindowLongPtr(hwnd, GWL_WNDPROC, newWndProc), where newWndProc is a pointer to the new window's window proc.
The new window's window proc can then handle the messages that it wants to override, and call DefWindowProc for the rest.
To construct a window with a new class name, have the constructor copy the class info for the inherited class and create a new class that's identical to that one, except for the name. Then expose a method that will allow the client to change class-specific things. The API functions you're interested in would be GetClassInfoEx and SetClassLong, SetClassWord or SetClassLongPtr.
Inheritance still makes sense in this world because the default processing is the same for every window of a particular class, and inherited classes inherit the default processing from their parents.
You don't need anything like an abstract static method for this. All you need is the window handle. You can get the class name by calling GetClassName with the window handle, and then call GetClassInfoEx with the returned class name.
Wow, I certainly didn't expect this...
I searched for the phrase x86 thunks on Google. And, as it turns out, I wasn't the first person to come across this problem (surprise!).
The first hit was the exact problem and the solution to this question about Window Procs, even though it had nothing to do with my query (or at least, very little to do directly)... hope someone else finds it useful too.