Copy selected text to Clipboard in MSWord, OOWriter, etc - winapi

I have code on Delphi (but this not principal)
hWindow := GetForegroundWindow;
EditHandle := GetTopWindow(hWindow);
SendMessage(EditHandle, WM_COPY, 0, 0);
SClipboard := Clipboard.AsText;
If this code worked for Notepad - all very good. If another, not simple editor, selected text not copyed to clipboard.
How I can to execute copy text to clipboard?
I suspect that SendMessage does not work.

First, Not all the top windows are the edit control. So, EditHandle is unpredictable.
Then, WM_COPY is only supported in edit control or combo box. The same goes for WM_GETTEXT, They do not support all windows.
You are not able to change its message processing mechanism unless you're the owner of Windows.
However, there is a workaround--Simulate "Ctrl + C" keyboard input to target window.
//SetForegroundWindow(hWindow); Since hWindow is already a Foreground Window
keybd_event(VK_CONTROL, MapVirtualKey(VK_CONTROL, 0), 0, 0); // Ctrl down
keybd_event(ord('C'), MapVirtualKey(ord('C'), 0), 0, 0); // C down
keybd_event(ord('C'), MapVirtualKey(ord('C'), 0), KEYEVENTF_KEYUP, 0); // C up
keybd_event(VK_CONTROL, MapVirtualKey(VK_CONTROL, 0), KEYEVENTF_KEYUP, 0); // Ctrl up
EDIT:
Since the keybd_event has been superseded by SendInput, Here is a C++ sample for using SendInput:
INPUT input[4] = {0};
input[0].type = input[1].type = input[2].type = input[3].type = INPUT_KEYBOARD;
input[0].ki.wVk = input[3].ki.wVk = VK_CONTROL;
input[0].ki.wScan = input[3].ki.wScan = MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC);
input[1].ki.wVk = input[2].ki.wVk = 'C';
input[1].ki.wScan = input[2].ki.wScan = MapVirtualKey('C', MAPVK_VK_TO_VSC);
input[2].ki.dwFlags = input[3].ki.dwFlags = KEYEVENTF_KEYUP; // there is no KEYEVENTF_KEYDOWN
SendInput(4, input, sizeof(INPUT));

Related

winapi - rich edit control - how to paste a text using a context menu

I create an edit window this way:
hwndEdit = CreateWindowEx(
0,
MSFTEDIT_CLASS,
TEXT("EDIT"),
WS_BORDER | WS_CHILD | ES_LEFT,
20,
20,
100,
30,
gHwnd,
NULL,
hInst,
NULL);
I can paste a text using a keyboard shortcut (ctrl + v) but when I use a right mouse button a context menu is not displayed (for a standard edit control it works). I couldn't find any c/c++ example code. How to enable/implement a context menu for a rich edit control ?
It seems that you have created a custom edit window.
You can handle right click on the edit window via checking for WM_CONTEXTMENU in your WndProc.
Grab the handle to the window via the wParam parameter, compare it to your edit window to see if the user right clicked the edit window.
From there, create the popupmenu via CreatePopupMenu().
Insert/Append into the menu via InsertMenu()/AppendMenu().
Finally, call TrackPopupMenu().
Code:
#define IDC_PASTE 102
case WM_CONTEXTMENU:
if ((HWND)wParam == hwndEdit)
{
m_hMenu = CreatePopupMenu();
InsertMenu(m_hMenu, 0, MF_BYCOMMAND | MF_STRING | MF_ENABLED, IDC_PASTE, L"Paste");
TrackPopupMenu(m_hMenu, TPM_TOPALIGN | TPM_LEFTALIGN, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 0, hWnd, NULL);
}
Next you need to handle the paste message. As can be seen from the problem, your paste shortcut is still useful, so you can use SendInput to simulate paste.
Code:
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDC_PASTE:
{
SetForegroundWindow(hwndEdit);
INPUT ip;
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0;
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;
// Press the "Ctrl" key
ip.ki.wVk = VK_CONTROL;
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
// Press the "V" key
ip.ki.wVk = 'V';
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
// Release the "V" key
ip.ki.wVk = 'V';
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
// Release the "Ctrl" key
ip.ki.wVk = VK_CONTROL;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
}
break;
...

Minimize all open windows?

