andla
asked on
Getting text from treeview from outside
Does anybody know how to get text from a treeview control that does not belong to my process ?
When i run this code i get an access violation in comctl32.dll
Please help me.
int wfp=(int)(hWnd=(HWND)Windo wFromPoint (pt));
HTREEITEM hti = TreeView_GetRoot(hWnd);
if(hti)
{
item.mask =TVIF_TEXT;
item.cchTextMax=199;
item.pszText=new char[300];
strcpy(item.pszText,"");
item.hItem = hti;
hti=(HTREEITEM)TreeView_Ge tNextItem( hWnd,&item ,TVGN_CARE T);
TreeView_GetItem(hWnd,&ite m);//This macro always fails.
int x=0;//Just to stop the debugger inside brackets
x=1;
}
Regards
Andla
When i run this code i get an access violation in comctl32.dll
Please help me.
int wfp=(int)(hWnd=(HWND)Windo
HTREEITEM hti = TreeView_GetRoot(hWnd);
if(hti)
{
item.mask =TVIF_TEXT;
item.cchTextMax=199;
item.pszText=new char[300];
strcpy(item.pszText,"");
item.hItem = hti;
hti=(HTREEITEM)TreeView_Ge
TreeView_GetItem(hWnd,&ite
int x=0;//Just to stop the debugger inside brackets
x=1;
}
Regards
Andla
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Note I use ListView_GetItem, because it was easier to find a listview on my computer.
//----------
// Main.cpp
//----------
//cl /LD /MD hook.cpp user32.lib kernel32.lib comctl32.lib
//cl main.cpp hook.lib user32.lib
#include <windows.h>
#include <stdlib.h>
#include <iostream.h>
HWND hTV;
bool setHook(HWND hTV,HWND w);
LRESULT CALLBACK wndProc(HWND w,UINT msg,WPARAM wp,LPARAM lp)
{
switch(msg) {
case WM_COPYDATA:
{
PCOPYDATASTRUCT c=(PCOPYDATASTRUCT)lp;
LPSTR t=new CHAR[c->cbData];
memcpy(t,c->lpData,c->cbDa ta);
ReplyMessage(0);
MessageBox(0,t,"Item text",MB_OK);
delete[] t;
SendMessage(w,WM_CLOSE,0,0 );
break;
}
case WM_USER:
setHook(hTV,w);
break;
case WM_CREATE:
PostMessage(w,WM_USER,0,0) ;
return 0;
case WM_RBUTTONDOWN:
case WM_CLOSE:
PostQuitMessage(0);
DestroyWindow(w);
return 0;
}
return DefWindowProc(w,msg,wp,lp) ;
}
//int WINAPI WinMain(HINSTANCE,HINSTANC E,LPSTR,in t)
void main(int argc,char* argv[])
{
if(argc<2)
{
cout<<"Usage: main.exe <listview handle (eg: 0x123400)>"<<endl;
return;
}
hTV=HWND(strtoul(argv[1],0 ,0));
if(!hTV)
{
cout<<"Not a window"<<endl;
return;
}
WNDCLASS cls;
memset(&cls,0,sizeof(cls)) ;
cls.lpfnWndProc=wndProc;
cls.hInstance=GetModuleHan dle(0);
cls.hIcon=0;
cls.lpszClassName="test";
cls.hbrBackground=HBRUSH(C OLOR_WINDO W+1);
RegisterClass(&cls);
HWND w=CreateWindowEx(0,"test", "test",
WS_POPUP|WS_VISIBLE|WS_SYS MENU|WS_CA PTION,
5,5,200,200,0,0,cls.hInsta nce,0);
MSG msg;
while(GetMessage(&msg,0,0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
//----------
// Hook.dll
//----------
#include <windows.h>
#include <commctrl.h>
#pragma data_seg(".shared")
HHOOK hHook=0;
HWND hTV=0;
HWND hW=0;
#pragma data_seg()
#pragma comment(linker,"/SECTION:. shared,RWS ")
HINSTANCE hDll;
LRESULT CALLBACK hookProc(int code,WPARAM wParam,LPARAM lParam)
{
char buf[120];
LVITEM t;
t.mask=LVIF_TEXT;
t.pszText=buf;
t.cchTextMax=sizeof(buf);
t.iItem=0;
t.iSubItem=0;
ListView_GetItem(hTV,&t);
COPYDATASTRUCT c={0,strlen(buf)+1,buf};
SendMessage(hW,WM_COPYDATA ,WPARAM(hT V),LPARAM( &c));
LRESULT r=CallNextHookEx(hHook,cod e,wParam,l Param);
UnhookWindowsHookEx(hHook) ;
return r;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID)
{
if(fdwReason==DLL_PROCESS_ ATTACH)
hDll=hinstDLL;
return TRUE;
}
_declspec(dllexport) bool setHook(HWND htv,HWND w)
{
hTV=htv;
hW=w;
DWORD tid=GetWindowThreadProcess Id(hTV,0);
hHook=SetWindowsHookEx(WH_ GETMESSAGE ,hookProc, hDll,tid);
PostThreadMessage(tid,WM_G ETTEXTLENG TH,0,0);
return hHook!=0;
}
_declspec(dllexport) void removeHook()
{
if(hHook) UnhookWindowsHookEx(hHook) ;
}
//----------
// Main.cpp
//----------
//cl /LD /MD hook.cpp user32.lib kernel32.lib comctl32.lib
//cl main.cpp hook.lib user32.lib
#include <windows.h>
#include <stdlib.h>
#include <iostream.h>
HWND hTV;
bool setHook(HWND hTV,HWND w);
LRESULT CALLBACK wndProc(HWND w,UINT msg,WPARAM wp,LPARAM lp)
{
switch(msg) {
case WM_COPYDATA:
{
PCOPYDATASTRUCT c=(PCOPYDATASTRUCT)lp;
LPSTR t=new CHAR[c->cbData];
memcpy(t,c->lpData,c->cbDa
ReplyMessage(0);
MessageBox(0,t,"Item text",MB_OK);
delete[] t;
SendMessage(w,WM_CLOSE,0,0
break;
}
case WM_USER:
setHook(hTV,w);
break;
case WM_CREATE:
PostMessage(w,WM_USER,0,0)
return 0;
case WM_RBUTTONDOWN:
case WM_CLOSE:
PostQuitMessage(0);
DestroyWindow(w);
return 0;
}
return DefWindowProc(w,msg,wp,lp)
}
//int WINAPI WinMain(HINSTANCE,HINSTANC
void main(int argc,char* argv[])
{
if(argc<2)
{
cout<<"Usage: main.exe <listview handle (eg: 0x123400)>"<<endl;
return;
}
hTV=HWND(strtoul(argv[1],0
if(!hTV)
{
cout<<"Not a window"<<endl;
return;
}
WNDCLASS cls;
memset(&cls,0,sizeof(cls))
cls.lpfnWndProc=wndProc;
cls.hInstance=GetModuleHan
cls.hIcon=0;
cls.lpszClassName="test";
cls.hbrBackground=HBRUSH(C
RegisterClass(&cls);
HWND w=CreateWindowEx(0,"test",
WS_POPUP|WS_VISIBLE|WS_SYS
5,5,200,200,0,0,cls.hInsta
MSG msg;
while(GetMessage(&msg,0,0,
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
//----------
// Hook.dll
//----------
#include <windows.h>
#include <commctrl.h>
#pragma data_seg(".shared")
HHOOK hHook=0;
HWND hTV=0;
HWND hW=0;
#pragma data_seg()
#pragma comment(linker,"/SECTION:.
HINSTANCE hDll;
LRESULT CALLBACK hookProc(int code,WPARAM wParam,LPARAM lParam)
{
char buf[120];
LVITEM t;
t.mask=LVIF_TEXT;
t.pszText=buf;
t.cchTextMax=sizeof(buf);
t.iItem=0;
t.iSubItem=0;
ListView_GetItem(hTV,&t);
COPYDATASTRUCT c={0,strlen(buf)+1,buf};
SendMessage(hW,WM_COPYDATA
LRESULT r=CallNextHookEx(hHook,cod
UnhookWindowsHookEx(hHook)
return r;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID)
{
if(fdwReason==DLL_PROCESS_
hDll=hinstDLL;
return TRUE;
}
_declspec(dllexport) bool setHook(HWND htv,HWND w)
{
hTV=htv;
hW=w;
DWORD tid=GetWindowThreadProcess
hHook=SetWindowsHookEx(WH_
PostThreadMessage(tid,WM_G
return hHook!=0;
}
_declspec(dllexport) void removeHook()
{
if(hHook) UnhookWindowsHookEx(hHook)
}
ASKER
I see that you use a library instead of a dll.
I did try to make a dll project but i don't have much experience with this.
If i'm not entirely wrong I have read that LoadLibrary mostly returns 0x10000000 witch should be normal. But i don't understand way GetLastError return 120.
When i use the GetProcAddress it return NULL and GetLastError returns 126 because it could not find the module.
I then tried to use GetModuleHandle but this functions always returns 0 and GetLastError return 126. I tried both the filename and the whole path with the filename.
I think i have to try to make a library file instead and se if i have more luck with that :-)
Regards
Andreas.
I did try to make a dll project but i don't have much experience with this.
If i'm not entirely wrong I have read that LoadLibrary mostly returns 0x10000000 witch should be normal. But i don't understand way GetLastError return 120.
When i use the GetProcAddress it return NULL and GetLastError returns 126 because it could not find the module.
I then tried to use GetModuleHandle but this functions always returns 0 and GetLastError return 126. I tried both the filename and the whole path with the filename.
I think i have to try to make a library file instead and se if i have more luck with that :-)
Regards
Andreas.
ASKER
How do i avoid this ?
Compiling...
program.cpp
Linking...
LINK : warning LNK4075: ignoring /INCREMENTAL due to /FORCE specification
AndySLib.lib(prg.obj) : warning LNK4006: "struct HWND__ * hTV" (?hTV@@3PAUHWND__@@A) already defined in program.obj; second definition ignored
AndySLib.lib(prg.obj) : warning LNK4006: "struct HWND__ * hTV" (?hTV@@3PAUHWND__@@A) already defined in program.obj; second definition ignored
Compiling...
program.cpp
Linking...
LINK : warning LNK4075: ignoring /INCREMENTAL due to /FORCE specification
AndySLib.lib(prg.obj) : warning LNK4006: "struct HWND__ * hTV" (?hTV@@3PAUHWND__@@A) already defined in program.obj; second definition ignored
AndySLib.lib(prg.obj) : warning LNK4006: "struct HWND__ * hTV" (?hTV@@3PAUHWND__@@A) already defined in program.obj; second definition ignored
ASKER
Oops sorry i fixed it with the extern keyword.
ASKER
I did fix so your program worked.
I can now get the text from lisview items. I did some changes and added a timer procedure so that i just could point on the window.
void CALLBACK Timer(HWND hw,UINT msg,UINT ident,DWORD time)
{
if(GetAsyncKeyState(VK_CON TROL) & 0x8000)
{
MessageBeep(0xffffffff);
POINT pt;
GetCursorPos( &pt );
hTV=(HWND)WindowFromPoint( pt);
setHook(hTV,hWnd);
}
}
Thanks for your help i think i can continue now. :-)
I would be happy if you could stay in this posting if you got some time over to aid me on my way. If you want i can post my solution with treeview laiter.
Regards
Andreas.
I can now get the text from lisview items. I did some changes and added a timer procedure so that i just could point on the window.
void CALLBACK Timer(HWND hw,UINT msg,UINT ident,DWORD time)
{
if(GetAsyncKeyState(VK_CON
{
MessageBeep(0xffffffff);
POINT pt;
GetCursorPos( &pt );
hTV=(HWND)WindowFromPoint(
setHook(hTV,hWnd);
}
}
Thanks for your help i think i can continue now. :-)
I would be happy if you could stay in this posting if you got some time over to aid me on my way. If you want i can post my solution with treeview laiter.
Regards
Andreas.
ASKER
I can now get the text from lisview items. I did some changes and added a timer procedure so that I just could point on the window.
void CALLBACK Timer(HWND hw,UINT msg,UINT ident,DWORD time)
{
if(GetAsyncKeyState(VK_CON
{
MessageBeep(0xffffffff);
POINT pt;
GetCursorPos( &pt );
hTV=(HWND)WindowFromPoint(
setHook(hTV,hWnd);
}
}
Thanks for your help i think i can continue now. :-)
I would be happy if you could stay in this posting if you got some time over to aid me on my way. If you want i can post my solution with treeview laiter.
Regards
Andreas.I did fix so your program worked.
>>I see that you use a library instead of a dll.
It must be a DLL and not LIB. The main program must be linked with the import library (LIB) of the DLL.
So you compile and link the DLL code, and get DLL and LIB files. Then you compile the main code and link it with LIB. No need to load library explicitly, it will be done automatically.
It must be a DLL and not LIB. The main program must be linked with the import library (LIB) of the DLL.
So you compile and link the DLL code, and get DLL and LIB files. Then you compile the main code and link it with LIB. No need to load library explicitly, it will be done automatically.
ASKER
Thanks :-)
Here is what i did and it worked.
I created a lib project and added the code.
I create a win32 project and added the .lib file in
the project. I added your code and did some small changes and added the timer procedure.
If you don't believe me i can send you the project :-D
From above i had some problem with dll's and thats because Microsoft for some reason forgot to add extern "C" {}. So now i succeded with a dll (hurray). But i have trouble understand what dllimport is used for.
Regards
Andreas
Here is what i did and it worked.
I created a lib project and added the code.
I create a win32 project and added the .lib file in
the project. I added your code and did some small changes and added the timer procedure.
If you don't believe me i can send you the project :-D
From above i had some problem with dll's and thats because Microsoft for some reason forgot to add extern "C" {}. So now i succeded with a dll (hurray). But i have trouble understand what dllimport is used for.
Regards
Andreas
The solution provided above by Nick is fantastic. I only ran into one problem: you can't call PostThreadMessage() with the WM_GETTEXTLENGTH message; the MSDN page for WM_GETTEXTLENGTH says the message should only be sent, not posted. On Win2k this caused the call to PostThreadMessage() to fail, so the hook procedure was never called and the messagebox never came up.
I'm not sure what the best alternative is, but calling it with WM_USER seems to work just fine. From there, you can easily build on Nick's example code to accomplish whatever you need.
I'm not sure what the best alternative is, but calling it with WM_USER seems to work just fine. From there, you can easily build on Nick's example code to accomplish whatever you need.
ASKER
geissomatic >>I'm glad to se something happening on old qestions even if it is one year old. What are you trying to accomplish ? I'm Curious.
Yours sincerely
Andla
Yours sincerely
Andla
WM_USER is not good, because it might cause some undesired action in the destination window procedure.
WM_NULL must be better.
WM_NULL must be better.
Nick - Thanks! I'll try using WM_NULL instead.
Andla - I'm working on running intensively animated graphics (i.e. hardware-accelerate stuff) as your wallpaper (behind the icons) without using overlays. But, there's really no way to do this without recreating an articial desktop... so I need to query the desktop's listview child window for all of its icon positions, text labels, and PIDL's (which, it turns out, seem to be pointed to by the 32-bit userdata parameter for each item text). It should be posted, with most of the source code, at http://www.nullsoft.com/free/vms/ within a week or so. For a beta demo, go to http://www.geisswerks.com/ryan/whatsnew-graphics.html and download the 3 files in the 10/20/02 entry. (Requires Winamp 2.x)
This is great stuff! Thanks for everyone's help!
Andla - I'm working on running intensively animated graphics (i.e. hardware-accelerate stuff) as your wallpaper (behind the icons) without using overlays. But, there's really no way to do this without recreating an articial desktop... so I need to query the desktop's listview child window for all of its icon positions, text labels, and PIDL's (which, it turns out, seem to be pointed to by the 32-bit userdata parameter for each item text). It should be posted, with most of the source code, at http://www.nullsoft.com/free/vms/ within a week or so. For a beta demo, go to http://www.geisswerks.com/ryan/whatsnew-graphics.html and download the 3 files in the 10/20/02 entry. (Requires Winamp 2.x)
This is great stuff! Thanks for everyone's help!
I've read that from NickRepin :
" It doesn't work because you pass to TreeView_GetItem() a memory buffer which is in the address space of another (your) process and therefore inaccessible ".
I'm not sure to understand ...
To get a text from a window, I do that (which is working) :
char t[500];
SendMessage(H0, WM_GETTEXT, (WPARAM) 500, (LPARAM) &t);
Why that works, and not the same thing for TListView, please ?
char t[1000];
LV_ITEM p;
p.mask = LVIF_TEXT;
p.pszText = t;
for (int i = 0 ; i < ListView_GetItemCount(H0) ; i++) {
p.iItem = i;
p.iSubItem = 0;
p.cchTextMax = 1000;
SendMessage(H0, LVM_GETITEM, 0, (LPARAM) (LV_ITEM FAR *) &p);
ListBox1->Items->Add(t);
}
Thanks
Mathieu
" It doesn't work because you pass to TreeView_GetItem() a memory buffer which is in the address space of another (your) process and therefore inaccessible ".
I'm not sure to understand ...
To get a text from a window, I do that (which is working) :
char t[500];
SendMessage(H0, WM_GETTEXT, (WPARAM) 500, (LPARAM) &t);
Why that works, and not the same thing for TListView, please ?
char t[1000];
LV_ITEM p;
p.mask = LVIF_TEXT;
p.pszText = t;
for (int i = 0 ; i < ListView_GetItemCount(H0) ; i++) {
p.iItem = i;
p.iSubItem = 0;
p.cchTextMax = 1000;
SendMessage(H0, LVM_GETITEM, 0, (LPARAM) (LV_ITEM FAR *) &p);
ListBox1->Items->Add(t);
}
Thanks
Mathieu
ASKER
How would this dll look like ?
How would i use the WM_COPY ?
I'm using windows 98.
/Andla