The MASM Forum

General => The Campus => Topic started by: Vozzie on September 25, 2012, 07:12:29 AM

Title: IPC, WM_COPYDATA (IPC between desktops)
Post by: Vozzie on September 25, 2012, 07:12:29 AM
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
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: dedndave on September 25, 2012, 07:48:53 AM
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
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: jj2007 on September 25, 2012, 07:51:05 AM
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
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: dedndave on September 25, 2012, 08:08:24 AM
oh yah - then there is always the command line - lol
nice, Jochen   :t

a method i have used before and forgot all about   :lol:
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: Vozzie on September 25, 2012, 08:10:36 AM
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...
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: qWord on September 25, 2012, 10:02:12 AM
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.
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: Vozzie on September 25, 2012, 10:05:09 AM
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...
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: Vozzie on September 25, 2012, 10:21:23 AM
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
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: Vozzie on September 25, 2012, 12:56:39 PM
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
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: jj2007 on September 25, 2012, 01:01:30 PM
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
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: Vozzie on September 25, 2012, 01:12:27 PM
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...
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: dedndave on September 25, 2012, 07:01:07 PM
you could create a temporary file to pass info
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: qWord on September 25, 2012, 08:40:43 PM
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.
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: Vozzie on September 26, 2012, 01:24:34 AM
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'.
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: Vozzie on September 26, 2012, 01:48:17 AM
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...
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: Vozzie on September 27, 2012, 08:37:06 AM
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...
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: jj2007 on September 27, 2012, 09:08:26 AM
I get "insufficient memory" for CreateDesktop on WinXP SP3 Home...

Now I tried again and wow, it works!
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: Vozzie on September 27, 2012, 09:29:13 AM
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).



Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: jj2007 on September 27, 2012, 09:31:49 AM
I get both WM_APP+1 and WM_APP+2.
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: Vozzie on September 27, 2012, 09:33:10 AM
 :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
             

Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: 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().
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).
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: Vozzie on September 27, 2012, 11:15:58 AM
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)...
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: jj2007 on September 27, 2012, 03:11:21 PM
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.
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: 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...
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: Vozzie on September 28, 2012, 05:25:20 AM
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,...
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: 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.

BTW: Have you ever consider IPC using WinSock? – that would be a robust solution.
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: johnparker29 on September 30, 2012, 11:39:29 PM
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.
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: Vozzie on October 03, 2012, 02:18:59 AM
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,...
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: qWord on October 03, 2012, 05:12:27 AM
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
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: Vozzie on October 03, 2012, 07:21:50 AM
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,...? :)

Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: qWord on October 03, 2012, 07:37:12 AM
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".)
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: Vozzie on October 04, 2012, 01:49:13 AM
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?
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: qWord on October 04, 2012, 02:21:24 AM
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)
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: jj2007 on October 04, 2012, 03:12:48 AM
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.
Title: Re: IPC, WM_COPYDATA (IPC between desktops)
Post by: qWord on October 04, 2012, 03:25:57 AM
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 ;)