2

I wish to know how to make another's application window be a parent to my wx window.

I know that it is possible because twain module does just that.

For instance, you can pass in pygame.display's handle and it will act as a parent of scanning dialog that will appear. You can give it a handle of your Tk() or wx.Frame() directly (but it will grab out only the handle number anyway).

Or you can pass in a handle of completely different application, notepad for example.

I would like to achieve this. So that my wx dialog or pop up window appear in Modal mode over another application.

You already deduced that I want to do it on MS Windows. Well, I'd like to do it cross-platform, but other platforms aren't so stupid to let anyone messing in other app's interface. Sure I think it is possible, but much harder. So, for now Windows only.

I guess for this I will need to emulate wx.Window or Frame or Panel or something based on a chosen window handle to pass it to my dialog. Or something like that.

Any ideas?

Dalen
  • 4,128
  • 1
  • 17
  • 35

2 Answers2

1

I did not resolve my problem. Fortunately for me, both applications, the client one, and the one that I wanted to be its parent, were mine, so I rewrote the parent one using wxPython and added necessary interface into it, i.e. created the new application. I was unwilling to do that at first, that's why I searched for a "parenting" solution.

However, In this 2 years I happen to stumble on some useful info about it:

  1. I found a factory function called something like _CreateWindowFromNativeWindow() or _CreateWindowFromHandle() or something like that. That was an internal function in wxPython but was callable from our code as far as I saw. But for the love of it I cannot find it again. I did not try it, so it is a tip only. Perhaps somebody can dig it out.

  2. I found the method wx.Window.AssociateHandle() This however is real and should work. We cannot create a wx.Window() without a parent, but wx.Frame() we can. So something like this:


f = wx.Frame(None)
f.AssociateHandle(hwnd)

should work. Now f should be linked to the native window of another app, if the hwnd is right and we have appropriate permissions, and we should be able to use it as a parent for other wx windows. Whomever tries it, please post a comment to let us know whether it works as expected.

There is always a ctypes solution if we know how to make wxWidgets realise that the OS changed a handle of the window. I don't because I stopped to look in that direction. Also, there is a solution of exposing undocumented method setHWND() of wxWidgets, which should exist according to some sources, by modifying the wxPython sources and building them.

Dalen
  • 4,128
  • 1
  • 17
  • 35
0

I will talk in wxWidgets (C/C++ library) terminology, so, for example, my "wxFrame" will turn into yours wx.Frame.

wxWindow class has a method SetId (http://docs.wxwidgets.org/3.1/classwx_window.html). So you may try to create wxWindow object (let's call it "ParrentWindow") with default constructor, find out id of some window of some external application, and pass this window id to SetId method of our "ParrentWindow" object.

Then you should try to use this object as a parent of some of your own windows (wxWindow, wxFrame, wxPannel, etc.): just pass our "ParrentWindow" to the new window object's constructor.

Maybe it will work.

But remember that (in modern versions of MS Windows OS) your app can be restricted to operate only with your own windows. And if that is the case than you will need to run your app under one of the administrators accounts.

UPD:

I've just looked into MSDN and yes: you can change parent of already existing (already built) window by using SetParent() win32 API function: https://msdn.microsoft.com/en-us/library/windows/desktop/ms633541(v=vs.85).aspx

So you may load User32.dll into your Python code and use this win32 Api directly (by using default ctypes module) or indirectly (by pywin32 module). Then you just need to get HWND of your child window and HWND of external parent window. And pass them into SetParent() win32 API function. But you should remember that using win32 API bypassing wxWindows code may lead (or may not) to inconsistency in an appropriate wxWindows objects.

KromviellBlack
  • 908
  • 6
  • 10
  • 2 problems here. 1. I am not allowed to create wx.Window() without parent, wx.Frame() I can. But - 2. Isn't wx.Frame.SetId() only localized ID for wx event manager? see wx.Frame.GetId()!=wx.Frame.GetHandle(). And there is no wx.Frame.SetHandle(). – Dalen Dec 02 '16 at 14:38
  • Oh, yeah, I just found that wxWidgets, at least new versio has a class wxNativeWindow, which does just what I need, but wxPython doesn't yet. I will have to emulate it somehow.n – Dalen Dec 02 '16 at 15:39
  • I've updated an answer with some additional info. PS: Last time I've worked with wxWidgets library and last time I've modified wxWidgets sources was, I think, in 2012 so currently it is hard to me to be more precise and more helpful about wxWidgets. Sry. – KromviellBlack Dec 02 '16 at 15:46
  • Thanks, that may work. I'll check it later. I saw special effects added to wx windows through ctypes on windows, e.g. implementation of a transparent window. So, this may actually work. I'll let you know when I try it. – Dalen Dec 02 '16 at 16:12
  • OK - it will be interesting to hear – KromviellBlack Dec 02 '16 at 20:29
  • Hi, it works and it doesn't work. Using user32.SetParent changes the parent as far as OS is concerned, but wx doesn't catch to the change. It still thinks that the parent is Desktop or whatever window was set to be before user32.SetParent. This causes some funny problems, including program freezes. Especially if the old parent window was destroyed and it cannot reference to it in any way. Do you happen to know where wx keeps info about window's parent handle? – Dalen Dec 19 '16 at 22:49
  • @Dalen currently I don't remember, but I'll try to look through xwWidgets' sources in a few days (or this weekend) – KromviellBlack Dec 21 '16 at 08:01
  • If you are so good to do this for me, take a look at wxNativeWindow() I mentioned, there will be something useful for sure! Thank you very much! – Dalen Dec 21 '16 at 19:53