Page 1 of 1

Embedding external applications within another application?

Posted: Thu May 22, 2008 8:20 pm
by dell_jockey
I have this software that does some OpenGL stuff in a fixed-size (borderless) window. It was NOT written in PB, however, I'd like to use PB to write an external program that:
- offers a control in which that external program is displayed/running/embedded
- through networking (most likely UDP based) offers the user a remote control to take influence in the actions of that external program.

The second part is not that difficult, as it is straight network programmng, which is supported by both languages.

But the BIG question is about this embedding thing. Is there a way to let an entire application be a sub-window within the application that calls it?

I know, not quite a trivial question, but perhaps someone here knows his way around the Win32 innards well enough....

bye
dell_jockey

Posted: Thu May 22, 2008 9:00 pm
by Thalius
Am not sure what you want to achieve.

However a communication ( atleast under windows ) is possible between two programs using WM Messages - probably easer than UDP if its only used local. Besides you could for example call that exe from PB and share handles, ressources ( shared-mem ) or whatever.

Thalius

Posted: Thu May 22, 2008 9:10 pm
by Mistrel
This is entirely possible but probably not in the way you're hoping for. What you'll need to do is run the two programs in parallel and communicate between the two using IPC.

To gain control over the other application you'll need to inject a DLL that will subclass the main window so you can communicate with it. Once you have communication established you should use shared memory and a mutex instead of window messages.

What you're asking for is complex but with a little effort it can be done.

See my post here:
http://www.purebasic.fr/english/viewtopic.php?t=30617

Posted: Thu May 22, 2008 9:22 pm
by Flype
about the gui embedding you can try something like this but i'm not sure that is what you want and this seems 'dangerous' depending on how is coded the embedded app.

but there's some bad repainting here, maybe someone can show how to repaint correctly. using callback/subclassing...

Code: Select all

#APPNAME1 = "Calculator"

Define *Parent
Define *Child

*Child = FindWindow_(0, #APPNAME1)
If Not *Child
  RunProgram("calc.exe") : Delay(1000)
  *Child = FindWindow_(0, #APPNAME1)
  If Not *Child
    MessageRequester("Error", #APPNAME1 + " must be running !")
    End
  EndIf
EndIf

*Parent = OpenWindow(0, 0, 0, 320, 240, "Master", #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_SizeGadget)

If *Parent
  
  SetWindowColor(0, $AAAAAA)
  
  CreateStatusBar(0, WindowID(0))
  
  SetParent_(*Child, WindowID(0))
  ;SetWindowLong_(*Child, #GWL_STYLE, GetWindowLong_(*Child, #GWL_STYLE)&~#WS_CLIPCHILDREN)
  SetWindowPos_(*Child, 0, 0, 0, 0, 0, #SWP_NOSIZE | #SWP_SHOWWINDOW)
  ;RedrawWindow_(*Child,0,0,0)
  
  Repeat
    
    Select WaitWindowEvent()
        
      Case #PB_Event_CloseWindow
        If IsWindow_(*Child)
          SetParent_(*Child, 0)
        EndIf
        CloseWindow(0)
        Break
        
      Case #PB_Event_Repaint
        RedrawWindow_(*Child, 0, 0, #RDW_INTERNALPAINT|#RDW_INVALIDATE)
        
    EndSelect
    
  ForEver
  
EndIf

End

Posted: Thu May 22, 2008 9:37 pm
by srod
You can't subclass a window from another process flype - not unless you take the route of a global hook as suggested by Mistrel.

However, to get your re-painting working better, use #WM_PAINT in a callback - it's far better than the PB event when moving the window etc. Also, a slight modification to the RedrawWinwdow_() flags is required.

Code: Select all

#APPNAME1 = "Calculator" 

Define *Parent 
Global *Child 


Procedure MyWindowCallback(hWnd, uMsg, wParam, lParam)
  result = #PB_ProcessPureBasicEvents
  Select uMsg
    Case #WM_PAINT
        RedrawWindow_(*Child, 0, 0, #RDW_INVALIDATE|#RDW_ERASE|#RDW_FRAME) 
  EndSelect
  ProcedureReturn Result
EndProcedure


*Child = FindWindow_(0, #APPNAME1) 
If Not *Child 
  RunProgram("calc.exe") : Delay(1000) 
  *Child = FindWindow_(0, #APPNAME1) 
  If Not *Child 
    MessageRequester("Error", #APPNAME1 + " must be running !") 
    End 
  EndIf 
EndIf 

*Parent = OpenWindow(0, 0, 0, 320, 240, "Master", #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_SizeGadget) 

If *Parent 
  
  SetWindowColor(0, $AAAAAA) 
  
  CreateStatusBar(0, WindowID(0)) 
  
  SetParent_(*Child, WindowID(0)) 
  SetWindowPos_(*Child, 0, 0, 0, 0, 0, #SWP_NOSIZE | #SWP_SHOWWINDOW) 
  SetWindowCallback(@MyWindowCallback())
  
  Repeat 
    
    Select WaitWindowEvent() 
        
      Case #PB_Event_CloseWindow 
        If IsWindow_(*Child) 
          SetParent_(*Child, 0) 
        EndIf 
        CloseWindow(0) 
        Break 
    EndSelect 
    
  ForEver 
  
EndIf 

End

Posted: Thu May 22, 2008 10:22 pm
by dell_jockey
Stop it, you're way over my head here... :)

As to the communications: that I have covered.

It's the embedding of an external program that's giving me trouble. Perhaps I should use the kiosk system that was published elsewhere on this forum, although I'd rather have a tighter coupling between the main calling program and the other application that is being 'hosted' by the main program.

Srod & Flype: I ran both of your codes and the calculator was started allright, but the OpenWindow bit doesn't get displayed. The debugger isn't providing any additional information.

Thanks for responding!

Posted: Thu May 22, 2008 10:26 pm
by dell_jockey
Thalius wrote:Am not sure what you want to achieve.
You could descibe it as an main application that can host another application (or perhaps only hosts/displays the output of that other application). Part of the main app should function as a 'presentation frame' that shows the output of that other app.

clear as mud?

Posted: Thu May 22, 2008 11:03 pm
by Flype
and the childs apps are made by you (same conceptor as the main app) or by anybody else ?

Posted: Fri May 23, 2008 11:16 am
by dell_jockey
Flype wrote:and the childs apps are made by you (same conceptor as the main app) or by anybody else ?
both can happen, but either case, these apps will normally initialise a borderless window (either 800x600 or 1024x768 24/32bit graphics) and diplay their graphics there, much in the way full-screen games do.
I'm looking for a 'framework' in which to display/host such external applications.

Since these apps indeed open a borderless window (it's not full-screen graphics), one idea might be to use the kiosk-code mentioned before to start the external app, and somehow instruct that external application to start 'screen centered' and 'always on top'. This way, I could still have the hosting software active and still have the external app visible at all times. Within this setting I should rephrase my question: how to instruct an external program to initialise itself 'screen centered' and 'always on top'. Does this spark any new ideas?