File: n_parent.sru
Size: 7017
Date: Thu, 14 Jul 2022 19:30:30 +0200
$PBExportHeader$n_parent.sru
forward
global type n_parent from nonvisualobject
end type
type process_information from structure within n_parent
end type
type startupinfo from structure within n_parent
end type
end forward

type process_information from structure
   longptr     hprocess
   longptr     hthread
   unsignedlong      dwprocessid
   unsignedlong      dwthreadid
end type

type startupinfo from structure
   unsignedlong      cb
   string      lpreserved
   string      lpdesktop
   string      lptitle
   unsignedlong      dwx
   unsignedlong      dwy
   unsignedlong      dwxsize
   unsignedlong      dwysize
   unsignedlong      dwxcountchars
   unsignedlong      dwycountchars
   unsignedlong      dwfillattribute
   unsignedlong      dwflags
   unsignedinteger      wshowwindow
   unsignedinteger      cbreserved2
   longptr     lpreserved2
   longptr     hstdinput
   longptr     hstdoutput
   longptr     hstderror
end type

global type n_parent from nonvisualobject autoinstantiate
end type

type prototypes
Subroutine SleepMS ( &
   ulong dwMilliseconds &
   ) Library "kernel32.dll" Alias For "Sleep"

Function longptr GetDesktopWindow ( &
   ) Library "user32.dll"

Function longptr GetWindow ( &
   longptr hWnd, &
   ulong uCmd &
   ) Library "user32.dll"

Function long GetWindowText ( &
   longptr hWnd, &
   Ref string lpString, &
   long nMaxCount &
   ) Library "user32.dll" Alias For "GetWindowTextW"

Function longptr GetWindowThreadProcessId ( &
   longptr hWnd, &
   Ref longptr lpdwProcessId &
   ) Library "user32.dll"

Function longptr SetParent ( &
   longptr hWndChild, &
   longptr hWndNewParent &
   ) Library "user32.dll"

Function boolean MoveWindow ( &
   longptr hWnd, &
   long xpos, &
   long ypos, &
   long nWidth, &
   long nHeight, &
   boolean bRepaint &
   ) Library "user32.dll"

Function boolean ShowWindow ( &
   longptr hWnd, &
   long nCmdShow &
   ) Library "user32.dll"

Function Longptr SetWindowLong( &
   longptr hWnd, &
   long nIndex, &
   ulong dwNewLong &
   ) Library "user32.dll" Alias For "SetWindowLongW"

Function boolean CreateProcess ( &
   string lpApplicationName, &
   Ref string lpCommandLine, &
   longptr lpProcessAttributes, &
   longptr lpThreadAttributes, &
   boolean bInheritHandles, &
   ulong dwCreationFlags, &
   longptr lpEnvironment, &
   string lpCurrentDirectory, &
   STARTUPINFO lpStartupInfo, &
   Ref PROCESS_INFORMATION lpProcessInformation &
   ) Library "kernel32.dll" Alias For "CreateProcessW"

Function Boolean CloseHandle ( &
   longptr hObject &
   ) Library "kernel32.dll"

end prototypes

type variables
Constant Long STARTF_USESHOWWINDOW  = 1
Constant Long CREATE_NEW_CONSOLE    = 16
Constant Long NORMAL_PRIORITY_CLASS = 32
Constant Long SW_HIDE      = 0
Constant Long SW_NORMAL    = 1
Constant Long GWL_STYLE    = -16
Constant ULong GW_HWNDNEXT = 2
Constant ULong GW_OWNER    = 4
Constant ULong GW_CHILD    = 5
Constant ULong WS_POPUP    = 2147483648
Constant ULong WM_SIZE     = 5
Constant ULong WM_CLOSE    = 16

Longptr il_hWnd
String is_commandline

end variables

forward prototypes
public subroutine of_resize (integer newwidth, integer newheight)
public subroutine of_close ()
public function string of_getwindowtext ()
public function boolean of_attach (window aw_parent, string as_commandline)
public function boolean of_attach (dragobject ado_parent, string as_commandline)
public function boolean of_attach (longptr al_hwnd, integer ai_width, integer ai_height, string as_commandline)
end prototypes

