October 31, 2025, 11:49:42 AM

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


Trans-application messaging

Started by Jerry Muelver, January 24, 2009, 05:25:09 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Jerry Muelver

WordWeb sits in my taskbar. When I select text in ANY application, click on the WordWeb icon, WordWeb pops up instantly with a spellcheck and thesaurs reference for the highlighted text. My question is, how does WordWeb know about the selected text? I know about the clipboard, but this text is not copied, just selected. How do I grab that selected text to feed to my app?

Jerry Muelver

Found this in windows.inc:

DECLARE IMPORT, _GetForegroundWindow ALIAS GetForegroundWindow(),INT

' SetWindowsHook() codes
CONST WH_MIN = (-1)
CONST WH_MSGFILTER = (-1)
CONST WH_JOURNALRECORD = 0
CONST WH_JOURNALPLAYBACK = 1
CONST WH_KEYBOARD = 2
CONST WH_GETMESSAGE = 3
CONST WH_CALLWNDPROC = 4
CONST WH_CBT = 5
CONST WH_SYSMSGFILTER = 6
CONST WH_MOUSE = 7
CONST WH_HARDWARE = 8
CONST WH_DEBUG = 9
CONST WH_SHELL = 10
CONST WH_FOREGROUNDIDLE = 11
CONST WH_MAX = 11

--------------
Is that the stuff I need?

sapero

January 24, 2009, 04:29:58 PM #2 Last Edit: January 25, 2009, 09:52:29 AM by sapero
I have been working on it. This tiny program called "WordWeb Emu" can copy selected text from edit, richedit, scintilla and webbrowser without any hooks. The active edit control is pooled every 1 sec by GetGUIThreadInfo api, in timer handler.

For edit controls there is no command to copy only the selected text (?), so I have created a separate function that copies the whole text into string, and then copies the selection into internal edit control.
$include "windowssdk.inc"
$include "richedit.inc"
$include "mshtml.inc"
$include "Oleacc.inc"
CONST IDC_TEXT = 1000

DIALOG d1
NOTIFYICONDATA g_nid
UINT WM_TRAY
UINT WM_HTML_GETOBJECT
HWND g_hwndFocus

CREATEDIALOG d1,0,0,426,273,0x80CA0080,0,"WordWeb Emu",&d1_handler
CONTROL d1,@STATIC,"",0,0,0,0,0x5080010B,4
CONTROL d1,@EDIT,"", 10,11,406,227,0x50A00004,IDC_TEXT
DOMODAL d1


SUB d1_handler
int threadId, processId
GUITHREADINFO ti

SELECT @MESSAGE
CASE @IDINITDIALOG
CENTERWINDOW d1
' setup a new tray icon
WM_TRAY      = RegisterWindowMessage("MyTrayMessage")
WM_HTML_GETOBJECT = RegisterWindowMessage("WM_HTML_GETOBJECT")
g_nid.cbSize = len(g_nid)
g_nid.hWnd   = d1.hwnd
g_nid.uID    = 1
g_nid.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP
g_nid.hIcon  = LoadIcon(0, IDI_APPLICATION)
strcpy(&g_nid.szTip, "WordWeb Emulator")
g_nid.uCallbackMessage = WM_TRAY
Shell_NotifyIcon(NIM_ADD, &g_nid)
'
StartTimer(d1, 1000, 100)
SetControltext(d1, IDC_TEXT, "select text in edit/richedit/scintilla/browser and click tray icon")

case @IDTIMER
if (@WPARAM = 100)
' save the focused window handle in g_hwndFocus
threadId = GetWindowThreadProcessId(GetForegroundWindow(), &processId)
if (processId <> GetCurrentProcessId())
ti.cbSize = len(ti)
ti.hwndFocus = 0
GetGUIThreadInfo(threadId, &ti)
g_hwndFocus = ti.hwndFocus
endif
endif

CASE @IDCLOSEWINDOW
DestroyIcon(g_nid.hIcon)
Shell_NotifyIcon(NIM_DELETE, &g_nid)
CLOSEDIALOG d1,@IDOK

CASE WM_TRAY
OnTray(@LPARAM)

ENDSELECT
RETURN
ENDSUB

sub OnTray(LPARAM lParam)
POINT pt
int cmdid

select (lParam)

case WM_RBUTTONUP
HMENU hPopup = CreatePopupMenu()
_InsertMenu(hPopup, 0, MF_BYPOSITION, 100, IIFP(IsWindowVisible(d1.hwnd), "Hide", "Show"))
_InsertMenu(hPopup, 1, MF_BYPOSITION|MF_SEPARATOR, 0, 0)
_InsertMenu(hPopup, 2, MF_BYPOSITION, 101, "Exit")

GetCursorPos(&pt)
SetForegroundWindow(d1.hwnd)
cmdid = TrackPopupMenu(hPopup, TPM_RETURNCMD, pt.x, pt.y, 0, d1.hwnd, 0)
PostMessage(d1.hwnd, WM_NULL, 0, 0)
DestroyMenu(hPopup)

select (cmdid)
case 100
OnTray(WM_LBUTTONDBLCLK)
case 101:
CloseDialog(d1, 0)
endselect