I need to perform the same task as WindowsKey + M through code, ie. minimize all open windows. This must be done through the Win32 API, not .Net.
I tried the following in FreeBasic, but nothing happens:
Dim hWndConsole As HWND
'Shell_TrayWnd = class name of taskbar
Dim WindowName as String = "Shell_TrayWnd"
hWndConsole = FindWindow(0, strptr(WindowName))
ShowWindow(hWndConsole, SW_MINIMIZE) 'outta my sight
Does someone know how to do this?
Thank you.
Edit: Here's the working solution:
#include "Windows.bi"
Dim hWndConsole As HWND
'Shell_TrayWnd = class name of taskbar
Dim WindowName as String = "Shell_TrayWnd"
Dim res as LRESULT
CONST minall = 419
hWndConsole = FindWindow( "Shell_TrayWnd",null)
res = postMessage(hWndConsole, WM_COMMAND, minall, null )
This seems like a bit of a hack to me, but the following does seem to accomplish what you are looking for (in C):
HANDLE hwnd = FindWindow( "Shell_TrayWnd", NULL );
LRESULT res = SendMessage( hwnd, WM_COMMAND, (WPARAM)419, 0 );
When you have the handle of a window, you can make it minimize with the WM_SYSCOMMAND message. E.g.:
SendMessage(hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
So all you would need to do is enumerate the top-level windows (with the EnumWindows command) and send that command to the windows you want to minimize (which wouldn't be all top-level windows - probably only visible, overlapped windows without the WS_EX_TOOLWINDOW extended style should be minimized like this).
Putting this out as an option, not a recommendation - simulating the keyboard events for Win-M:
keybd_event(VK_LWIN, 0, 0, 0);
keybd_event('M', 0, 0, 0);
keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);

WIndows MAPI unicode issue

It seems to me that MAPI (Windows Mail API) has issues with UTF8 (or maybe I did something wrong).
Code sample:
HMODULE m_hLib = LoadLibraryA("MAPI32.DLL");
if (m_hLib == NULL)
return SEND_MAIL_CANCELED;
LPMAPISENDMAIL SendMail;
SendMail = (LPMAPISENDMAIL) GetProcAddress(m_hLib, "MAPISendMail");
if (!SendMail)
return;
MapiFileDesc fileDesc;
ZeroMemory(&fileDesc, sizeof(fileDesc));
fileDesc.nPosition = (ULONG) -1;
fileDesc.lpszPathName = (LPSTR) filePath.toUtf8();
fileDesc.lpszFileName = (LPSTR) fileName.toUtf8();
MapiRecipDesc recipientData;
ZeroMemory(&recipientData, sizeof(recipientData));
recipientData.lpszName = (LPSTR) recipient.toUtf8();
recipientData.ulRecipClass = MAPI_TO;
MapiMessage message;
ZeroMemory(&message, sizeof(message));
message.ulReserved = CP_UTF8;
message.lpszSubject = (LPSTR) title.toUtf8();
message.nFileCount = 1;
message.lpFiles = &fileDesc;
message.nRecipCount = 1;
message.lpRecips = &recipientData;
int nError = SendMail(0, NULL, &message, MAPI_LOGON_UI | MAPI_DIALOG, 0);
title, filePath, fileName and recipient are all std::strings. As far as I know, UTF8 is compatible with ASCII (also NULL terminated), so its string can hold such values without any problems.
I'm converting to UTF8 from wstring in this way:
int requiredSize = WideCharToMultiByte(CP_UTF8, 0, data.c_str(), -1, 0, 0, 0, 0);
if(requiredSize > 0)
{
std::vector<char> buffer(requiredSize);
WideCharToMultiByte(CP_UTF8, 0, data.c_str(), -1, &buffer[0], requiredSize, 0, 0);
this->container.append(buffer.begin(), buffer.end() - 1);
}
container is a std::string object.
MAPISendMail() does not support UTF-8, only Ansi. If you need to send Unicode data, you have to use MAPISendMailHelper() on Windows 7 and earlier, or MAPISendMailW() on Windows 8 and later. This is clearly stated in the MAPISendMail() documentation.
On a side note, WideCharToMultiByte() includes the null terminator when you set the cchWideChar parameter to -1. As such, you are encoding and including that null terminator in your container data. You should instead set cchWideChar to the actual length of the string to avoid the null terminator completely:
int requiredSize = WideCharToMultiByte(CP_UTF8, 0, data.c_str(), data.length(), 0, 0, 0, 0);
if (requiredSize > 0)
{
std::vector<char> buffer(requiredSize);
WideCharToMultiByte(CP_UTF8, 0, data.c_str(), data.length(), &buffer[0], requiredSize, 0, 0);
container.append(buffer.begin(), buffer.end());
}
On http://msdn.microsoft.com/en-us/library/windows/desktop/dd296721.aspx it states "On Windows 7 and earlier: Use MAPISendMailHelper to send a message" but at the bottom of http://msdn.microsoft.com/en-us/library/windows/desktop/hh802867.aspx it states "Minimum supported" is Windows 8. Seems like contradictory information and therefore it's unclear whether MAPISendMailHelper is really for Windows 7 and earlier.

Save snapshots of minimized windows with Xlib

In short, I want to write a Gnome-Shell-style window switcher. So I need to fetch snapshots of all the windows. My current program looks like this:
char filename[101];
sprintf(filename, "%d.png", (int)win_list[i]);
GdkWindow *win_gdk = gdk_x11_window_foreign_new_for_display
(gdk_display_get_default(), win_list[i]);
gint _w, _h;
gdk_drawable_get_size(GDK_DRAWABLE(win_gdk), &_w, &_h);
XEvent _xevent;
_xevent.xexpose =
(XExposeEvent)
{
.type = Expose,
.send_event = True,
.display = xsu_vars.dpy,
.window = win_list[i],
.x = 0, .y = 0, .width = _w, .height = _h,
.count = 0
};
XSendEvent(xsu_vars.dpy, win_list[i], False, 0, &_xevent);
GdkPixbuf *_pb = gdk_pixbuf_get_from_drawable(
NULL, GDK_DRAWABLE(win_gdk), NULL, 0, 0, 0, 0, _w, _h);
if(_pb != NULL) {
cairo_surface_t *_surf_cairo = cairo_image_surface_create(
CAIRO_FORMAT_RGB24, _w, _h);
cairo_t *_cr = cairo_create(_surf_cairo);
gdk_cairo_set_source_pixbuf(_cr, _pb, 0, 0);
cairo_paint(_cr);
cairo_surface_write_to_png(_surf_cairo, filename);
printf("%s saved successfully!\n", filename);
} else {
printf("failed...\n");
}
The program works well well, but it will not generate correct images for those windows which are on a different desktop of minimized -- they would look like this:
Note that I send a expose event to all windows before generating pixbufs of them.
UPDATE:
It seems that xlib doesn't support that. So the only way may be creating cache manually.
This is possible with Composite extension - see "Preventing the backing pixmap from being freed when the window is hidden/destroyed" section in tutorial.
Yes, your update is correct. When a window is unmapped (or covered up), X just discards its contents; they don't exist anywhere in order to be snapshotted.
I believe libwnck contains code to do this and other parts of writing a switcher, btw. It's basically a library for writing things like window switchers.

How to activate some window from external application in windows?

I want to send some keystroke to the external application, and it's work fine, but when I try to send keystroke to the child window of same external application, for some reason that doesn't work, so I need help. Let's say that we want to print clipboard text from notepad, and want to do it at one step. At code that will look like this.
#include <windows.h>
#include <stdio.h>
#include <iostream.h>
using namespace std;
int main(int argc, char* argv[]){
WinExec("notepad", 1);
Sleep(1000);
HWND handle = FindWindow("notepad",0); // it's handling as well
SetForegroundWindow(handle);
keybd_event(VK_CONTROL, 0, 0, 0); // simulate CTRL down
keybd_event(VkKeyScan('V'), 0, 0, 0);
keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
Sleep(500);
keybd_event(VK_CONTROL, 0, 0, 0); // simulate CTRL down
keybd_event(VkKeyScan('P'), 0, 0, 0);
keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); // simulate CTRL up
Sleep(1000);
HWND handle1 = FindWindow(0, "Print"); // it wann't find "Print" window
SetForegroundWindow(handle1);
keybd_event(VK_MENU, 0, 0, 0); // simulate ALT down
keybd_event(VkKeyScan('P'), 0, 0, 0);
keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
return 0;
}
But it want to send ALT+P to "Print" window, why?
Final goal is to make little macro that send to application keystorkes (on any windows child, or parent..)
OS: WIN 7 64bit
You can probably make the existing code (sort of) work by simply removing these lines:
HWND handle1 = FindWindow(0, "Print"); // it wann't find "Print" window
SetForegroundWindow(handle1);
Remember that faked input goes to the thread which has the input focus and when you show the print dialog in Notepad, that dialog will gain the input focus. You simply do not need to set the focus, the system will do that for you.
However, the approach you are taking is incredibly brittle. I suspect that you would be far better served by using something like UI Automation.

Resources