public subroutine of_resize (integer newwidth, integer newheight);// Resize the attached window

Long ll_width, ll_height

If il_hWnd > 0 Then
   ll_width  = UnitsToPixels(newwidth, XUnitsToPixels!)
   ll_height = UnitsToPixels(newheight, YUnitsToPixels!)
   MoveWindow(il_hWnd, 0, 0, ll_width, ll_height, True)
End If

end subroutine

public subroutine of_close ();// send the Close event

If il_hWnd > 0 Then
   Send(il_hWnd, WM_CLOSE, 0, 0)
   il_hWnd = 0
End If

end subroutine

public function string of_getwindowtext ();// Get the window text

String ls_wintext

ls_wintext = Space(255)

If GetWindowText(il_hWnd, ls_wintext, 255) = 0 Then
   ls_wintext = is_commandline
End If

Return ls_wintext

end function

public function boolean of_attach (window aw_parent, string as_commandline);// Run an external program and attach the window

Integer li_width, li_height
Longptr ll_hWnd

ll_hWnd   = Handle(aw_parent)
li_width  = aw_parent.WorkspaceWidth()
li_height = aw_parent.WorkspaceHeight()

Return of_Attach(ll_hWnd, li_width, li_height, as_commandline)

end function

public function boolean of_attach (dragobject ado_parent, string as_commandline);// Run an external program and attach the window

Integer li_width, li_height
Longptr ll_hWnd

ll_hWnd   = Handle(ado_parent)
li_width  = ado_parent.Width
li_height = ado_parent.Height

Return of_Attach(ll_hWnd, li_width, li_height, as_commandline)

end function

public function boolean of_attach (longptr al_hwnd, integer ai_width, integer ai_height, string as_commandline);// Run an external program and attach the window

Environment le_env
STARTUPINFO lstr_si
PROCESS_INFORMATION lstr_pi
Long ll_null, ll_loop
Longptr ll_hWnd, ll_hProcess, ll_hThread
ULong lul_CreationFlags
String ls_null

// can't run this twice
If il_hWnd > 0 Then Return False

GetEnvironment(le_env)

// initialize arguments
SetNull(ls_null)
If le_env.ProcessBitness = 64 Then
   lstr_si.cb = 104
Else
   lstr_si.cb = 68
End If
lstr_si.dwFlags = STARTF_USESHOWWINDOW
lstr_si.wShowWindow = SW_HIDE
lul_CreationFlags = CREATE_NEW_CONSOLE + NORMAL_PRIORITY_CLASS

// run the external program
If CreateProcess(ls_null, as_commandline, ll_null, &
         ll_null, False, lul_CreationFlags, ll_null, &
         ls_null, lstr_si, lstr_pi) Then
   // close process and thread handles
   CloseHandle(lstr_pi.hProcess)
   CloseHandle(lstr_pi.hThread)

   // find the external program's main window
   for ll_loop = 1 To 100
      // wait 10 milliseconds
      SleepMS(10)
      // walk through all open windows
      ll_hWnd = GetWindow(GetDesktopWindow(), GW_CHILD)
      do until ll_hWnd = 0
         // get the thread/process that owns the window
         ll_hThread = GetWindowThreadProcessId(ll_hWnd, ll_hProcess)
         If ll_hProcess = lstr_pi.dwProcessId Then
            // make sure it is a main window
            If GetWindow(ll_hWnd, GW_OWNER) = 0 Then
               il_hWnd = ll_hWnd
               is_commandline = as_commandline
               SetParent(il_hWnd, al_hWnd)
               SetWindowLong(il_hWnd, GWL_STYLE, WS_POPUP)
               ShowWindow(il_hWnd, SW_NORMAL)
               of_Resize(ai_width, ai_height)
               Return True
            End If
         End If
         ll_hWnd = GetWindow(ll_hWnd, GW_HWNDNEXT)
      loop
   next
   MessageBox("n_parent", "Failed to find window: " + as_commandline)
Else
   MessageBox("n_parent", "Create Process failed: " + as_commandline)
End If

Return False

end function

on n_parent.create
call super::create
TriggerEvent( this, "constructor" )
end on

on n_parent.destroy
TriggerEvent( this, "destructor" )
call super::destroy
end on