case WM_LBUTTONDBLCLK
SetForegroundWindow(d1.hwnd)
ShowWindow d1, IIF(IsWindowVisible(d1.hwnd), @SWHIDE, @SWRESTORE)

case WM_LBUTTONDOWN
if (IsWindowVisible(d1.hwnd))
CopyTextFromWindow()
endif
endselect
return
endsub


sub CopyTextFromWindow()
BOOL fIsunicode
BOOL handled
istring szClassName[64]

SetControltext(d1, IDC_TEXT, "")
if (g_hwndFocus and GetClassName(g_hwndFocus, szClassName, 64))

StopTimer(d1, 100)
'SetCaption d1, szClassName
CharLower(szClassName)

fIsunicode = IsWindowUnicode(g_hwndFocus)

select (szClassName)

case "edit"
CopyTextFromEdit()

case "riched"
case& "richedit20a"
case& "richedit20w"
case& "richedit50w"
case& "scintilla"
' TODO: more richedit classes
CopyTextFromRichEdit(fIsunicode)

case "internet explorer_server"
CopyTextFromIE()

default
SetControltext(d1, IDC_TEXT, using("Unhandled class name: &", szClassName))

endselect
StartTimer(d1, 1000, 100)
SetForegroundWindow(d1.hwnd)
endif
return
endsub


sub CopyTextFromEdit()
pointer pText
int     cpMin
int     cpMax
int     cch

SendMessageA(g_hwndFocus, EM_GETSEL, &cpMin, &cpMax)
cch = SendMessageA(g_hwndFocus, WM_GETTEXTLENGTH, 0, 0) + 1

if ((cpMin = 0) and (cpMax = -1))
cpMax = cch - 1
endif

if (cpMax > cpMin)

pText = new(char, cch)
if (pText)
SendMessageA(g_hwndFocus, WM_GETTEXT, cch, pText)

*<char>(pText + cpMax) = 0
SetControltext(d1, IDC_TEXT, *<string>(pText + cpMin))

delete pText
endif
endif

return
endsub


sub CopyTextFromRichEdit(BOOL fIsunicode)
int     processId
HANDLE  hProces
pointer pRemoteMemory
pointer pText
int     cpMin
int     cpMax
int     cchAlloc
int     cch
int     bytesRead

' retrieves the starting and ending character positions of the current selection
SendMessageA(g_hwndFocus, EM_GETSEL, &cpMin, &cpMax)

' if something is selected
if (cpMax > cpMin)
cch = cpMax - cpMin + 1

cchAlloc = cch
if (fIsunicode) then cchAlloc = cch * 2

GetWindowThreadProcessId(g_hwndFocus, &processId)
hProces = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE, FALSE, processId)
if (hProces)

pRemoteMemory = VirtualAllocEx(hProces, 0, cchAlloc, MEM_COMMIT, PAGE_READWRITE)

if (pRemoteMemory)

pText = new(char, cchAlloc)
if (pText)
SendMessageA(g_hwndFocus, EM_GETSELTEXT, 0, pRemoteMemory)
ReadProcessMemory(hProces, pRemoteMemory, pText, cchAlloc, &bytesRead)

if (fIsunicode)
SetControlTextW(d1, IDC_TEXT, *<wstring>pText)
else
SetControlText(d1, IDC_TEXT, *<string>pText)
endif

delete pText
endif
VirtualFreeEx(hProces, pRemoteMemory, 0, MEM_RELEASE)
endif
CloseHandle(hProces)
endif
endif

return
endsub


sub CopyTextFromIE()
DWORD dwResult

CoInitialize(0)

if (SendMessageTimeout(g_hwndFocus, WM_HTML_GETOBJECT, 0, 0, SMTO_ABORTIFHUNG, 1000, &dwResult))

IHTMLDocument2 doc
if (ObjectFromLresult(dwResult, _IID_IHTMLDocument2, 0, &doc) = 0)

IHTMLSelectionObject selection
if ((doc->get_selection(&selection) = 0) and selection)

IDispatch disp
if ((selection->createRange(&disp) = 0) and disp)

IHTMLTxtRange textrange
if (disp->QueryInterface(_IID_IHTMLTxtRange, &textrange) = 0)

BSTR bstrText
if ((textrange->get_text(&bstrText) = 0) and bstrText)
SetControltext(d1, IDC_TEXT, w2s(*<wstring>bstrText))
SysFreeString(bstrText)
endif
textrange->Release()
endif
disp->Release()
endif
selection->Release()
endif
doc->Release()
endif
endif
CoUninitialize()
return
endsub


EIDT: updated CopyTextFromEdit()

Ionic Wind Support Team

Sapero, for normal edit controls I think you can just send it a WM_COPY message, once you have the handle to the control.

From Microsoft:

Quote
An application sends the WM_COPY message to an edit control or combo box to copy the current selection to the clipboard in CF_TEXT format.

Paul.
Ionic Wind Support Team

Jerry Muelver

Thank you, both! This will take some (serious) study on my part.  ::)

Thank you, again.

Did I mention, "Thank you"?

Jerry Muelver

Hmmm.... I seem to be missing windowssdk.inc. I'll have to get all the puzzle pieces together, first.  ;)