Wiki Home

Take Window


Namespace: WIN_COM_API
This is a useful function that let's VFP take "possession" of any window and make it seem to be integral inside VFP. I like to use this to place the HTML Help window inside the VFP window, particularly since in Win2k it is difficult to get the help window to come to the foreground if it is already open.
* Author.....: William GC Steinford
* Date.......: Oct 8, 2002
* Abstract...: Place Any window inside main VFP window 
FUNCTION TakeWindow
LPARAMETERS pcWindowTitle
LOCAL lnWHND, lnVFP, lnRes

DECLARE INTEGER FindWindow in win32api as apiFindWindow ;
  INTEGER nClass, STRING cName
  
lnWHND = apiFindWindow( 0, pcWindowTitle )

if lnWHND<0
  RETURN -1
endif

lnVFP = apiFindWindow( 0, _Screen.Caption )
if lnVFP<0
  RETURN -1
ENDIF

DECLARE INTEGER SetParent in Win32API as apiSetParent ;
  INTEGER hWndChild, INTEGER hWndNewParent   

lnRes = apiSetParent( lnWHND, lnVFP )
RETURN lnRes

wgcs : Here's my newer, more complicated and more capable Take Window (this makes some assumptions of the internal window organization of VFP that MAY change in the future, hence I'm leaving my simpler one above. VFP8 works with this one, though!):
PROCEDURE TakeWindow
* Author.....: William GC Steinford
* Date.......: Nov 6, 2002
* Abstract...: Place Any window inside any VFP window (main VFP window or DEFINE'd Window)
LPARAMETERS pcWindowTitle, pcParentWindow
LOCAL lnWHND, lnVFP, lnRes, lnCNT, lnWinCnt

DECLARE INTEGER FindWindow in win32api as apiFindWindow ;
  INTEGER nClass, STRING cName
DECLARE INTEGER FindWindowEx in win32api as apiFindWindowEx ;
  INTEGER nParent, INTEGER nChildAfter, ;
  INTEGER nClass, STRING cName

* First get the VFP window handle
lnVFP = apiFindWindow( 0, _Screen.Caption )
if lnVFP<=0
  RETURN -1
ENDIF
lnWinCnt = lnVFP

lnWHND = apiFindWindow( 0, pcWindowTitle )

* Not outside of VFP... if we have a parent window, check inside VFP
if lnWHND<=0 and vartype(pcParentWindow)='C' and not empty(pcParentWindow)
  lnWHND=apiFindWindowEx( lnVFP, 0, 0, pcWindowTitle ) && Look in VFP window
  if lnWHND=0 && Not in Main VFP window... This is the case if this window
              && was created by VFP
    && Container windows in VFP have no title
    lnCNT  = apiFindWindowEx( lnVFP, 0, 0, '' ) && Find in container window
    do while lnWHND=0 and lnCNT<>0
      lnWHND = apiFindWindowEx( lnCNT, 0, 0, pcWindowTitle ) && Look in container
      lnCNT  = apiFindWindowEx( lnVFP, lnCNT, 0, '' ) && Find next container window
    enddo
  endif
endif

if lnWHND<0
  RETURN -1
endif

* Find the Parent Window
if vartype(pcParentWindow)='C' and not empty(pcParentWindow)
  lnWinCNT=apiFindWindowEx( lnVFP, 0, 0, pcParentWindow ) && Look in container
  
  if lnWinCnt=0 && Not in Main VFP window... This is the case if this window
              && was created by VFP
    && Container windows in VFP have no title
    lnCNT  = apiFindWindowEx( lnVFP, 0, 0, '' ) && Find in container window
    do while lnWinCnt=0 and lnCNT<>0
      lnWinCnt = apiFindWindowEx( lnCNT, 0, 0, pcParentWindow ) && Look in container
      lnCNT  = apiFindWindowEx( lnVFP, lnCNT, 0, '' ) && Find next container window
    enddo
    if lnWinCNT<=0
      RETURN -1  && Couldnt find new parent window
    endif
  endif
else
  DEFINE WINDOW TakeWindowXoXoX TITLE "TakeWindowXoXoX" AT 0,0 Size 1,1
  * Find the last empty-caption window inside VFP... this is where
  *   VFP puts user windows (after the menubar and toolbars)
  lnWinCNT =0
  lnCNT  = apiFindWindowEx( lnVFP, 0, 0, '' ) && Find first container window
  DO WHILE lnCnt<>0 and lnWinCnt=0
    lnWinCNT = apiFindWindowEx( lnVFP, lnCNT, 0, 'TakeWindowXoXoX' ) && Find Marker Window
    lnCNT  = apiFindWindowEx( lnVFP, lnCNT, 0, '' ) && Find next container window
  ENDDO
  RELEASE WINDOW TakeWindowXoXoX
endif


DECLARE INTEGER SetParent in Win32API as apiSetParent ;
  INTEGER hWndChild, INTEGER hWndNewParent
     
if lnWinCnt<>0 && Use proper container window
  lnRes = apiSetParent( lnWHND, lnWinCnt )
else
  lnRes = apiSetParent( lnWHND, lnVFP )
endif
RETURN lnRes

This is really interesting, thanks! I wonder if one could use such an approach to nest VFP applications, and if so whether there are any gochas. That is a feature which was one of the "attractions" of the soon-to-be-extinct Active Documents. If this could accomplish the same thing, i.e. the nesting of an entire VFP application window (and process) within another VFP application, it could be a lot better than ActiveDocs, anyway. If the child app were a COM EXE, communication between these separate processes would be vastly cleaner and easier than could be achieved with ActiveDocs. And then, musing still further, there are the fascinating possibilities if such nesting can be done recursively to arbitrary depth (subject to ultimate memory restrictions, of course. And by the way, that is doable, albeit clumsily, via ActiveDocs.) Hmmm... This must be investigated further! - ?mda
From what I understand about the internal mechanism of Windows that makes this code possible, there is no small limit to the nesting depth of the windows... In fact, it shouldn't be limited to anything less than when windows are not nested: the availability of window handles should be the only limiting factor, and nesting the windows is no more resource-consuming than not nesting them.
My one concern is garbage collection: In my experiments so far, every window that I nest IS properly disposed of, and it's process terminated, when the window that it has been placed inside is disposed of. And, Yes, I have been able to nest one VFP application inside another! And I've nested Word inside VFP... and (using my newer version of Take Window, above) you can nest windows inside of windows inside of VFP... anyone want to test how deep before something complains? ;) - wgcs
See Also: Free Window
Contributors: wgcs
Category Code Samples Category Windows API
( Topic last updated: 2002.11.12 10:20:39 AM )