Hi,
I'm writing (for fun) a kiosk application that creates a second desktop runs some applications on it and only returns to the original desktop when the users enters a password. I got all this working and have 2 processes each running in a different desktop account.
My problem is i thought using WM_COPYDATA to communicate between the 2 applications but i can't find the window handle of the application running on the other desktop. I have the DF_ALLOWOTHERACCOUNTHOOK flag set when using CreateDesktop but that doesn't seem to work. (How can one hook without a window's handle?)
Does anybody know if it's possible to find the handle of a window in process on a created desktop?
And if not, what would be the second best way to communicate between 2 applications? I was thinking about waiting for events in a thread (CreateEvent, WaitForSingleObject etc) but being able to use the application's message window would be best (for me).
Regards,
Michaël
there are a couple ways
you could use HWND_BROADCAST to send the first message to all windows
another way might be to use the clipboard to pass the handle
another way to go, altogether, is to use DDE - a bit complicated
still another way is to find the window with EnumWindows
if you create the process, you have the process ID
Michaël,
The usual FindWindow etc stuff doesn't work, see below? Can the two apps communicate at all via handles?
If yes, you could pass the handle of the parent via the commandline to the child.
If no, and you don't need nanosecond speed, then polling with WM_TIMER and exchanging data via disk files works fine and is simple.
include \masm32\MasmBasic\MasmBasic.inc ; download (http://masm32.com/board/index.php?topic=94.0)
Init
.if WinByTitle("Post reply") ; returns handle in eax
xchg eax, ebx
Print "The full title is ", Win$(ebx)
SendData ebx, "Hello Mozilla, you cannot use this string..."
SetWin$ ebx="... but I can change your caption, hehe..."
.else
Print "no handle found..."
.endif
Inkey
Exit
end start
oh yah - then there is always the command line - lol
nice, Jochen :t
a method i have used before and forgot all about :lol:
Hy,
Because i want to use WM_COPYDATA because of it is convenient that you get a return value for your "command" i'll go for HWND_BROADCAST joined with a message created with RegisterWindowsMessage to pass the HWND from one to the other. If this doesn't work i'll try the commandline,... Hope that WM_COPYDATA then breaks the "desktop" barrier...
If not i'll maybe leave the communication behind(kill the process with TerminateProcess instead of WM_CLOSE) because the other options are (not bad but) too much hassle for too little need. (And it's always most fun when something that didn't work finally works...)
I thought to make it possible to load DLL's in both processes to make this program more dynamic. And make a way for those dll's to communicate. But i can leave this feature of communication behind and then the only need to communicate is to stop the other process properly.
Thx, greetings and i'll probably share some results...
You can enumerate all top level windows of a desktop using EnumDesktopWindows().
If you assign a unique property to the main window (SetProp) you can easily identify your application in that desktop.
In the attachment an working(Win7,x64) example.
Hi,
I was typing this while you posted...
Quote from: myselfHWND_BROADCAST wasn't very successfull either. Guess that's it impossible...
The bible states: Quote from: MSDN Library (http://msdn.microsoft.com/en-us/library/windows/desktop/ms682573.aspx)Window messages can be sent only between processes that are on the same desktop. In addition, the hook procedure of a process running on a particular desktop can only receive messages intended for windows created in the same desktop.
A bit strange, still have to find out what exactly DF_ALLOWOTHERACCOUNTHOOK is for (and maybe how to use it).
I could use the file system to signal the process it can exit and leave the communication i had in mind behind...
I've just seen the EnumDesktopWindows api and thought to give it a try , thx for pointing me out and for your sample i'm about to watch...
Yes! Thank you, :t :eusa_clap:
I've added the desk_b.exe in my kiosk's ini file, it was running on the new desktop, then i've hit desk_a.exe on the old desktop and desk_b.exe was gone...
Thank you, i'll try WM_COPYDATA now, i'm excited... :biggrin:
Update: WM_COPYDATA works
Hi,
Still not the solution, but i found the bottleneck. I wanted to use a "Message Only" window, but that doesn't show up in "EnumDesktopWindows" or "FindWindow". (At least not the way i did create it...)
Invoke RtlFillMemory, Addr wc, SizeOf WNDCLASSEX, 0
Mov wc.cbSize, SizeOf WNDCLASSEX
Mov wc.lpfnWndProc, Offset WndKiosk32Proc
Push hInstance
Pop wc.hInstance
Mov wc.lpszClassName, Offset szClassName
Invoke RegisterClassEx, Addr wc
Invoke CreateWindowEx, 0, Offset szClassName, Offset szNewDesktop, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, hInstance, bNewDesktop
Now i know that messages work i'll find another way to pass the handles... Send it from parent to the child process by commandline, and the child process gets it from the parent process with SendMessage...
Update: FindWindowEx should be able to find it
Quote from: Vozzie on September 25, 2012, 10:21:23 AM
Update: WM_COPYDATA works
What you attached doesn't do anything on my machine (XP SP3). I see two dialogs but they seem not to recognise each other. Or do I miss something?
This works, so the problem is elsewhere:
.elseif WORD ptr wParam == 104
if 1 ; works
SendData "Desktop B", Win$(rv(GetDlgItem, hDlg, 100)) ; requires MasmBasic (http://www.masm32.com/board/index.php?topic=94.0)
else ; no reaction from Desktop B
.if rv(GetDlgItemText,hDlg,100,&sz,LENGTHOF sz)
.if !rvx(hDesk=OpenDesktop,&sz,0,0,0)
invoke MessageBeep,MB_ICONEXCLAMATION
.else
invoke EnumDesktopWindows,hDesk,EnumWindowsProc,2
invoke CloseDesktop,hDesk
.endif
.else
invoke MessageBeep,MB_ICONEXCLAMATION
.endif
endif
.endif
Hi
The purpose is to run the second dialog on another desktop. There you run them both on the same "Default" desktop, it should work when you enter "Default" in the Edit box...
(By default, there are three desktops in the interactive window station: Default, ScreenSaver, and Winlogon. )
I attached a EasyCode project that runs a program on another desktop named "RunSolo". (The desktop's name is also RunSolo).
CommandLine: RunSolo.exe Notepad.exe
Or: RunSolo.exe desk_b.exe
Greetings
btw: The sample was code from qWord, I did only add the WM_COPYDATA. It looks like qWord made a perfect sample and the assumption that i knew what to do with it, ... Or he was testing me...
you could create a temporary file to pass info
Hi,
can you please recap what you want to do? Why do you want to use WM_COPYDATA?
To you message-only window: replace HWND_MESSAGE with zero -> this creates an invisible top most window, which can be enumerated.
Hi,
I'm @ my job now
Yes i want to use WM_COPYDATA. There was a problem with my program i could not find the window(EnumDesktopWindows, FindWIndowEx,...), BUT in your sample it works perfectly. So I was sure there was a 'bug' in my program.
I was still able to solve this problem this night but i am not sure about the reason. I ignored to call UpdateWindow after CreateWindow and it is possible that EnumDesktopWindows could not find the window due to this...
This evening i'll try with and without the call to UpdateWindow and see if this was the reason,...
What i want to do is
1) find a way to close the program on the new desktop This is OK now
2) load dll's in my program(from a config file) and pass them a "Interface" so they can make calls into my program but also make calls into the other instance of the program. ( by using WM_COPYDATA) Now i can concentrate on this
You all was of great help already.
I have no problem with showing/sharing my project, even i use a (good EasyCode) IDE. But it's a bit overhead to post the project for every single 'problem'.
Quote from: qWord on September 25, 2012, 08:40:43 PM
To you message-only window: replace HWND_MESSAGE with zero -> this creates an invisible top most window, which can be enumerated.
Yes, the problem is indeed the HWND_MESSAGE argument for hWndParent... (And not UpdateWindow).
Double thanks. :t
MasmBasic looks awesome, but i'll first learn how to walk before i'll run...
Hi,
Amazed by the fact that SendMessage only works after EnumDesktopWindows and not before... :icon_eek: I've tried the with commandline arguments yesterday but that didn't work. Now I made a test and it's strange to see it doesn't work before but does work after EnumDesktopWindows...
;....
.Data
ghWndApp1 DD 0
.Code
EnumDeskWinProc Proc Private hWnd:HWND, lParam:LPARAM
Mov Eax, hWnd
.If Eax == lParam
Mov ghWndApp1, Eax
Xor Eax, Eax
.Else
Mov Eax, TRUE
.EndIf
Ret
EnumDeskWinProc EndP
; ....
Invoke SendMessage, hWndApp1, WM_APP + 1, 0, 0
Invoke EnumDesktopWindows, hDesk, EnumDeskWinProc, hWndApp1
.If ghWndApp1
Invoke SendMessage, ghWndApp1, WM_APP + 2, 0, 0
; ....
masm qeditor code attached...
I get "insufficient memory" for CreateDesktop on WinXP SP3 Home...
Now I tried again and wow, it works!
Hi,
Yep, I had a error the first time too. Strange, i don't have this with the other desktop tests i tried(in EasyCode).
And do you also only get WM_APP+2 ? Or both WM_APP+1 and WM_APP+2? I only get WM_APP+2 (on vista).
I get both WM_APP+1 and WM_APP+2.
:dazzled:
Maybe something vista vs xp,... I'll go and try on 7...
Update : Win7 i only get WM_APP+2.
The 0xC0000142 'bug' when starting the second process i had all the time on Win7. This was due to Closing the process handle immediately after creating the process,... No more problem when using Sleep. (exactly what i'm going to do now,..)
.If rvx(hProcess=DoCreateProcess, Addr szTemp1)
Invoke Sleep, 1000
Invoke CloseHandle, hProcess
According to the documentation (http://msdn.microsoft.com/en-us/library/windows/desktop/ms682573(v=vs.85).aspx), you generally can't send any message between desktops - It is even surprisingly that it works when using EnumDesktopWindows().
I think that you must create a separate thread, which then calls SetThreadDesktop(). From that thread it may be possible to send messages to the corresponding desktop.
Sadly the documentation is a bit weak about this (IMO).
Quote from: qWord on September 27, 2012, 10:42:32 AM
According to the documentation (http://msdn.microsoft.com/en-us/library/windows/desktop/ms682573(v=vs.85).aspx), you generally can't send any message between desktops - It is even surprisingly that it works when using EnumDesktopWindows().
......
Yep, i quoted that part from the msdn in my #6th post. So now we know that after after using EnumDesktopWindows, and not even in the callback, it does work, ...
On XP you can pass the hWnd by commandline(probably file etc) to an app running on another desktop and that app can use it to send messages.
On Vista and above it looks like it's only possible to send messages after EnumDesktopWindows.
Windows, sometimes, works in mysterious ways,... But it's fun to find limits , or break them,...
If it's a 'feature' unsupported according to the documentation the software can break one day when using it...
Quote from: qWord on September 27, 2012, 10:42:32 AM......
I think that you must create a separate thread, which then calls SetThreadDesktop(). From that thread it may be possible to send messages to the corresponding desktop.
Sadly the documentation is a bit weak about this (IMO).
I tried that a long time in the past, but not from a thread,... The msdn states that there can't be any hooks or windows in that thread,... But it's for the intention i had a bit overhead to create a thread for every message... (because the "program is dynamic" future messages are unknown)
Anyway i'm just doing this for fun, (and learning)...
Quote from: qWord on September 27, 2012, 10:42:32 AMyou must create a separate thread, which then calls SetThreadDesktop(). From that thread it may be possible to send messages to the corresponding desktop.
It is definitely possible to send WM_COPYDATA from a console app, so the "no windows" obstacle can be overcome if both processes have a send-only submarine in the "other" desktop.
Whatever he will do it, the fun will begin when he recognize that it is dam hard (at least for Win7/Vista) to close/remove a desktop without rebooting or closing the curent session: Windows, AVs and other software may create processes for that desktop. Because they keep handles to the desktop, it required to find and kill them...
Hi,
My aim was to make a program that runs software on a second desktop and disables the current user from switching back(without password). And i thought maybe one day i'll want to put extra features in that program so wanted to load dll's and make them communicate. (It's one instance running 2 times)...
I did my homework :) and some reading before starting. Went thru some codeproject articles and passed the bottlenecks you mention... I don't know if that desktop needs to be closed down, i don't think the software will ever be used , lol,...
The program keeps track of all handles for the processes it created , so it could call terminateprocess on them. And with enumdesktopwindows, getwindowprocessthreadid and terminateprocess it must be possible to kill most what's running on the second desktop,...
The current desktop is a field in a process it's PEB.RTL_USER_PROCESS_PARAMETERS. But that structure can vary between versions of windows(or updates). On ntinternals it's 'documented' as the 26'th field, but on vista it is the 31st field.
Assume Fs:Nothing
Mov Eax, Fs:[30H]
Mov Eax, [Eax + 10H]
Mov Eax, [Eax + 31 * 4]
Invoke MessageBoxW, NULL, Eax, Eax, MB_TOPMOST
Anyway, i have to draw the line somewhere of what i'll implement,...
I've found only one Method: run the program as administrator in the desktop to close, search for all handles using NtQuerySystemInformation() and finally kill the corresponding processes.
That PEB stuff sound interesting - you may give us feedback if you successfully implement that method.
BTW: Have you ever consider IPC using WinSock? – that would be a robust solution.
I believed to create it possible to fill DLL's in both procedures to create this system more powerful. And create a way for those dll's to connect. But i can keep this function of interaction behind and then the only need to connect is to quit the other procedure effectively.
Quote from: qWord on September 28, 2012, 06:03:19 AM
I've found only one Method: run the program as administrator in the desktop to close, search for all handles using NtQuerySystemInformation() and finally kill the corresponding processes.
That PEB stuff sound interesting - you may give us feedback if you successfully implement that method.
Hy, i've attached a the source for a program "GetProcessDesktopName" that displays each process it's desktop value from the PEB. It uses NtQueryInformationProcess/ReadProcessMemory to find the names of the desktop...
Anyway, it was not the intention to implement, your question to give feedback felth like a challenge to me...
Quote from: qWord on September 28, 2012, 06:03:19 AM
BTW: Have you ever consider IPC using WinSock? – that would be a robust solution.
Yes i did. But this would require some sort of protocol and for sending structures(binary data) it would need some kind of binary protocol(what is harder then text). So no, sockets , if needed can be implemented in the DLL, but sockets will not be implemented in the Host application...
I'll have a look at "NtQuerySystemInformation" now,...
The program looks confident :t
Unfortunately it didn't find the desktop for all processes (even with Admin rights).
In the attachment a simple console program, that enumerates all processes, which owns a handle of specified desktop.
Syntax:
Quoteenum_desktop_procs DesktopName
or
Quoteenum_desktop_procs DesktopName /a /c
Also there are option for killing the processes.
BTW: There are several macros which support Unicode:
- rvx/rvcx and fnx/fncx with L"my txt" or L'my txt'
- UCSTR/uc$(),...
... see hlhelp.chm
Hi,
:icon_eek: You are mad, in a good way... :biggrin: Your code is very learnfull to me
I'll come back later on this, first have to dig my way thru that project...
BTW, i guess the RBT lib is a kind of linked list api. Do you have some documentation on it,...? :)
Quote from: Vozzie on October 03, 2012, 07:21:50 AM
BTW, i guess the RBT lib is a kind of linked list api. Do you have some documentation on it,...? :)
RBT = Read-Black tree (http://en.wikipedia.org/wiki/Red%E2%80%93black_tree). There is no documentation - I think the definitions and the function names speak for them self :-D
(I currently can't find the C Code that I've used for translation, but it is all based on algorithms that can be found in the book "Introduction to Algorithms; MIT Press".)
Quote from: qWord on October 03, 2012, 05:12:27 AM
Unfortunately it didn't find the desktop for all processes (even with Admin rights).
I guess that desktop name is there only when the application has a window( or hook, ...) on the desktop. I still need to compare the results with your code, but have some questions there, only am trying to find out as much as i can before i start asking questions...
SystemHandleInformation etc isn't very documented in the msdn , are those documented in the "DDK/WDK"?
Quote from: qWord on October 03, 2012, 05:12:27 AMIn the attachment a simple console program, that enumerates all processes, which owns a handle of specified desktop.
Did you update the code? Something important?
Quote from: Vozzie on October 04, 2012, 01:49:13 AMDid you update the code? Something important?
Not important to the functionality of the program, but I've made some changes to rbt.lib. I've also add some comments in rbt.inc.
Also take a look at this page: HOWTO: Enumerate handles (http://forum.sysinternals.com/howto-enumerate-handles_topic18892.html)
Quote from: qWord on September 27, 2012, 04:45:21 PM
Whatever he will do it, the fun will begin when he recognize that it is dam hard (at least for Win7/Vista) to close/remove a desktop without rebooting or closing the curent session: Windows, AVs and other software may create processes for that desktop. Because they keep handles to the desktop, it required to find and kill them...
Just curious: Why should that be such a big problem? Normally, you don't create the desktop with the intention to close it soon after... just leave it running.
Quote from: jj2007 on October 04, 2012, 03:12:48 AMJust curious: Why should that be such a big problem? Normally, you don't create the desktop with the intention to close it soon after... just leave it running.
The problem is to remove it, when it is no longer needed ;)