Win32API replicate Spy++ window-information capabilities within Python - winapi

I have a third-party GUI program that I'm wrapping with a Python class (using ctypes).
Are there Win32 API functions that can do the following?
1) Obtain the window handle for a window at a given screen location.
2) Obtain the window handle for a Button or Static window with a given caption.
3) Send text to an Edit window.
4) Extract text from a RICHEDIT instance.
I have WinSpy (a Spy++-type app) and know that it's possible to obtain window handles and captions using that tool, but I need something that works within Python.
I assume that Python's ctypes gives me access to any function within the Win32 API, so I've been scanning MSDN (especially this windows/messages section). I can't seem to find anything that works.
Thanks,
Mike

WindowFromPoint
FindWindowEx to find a child of a window with a given class and name (caption). Repeat operation to get through each parent-child indirection. EnumChildWindows can be helpful too.
SendMessageTimeout + WM_SETTEXT
SendMessageTimeout + WM_GETTEXT or EM_STREAMOUT

I had trouble finding a very simple example for WM_GETTEXT with pywin32 and figured here might be a good place to add one, since it answers part of the question:
MAX_LENGTH = 1024
handle = # A handle returned from FindWindowEx, for example
buffer = win32gui.PyMakeBuffer(MAX_LENGTH)
length = win32gui.SendMessage(handle, win32con.WM_GETTEXT, MAX_LENGTH, buffer)
result = buffer[:length]

Related

Interact with Windows windows programmatically

I wonder if there is any way to somehow interact with windows that are currently open on a Windows system. I am interested in getting some of their properties, namely:
Location
Dimension
is in background?
possibly window title
Preferably, I would like to do that in Java but any suggestions are welcome.
A comment by theB linked to good resources for Java. I'll run through the relevant Windows APIs, in case you want to go native with C++.
To enumerate all the top-level windows in the system, use EnumWindows. You give it a callback function with the signature of EnumWindowsProc, so it will receive each window handle as the first parameter.
You can get the window location (in screen coordinates) and dimensions with the GetWindowRect function. Pass in the window handle you received and get an LPRECT (pointer to RECT) out.
To determine whether a window is maximized, use GetWindowPlacement and check the showCmd field of the WINDOWPLACEMENT structure you receive.
Finally, to get a window's caption, use GetWindowText. (As an aside, if you want to get the text of a control in another process, you'll need to send the WM_GETTEXT message yourself.)

Access Windows Controls from another class or window

In an MFC program I am trying to access controls that are in one window (class) from another (sibling or daughter) window with code in a different .cpp file. Typically you access a control with a DDX_Control variable defined in the class .cpp file.
DDX_Control(pDX, IDC_STATUS, m_Status);
The code for the other window is in a different file, so I don’t have access to the control variable (m_Status). What I have done is used FindWindow to find the main window, then GetDlgItem to find the control I am interested in:
CWnd * tmpWnd = CWnd::FindWindow(NULL,"MainWindow"); // find the main dialog box
CStatic * tmpStatus = (CStatic*) tmpWnd->GetDlgItem(IDC_Status);
tmpStatus->SetWindowText(“Status Report);
This works fine in the debugger, but fails when executed outside the debugger. FindWindow gets the window ID correctly, but GetDlgItem returns null.
Ideally I’d like to access the control variable (m_Status) from the other window, but I don’ know how to do so. I understand the GetDlgItem is less than ideal under any circumstance.
One solution would be to send a message to the main window class and tell it what to do, but I’d have to have a routine to handle each control and know how to handle whatever kind of data I am sending.
Is there a “right” way to do this?
Thank you
The ultimate answer is to cast to the original class:
((CspDlg *)AfxGetMainWnd())->m_Status.SetWindowText("Report");
Since you created the "main" window you have an object or pointer for it. Or, you can call AfxGetMainWnd() to get a pointer to it. Then you can use that to access a public member such as m_Status. All of your windows are interconnected and it should not be necessary to use FindWindow to find any window in your own program.
The fact that some variables may be defined in another file is not relevant. That can be handled with suitable use of #include "theotherfile.h" and object pointers/references.

How do i accept MathML?

i discovered today that Windows 7 comes with a very impressive MathPanel utility, for performing handwriting recognition of equations:
Which is fine. (Here i've entered the formula for the part of the sRGB color space gamma conversion)
But now i don't seem to be able to do anything with it.
There is an Insert button. i would assume that clicking Insert would insert it into the application that is active behind it (much like the On-Screen Keyboard works):
Except i assume it would operate as a Paste operation.
i can find no information in the help on what is required by an application to make it work. There is no mention of any special API some software must support.
Nor can i find any information on MSDN about what special API is required to accept the insertion of an equation.
What API, registration, callback, listener, message, COM Object do i have to implement so that i will receive MathPanel input?
The only reason i mention MathML is because an answer on SuperUser mentioned MathML:
Theoretically, any app that supports MathML (Mathematical Markup Language) can be used with the Windows 7 Math Input Panel. The Math Input Panel only works with programs that support MathML. Here are a few such apps: StarOffice, OpenOffice, Opera and Maple.
Well how do i make my program support MathML?
As far as i know MathML is a markup language; not a Windows API. It would be like saying, "How do i make my program support HTML?" Html is text, and you can paste it anywhere.
MathPad refuses to paste unless i "support" MathML?
Update
Inspecting the IDataObject on the clipboard after clicking Insert, i see two formats available (neither of which are text, which explains why i do not get any markup):
Format 1:
CLIPFORMAT cfFormat: "MathML Presentation" (49839)
PDVTargetDevice ptd: 0x00000000
DWORD dwAspect: DVASPECT_CONTENT
DWORD lindex: -1
DWORD tymed: 1 (TYMED_HGLOBAL)
Format 2:
CLIPFORMAT cfFormat:"MathML" (49838)
PDVTargetDevice ptd: 0x00000000
DWORD dwAspect: DVASPECT_CONTENT
DWORD lindex: -1
DWORD tymed: 1 (TYMED_HGLOBAL)
So at least now i have some clipboard formats:
"MathML Presentation"
"MathML"
i still cannot find anything on MSDN about either clipboard format.
Spying on messages sent to my window, looks like the Math Input Panel application sends a Ctrl+V:
WM_KEYDOWN (0x11) VK_CONTROL
WM_KEYDOWN (0x56) V key
WM_CHAR (0x16)
WM_KEYUP (0x11) VK_CONTROL
WM_KEYUP (0x56) V key
So you need to recognize that someone's trying to hit Ctrl+V. Then you must extract the contents.
First register the three clipboard formats:
Handle CF_MathML_Presentation = RegisterClipboardFormat("MathML Presentation");
Handle CF_MathML_Content = RegisterClipboardFormat("MathML Content");
Handle CF_MathML = RegisterClipboardFormat("MathML");
Note: Appendix B of the W3C's Mathematical Markup Language (MathML) Version 3.0 documents the Windows clipboard format names to be registered:
Generic MathML Windows Clipboard Name: MathML
Presentation MathML Windows Clipboard Name: MathML Presentation
Content MathML Windows Clipboard Name: MathML Content
Then get a handle on the IDataObject in the clipboard:
IDataObject dataObject;
OleGetClipboard(dataObject);
Then enumerate all the formats, looking for the one you like:
IEnumFORMATETC enum;
dataObject.EnumFormatEtc(DATADIR_GET, out enum);
String mathXml = "";
foreach (FormatEtc format in enum)
{
if (format.cfFormat = CF_MathML_Presentation) ||
(format.cfFormat = CF_MathML_Content) ||
(format.cfFormat = CF_MathML)
{
//We know how to handle these formats:
STGMEDIUM medium;
dataObject.GetData(format.cfFormat, out medium);
mathXml = GetStringFromStorageMedium(medium); //handles all the nasty HGlobal/IStream/IStorage nonsense
}
}
ShowMessage(mathXml); //tada!
Microsoft also allows you to program the Math Input COM object:
//Create the COM object
IMathInputControl mathInputControl = CreateComObject(CLSID_MathInputControl);
mathInputControl.Show();
You can then create an object that receives the notification events:
class MathEvents : _IMathInputControlEvents
{
public HRESULT Insert(String mathXml)
{
//Notifies the event handler when the Insert button is clicked.
MessageBox.Show(mathXml);
return S_OK;
}
public HRESULT Clear()
{
//Notifies the event handler when the Clear button is clicked.
return S_OK;
}
public HRESULT Close()
{
//Notifies the event handler when the Close button is clicked.
return S_OK;
}
public HRESULT PaintHRESULT Paint(LONG_PTR hdc, LONG Left, LONG Top, LONG Right, LONG Bottom, LONG Element, LONG State)
{
//Notifies the event handler when the buttons and background of the control require painting.
return S_OK;
}
The missing ingredient is how to give mathInputControl a reference to our callback object.
That's super-secret complicated COM code, involving ConnectionPointContainer, andAdvise`, which cannot be done from C#.
But you don't need to, you can just use Ctrl+V.
I think it is officially called the "Math Input Panel" (MIP). The MathType product supports it and provides a menu item to run it. As other replies here mention, clicking MIP's Insert button sends a Ctrl-V to the window underneath it. If that window supports that keyboard shortcut and handles MathML, then it will work.
While the MathML Clipboard Format is the recommended way to handle MathML input on a paste, if you are implementing MathML support in your app you should also accept MathML text offered as CF_UNICODETEXT. Some apps support copying MathML to the clipboard but do not seem to know about the MathML Clipboard Format. Of course, your paste code will have to sniff the text to identify MathML as opposed to regular non-MathML text. You should also consider accepting a drag-and-drop as well as a paste.
The Math Input Control is a related but slightly different configuration of MIP. If I remember correctly, it lacks the history and some other features of the MIP. We started working with it for MathType and quickly realized that there's no advantage to it. You should just ignore it and just support paste and drag-and-drop of MathML. Add a Math Input Panel menu item if it makes sense for your app.
The clipboard format "MathML Presentation" actually contains text; I've tried this before using the Windows API GetClipboardData().
Moreover, if you copy a MathML fragment to the clipboard as plain text (e.g., CF_TEXT) and then paste it to a Word document, you will get plain text also, i.e., Word will NOT interpret it as Presentation MathML.
For Word to do so, you have to copy it as both CF_TEXT and as "MathML Presentation". To obtain the ID of the latter, try registering "MathML Presentation" as a clipboard format as suggested by Ian Boyd. Windows will return its clipboard format ID; use this ID with SetClipboardData().

What does ( WM_NCLBUTTONDOWN ) do?

i was studying the example of how to make round-shape form in Visual Basic 6, and i stopped at the code :
Public Const WM_NCLBUTTONDOWN = &HA1
I only know that this is a message to the windows passed as Const ...
What i want to know is :
what is &HA1 ?
what does Const WM_NCLBUTTONDOWN do ? what message does it send to Windows ?
anything else about it .
Please, thanks
You are working with messages that Windows sends to a window to tell your code that something interesting happened. You'll find this constant used in the WndProc() method of a form, the method that runs when Windows sends a message.
The WM_NCLBUTTONDOWN message is one of those messages. WM = Window Message. NC = Non Client, the part of the window that's not the client area, the borders and the title bar. L = Left button, you can figure out BUTTONDOWN.
These messages are declared in a Windows SDK file. You'll have it on your machine, the VS2008 version of that file is located in C:\Program Files\Microsoft SDKs\Windows\v6.0A\Include\WinUser.h. Open it with a text editor or VS to see what's inside. Search for the message identifier to find this line:
#define WM_NCLBUTTONDOWN 0x00A1
The Windows SDK was written to work with C programs. #define is equivalent to Const in VB.NET. The 0x prefix means 'hexadecimal' in the C language, just like &H does in VB.NET. The Windows calculator is helpful to convert hexadecimal values to decimal and back, use View + Programmer. You'll see the reason that &H is used in a VB.NET program, these constants started out in hexadecimal in the core declaration. But Private Const WM_NCLBUTTONDOWN = 161 will work just as well (10 x 16 + 1).
So within WndProc() you'd use a Select Case or If statement to detect the message. And you can do something special when the user clicks the left mouse button on the window title bar. If you ignore it then MyBase.WndProc(m) runs and the normal thing happens: Windows starts a modal loop that lets the user move the window. It is actually very rare that you want to stop or alter that behavior, users are pretty fond of that default behavior since all windows in Windows behave that way. The only message whose behavior you'd typically want to customize is WM_NCHITTEST. Very useful to give a borderless window border-like behavior. But that's another story.
That's a hexadecimal integer literal
It declares a constant; it doesn't actually do anything.
The WM_NCLBUTTONDOWN message is posted when the user presses the left mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor
&HA1 means the hexadecimal number A1, i.e., 161 (though you'll usually see Windows message constants represented in hex). More commonly you'll see this as 0xA1 (or 0x00A1) since that's how the hex number would be represented in C or C++ (the Windows API was originally written for C).
You won't be sending WM_NCLBUTTONDOWN to Windows; it's the other way around. Windows will be sending you WM_NCLBUTTONDOWN.
If you want to know what WM_NCLBUTTONDOWN is for, the documentation is just a Web-search away.

how to find type of GDI

i am beginner in win 32 api . i try use win 32 api for create an onscreen keyboard . I can give handle of window and components by click but how to realize type of these and i want set text only on text box and editable components
i try to use GetWindowInfo() and try use atomWindowType of window for realize type of that but this is not use full for this goal because this change on each restart of OS.
(click is handle of window)
WINDOWINFO pwi = new WINDOWINFO(); USER32INST.GetWindowInfo(click, pwi); if (pwi.atomWindowType != -15891) { setLastclick(click); } tnx
You are not going to be able to achieve what you desire, in full generality it is not realistically possible.
A window's type (or class) is essentially determined by its WndProc. You can use GetClassName and its ilk to help you identify some standard window classes, but as you have already discovered, most real-world apps will not use these standard classes.
So, although in theory, you could analyse the code behind the WndProc at runtime, in practice this is not remotely feasible.

Resources