Active Template Library with Liberty BASIC

Embedding a Browser or ActiveX Control in a Liberty BASIC Window

May 1, 2006 - Alyce Alyce

Liberty BASIC is not able to do Component Object Model (COM) programming natively, which makes the use of ActiveX controls difficult. You can use the LB_DispHelper ActiveX tools provided by Dennis McKinney to make use of ActiveX and COM with Liberty BASIC. http://syberden.net/libertybelle/COM%20with%20Liberty%20BASIC.html

The Active Template Library (ATL) is a set of template-based C++ classes that simplify the programming of Component Object Model (COM) objects. It is part of the Windows Operating System. Liberty BASIC cannot easily make use of this complete library, but there is a simple way to use a small part of it. You can do this by adding generic control containment capability to any window, so that the window can host ActiveX controls.

Please notice that this method provides very limited usefulness. It allows you to embed certain controls, a browser, or an HTML document into a Liberty BASIC Window. Your program has little or no control over the usage of the embedded control. This method is best used to do simple things, like display an animated GIF in a program window, or call up an HTML or PDF help system.

ATL DLL
This method requires the opening of the ATL.DLL that is part of the Windows Operating System. You must then initialize the DLL. The initialization function does not return a value.
 Open "atl" For DLL As #atl 
CallDLL #atl, "AtlAxWinInit", Ret As void

Creating the Control
The control will be created with the CreateWindowExA API call, but to make that call, you first need the instance handle of the program window. Do this with GetWindowLongA in the following manner:
 CallDLL #user32, "GetWindowLongA", _ 
hWndContainer As ulong, _ 'handle of container window
_GWL_HINSTANCE As long, _ 'flag to get instance handle
hInst As ulong 'returns instance handle
You can now make the API call to CreateWindowExA, using any of the possible window styles and extended window styles. You must include the handle of the container window, as well as the instance handle of that window. You also need to specify the X,Y location for the control and its width and height. The important part of this call is the class name. You must use "AtlAxWin" as the class name. This class was registered when you made the call to AtlAxWinInit.
 style = _WS_CHILD + _WS_VISIBLE +_WS_VSCROLL 
CallDLL #user32, "CreateWindowExA", _
_WS_EX_STATICEDGE As long, _ 'extended type
"AtlAxWin" As ptr, _ 'class name
fileName$ As ptr, _ 'URL, or progID or CLSID
style As long, _ 'window style
0 As long, _ 'left x pos
0 As long, _ 'top y pos
cw As long, _ 'width
ch As long, _ 'height
hWndContainer As ulong, _ 'handle of container
100 As long, _ 'handle to menu or child window ID
hInst As ulong, _ 'parent instance handle
0 As long, _ 'window creation data
hATL As ulong 'handle of active template library control

Notice the fileName$ argument. This is very important. The argument must be a program's progID, CLSID, or a URL. If it does not resolve to a valid progID or CLSID, it is assumed to be a URL and the MSIE web browser control is loaded. Since Internet Explorer includes the functionality to display GIFs, JPEGs, PDF files, TXT files, DOC files, HTML files, etc., your program window can contain any of these file types. You can also browse to a website. If fileName$ is " http://www.libertybasic.com/ " the browser is loaded and it navigates to the Liberty BASIC website.

This fileName$ string can also be raw HTML (prefixed with "MSHTML:")

Microsoft tells us this:
"AtlAxWin" is the name of a window class that helps provide ATL's control hosting functionality. When you create an instance of this class, the window procedure will automatically use the control hosting API to create a host object associated with the window and load it with the control that you specify as the title of the window.

Destroying the Control
There is no need to destroy the control. When your program window is closed, all child windows are automatically destroyed. To create the most stable application, close the program window before closing the DLL.
 [quit] 
close #main
close #atl
end
If it is necessary to destroy the ATL control before the program ends, use the DestroyWindow API call, like this:
 CallDLL #user32, "DestroyWindow", _ 
hATL As ulong, _
r as boolean
Multiple ATL Controls
Microsoft tells us this: It is not possible to host more than one control in a single ATL host window. Each host window is designed to hold exactly one control at a time.

Using a Graphicbox as a Container
The example programs that follow use a graphicbox as the parent, or container, for the ATL control. This allows a program to have more than one ATL control on a window. It also allows you to use native Liberty BASIC commands to enable, disable, show and hide the ATL control, by sending those commands to the graphicbox.

Sizing the Graphicbox and ATL Control
If you want the graphicbox to fill the client area of your window, use the GetClientRect API call, as in the following examples. Use the coordinates that are placed into the Rect struct to set the size for the graphicbox. Use them also to create the ATL window.

If it is necessary to resize the graphicbox and ATL control, use the "locate" command for the graphicbox. Be sure to issue a "refresh" command to the window after locating the graphicbox. Use the MoveWindow API call to resize the ATL control. Examples of this technique are included in the demonstration programs that follow.

Using ATL with Raw HTML

 nomainwin 

WindowWidth=400
WindowHeight=300
UpperLeftX=1:UpperLeftY=1
menu #main, "&File","E&xit", [quit]

graphicbox #main.g, 0, 0, 100, 100

Open "Liberty Basic ATL Demo" For Window_nf As #main
#main "TrapClose [quit]"

Open "atl" For DLL As #atl
CallDLL #atl, "AtlAxWinInit", Ret As void

hWndViewer = hWnd(#main.g) 'Windows handle of graphicbox
hMain = hWnd(#main) 'Windows handle of main window

STRUCT Rect,_ 'struct for storing client area rectangle
leftX as long,_ 'upper left x
upperY as long,_ 'upper left y
rightX as long,_ 'lower right x
lowerY as long 'lower right y

calldll #user32,"GetClientRect",_
hMain as ulong,_ 'window handle
Rect as struct,_ 'name of struct
r as long 'return
cw = Rect.rightX.struct
ch = Rect.lowerY.struct

'resize graphicbox to fill client area of window
#main.g "locate 0 0 ";cw+2;" ";ch+2
#main "refresh"

CallDLL #user32, "GetWindowLongA", _
hWndViewer As ulong, _ 'handle of graphicbox
_GWL_HINSTANCE As long, _ 'flag to get instance handle
hInst As ulong 'returns instance handle of graphicbox

style = _WS_CHILD + _WS_VISIBLE +_WS_VSCROLL

'a minimal HTML document:
html$ = "MSHTML:<html><head></head><body>This is an HTML document!</body></html>"
CallDLL #user32, "CreateWindowExA", _
_WS_EX_STATICEDGE As long, _ 'extended type
"AtlAxWin" As ptr, _ 'class name
html$ As ptr, _ 'URL, or progID or CLSID
style As long, _ 'window style
0 As long, _ 'left x pos
0 As long, _ 'top y pos
cw As long, _ 'width
ch As long, _ 'height
hWndViewer As ulong, _ 'handle of parent = graphicbox
100 As long, _ 'handle to menu or child window ID
hInst As ulong, _ 'parent instance handle
0 As long, _ 'window creation data
hATL As ulong 'handle of active template library control
wait

[quit]
Close #main
close #atl 'close DLL after closing window
end

Using ATL with CLSID

 'MSCAL.Calendar.7 
nomainwin

WindowWidth=400
WindowHeight=300
UpperLeftX=1:UpperLeftY=1
menu #main, "&File","E&xit", [quit]

graphicbox #main.g, 0, 0, 100, 100

Open "Liberty Basic ATL Demo" For Window_nf As #main
#main "TrapClose [quit]"

Open "atl" For DLL As #atl
CallDLL #atl, "AtlAxWinInit", Ret As void

hWndViewer = hWnd(#main.g) 'Windows handle of graphicbox
hMain = hWnd(#main) 'Windows handle of main window

STRUCT Rect,_ 'struct for storing client area rectangle
leftX as long,_ 'upper left x
upperY as long,_ 'upper left y
rightX as long,_ 'lower right x
lowerY as long 'lower right y

calldll #user32,"GetClientRect",_
hMain as ulong,_ 'window handle
Rect as struct,_ 'name of struct
r as long 'return
cw = Rect.rightX.struct
ch = Rect.lowerY.struct

'resize graphicbox to fill client area of window
#main.g "locate 0 0 ";cw+2;" ";ch+2
#main "refresh"

CallDLL #user32, "GetWindowLongA", _
hWndViewer As ulong, _ 'handle of graphicbox
_GWL_HINSTANCE As long, _ 'flag to get instance handle
hInst As ulong 'returns instance handle of graphicbox

style = _WS_CHILD + _WS_VISIBLE +_WS_VSCROLL

CallDLL #user32, "CreateWindowExA", _
_WS_EX_STATICEDGE As long, _ 'extended type
"AtlAxWin" As ptr, _ 'class name
"MSCAL.Calendar.7" As ptr, _ 'URL, or progID or CLSID
style As long, _ 'window style
0 As long, _ 'left x pos
0 As long, _ 'top y pos
cw As long, _ 'width
ch As long, _ 'height
hWndViewer As ulong, _ 'handle of parent = graphicbox
100 As long, _ 'handle to menu or child window ID
hInst As ulong, _ 'parent instance handle
0 As long, _ 'window creation data
hATL As ulong 'handle of active template library control
wait

[quit]
Close #main
close #atl 'close DLL after closing window
end

Using ATL with progID

 'MSCAL.Calendar 
nomainwin

WindowWidth=400
WindowHeight=300
UpperLeftX=1:UpperLeftY=1
menu #main, "&File","E&xit", [quit]

graphicbox #main.g, 0, 0, 100, 100

Open "Liberty Basic ATL Demo" For Window_nf As #main
#main "TrapClose [quit]"

Open "atl" For DLL As #atl
CallDLL #atl, "AtlAxWinInit", Ret As void

hWndViewer = hWnd(#main.g) 'Windows handle of graphicbox
hMain = hWnd(#main) 'Windows handle of main window

STRUCT Rect,_ 'struct for storing client area rectangle
leftX as long,_ 'upper left x
upperY as long,_ 'upper left y
rightX as long,_ 'lower right x
lowerY as long 'lower right y

calldll #user32,"GetClientRect",_
hMain as ulong,_ 'window handle
Rect as struct,_ 'name of struct
r as long 'return
cw = Rect.rightX.struct
ch = Rect.lowerY.struct

'resize graphicbox to fill client area of window
#main.g "locate 0 0 ";cw+2;" ";ch+2
#main "refresh"

CallDLL #user32, "GetWindowLongA", _
hWndViewer As ulong, _ 'handle of graphicbox
_GWL_HINSTANCE As long, _ 'flag to get instance handle
hInst As ulong 'returns instance handle of graphicbox

style = _WS_CHILD + _WS_VISIBLE +_WS_VSCROLL

CallDLL #user32, "CreateWindowExA", _
_WS_EX_STATICEDGE As long, _ 'extended type
"AtlAxWin" As ptr, _ 'class name
"MSCAL.Calendar" As ptr, _ 'URL, or progID or CLSID
style As long, _ 'window style
0 As long, _ 'left x pos
0 As long, _ 'top y pos
cw As long, _ 'width
ch As long, _ 'height
hWndViewer As ulong, _ 'handle of parent = graphicbox
100 As long, _ 'handle to menu or child window ID
hInst As ulong, _ 'parent instance handle
0 As long, _ 'window creation data
hATL As ulong 'handle of active template library control
wait



[quit]
Close #main
close #atl 'close DLL after closing window
end

Using ATL to Embed a Browser

Two demos follow. The first is a minimal program that shows how to embed a web browser in a Liberty BASIC Window. The second demo shows how to use that embedded browser to display various types of files, and how to resize it as the user resizes the program window.
 'the minimal browser 

nomainwin

WindowWidth=DisplayWidth-100
WindowHeight=DisplayHeight-100
UpperLeftX=1:UpperLeftY=1
menu #main, "&File","E&xit", [quit]

graphicbox #main.g, 0, 0, 100, 100

Open "Liberty Basic Browser ATL Demo" For Window_nf As #main
#main "TrapClose [quit]"

Open "atl" For DLL As #atl
CallDLL #atl, "AtlAxWinInit", Ret As void

hWndViewer = hWnd(#main.g) 'Windows handle of graphicbox
hMain = hWnd(#main) 'Windows handle of main window

STRUCT Rect,_ 'struct for storing client area rectangle
leftX as long,_ 'upper left x
upperY as long,_ 'upper left y
rightX as long,_ 'lower right x
lowerY as long 'lower right y

calldll #user32,"GetClientRect",_
hMain as ulong,_ 'window handle
Rect as struct,_ 'name of struct
r as long 'return
cw = Rect.rightX.struct
ch = Rect.lowerY.struct

'resize graphicbox to fill client area of window
#main.g "locate 0 0 ";cw+2;" ";ch+2
#main "refresh"

CallDLL #user32, "GetWindowLongA", _
hWndViewer As ulong, _ 'handle of graphicbox
_GWL_HINSTANCE As long, _ 'flag to get instance handle
hInst As ulong 'returns instance handle of graphicbox

style = _WS_CHILD + _WS_VISIBLE +_WS_VSCROLL

url$ = "http://www.libertybasic.com/"
CallDLL #user32, "CreateWindowExA", _
_WS_EX_STATICEDGE As long, _ 'extended type
"AtlAxWin" As ptr, _ 'class name
url$ As ptr, _ 'URL, or progID or CLSID
style As long, _ 'window style
0 As long, _ 'left x pos
0 As long, _ 'top y pos
cw As long, _ 'width
ch As long, _ 'height
hWndViewer As ulong, _ 'handle of parent = graphicbox
100 As long, _ 'handle to menu or child window ID
hInst As ulong, _ 'parent instance handle
0 As long, _ 'window creation data
hATL As ulong 'handle of active template library control
wait

[quit]
Close #main
close #atl 'close DLL after closing window
end
The browser can be used to view various file types.
 nomainwin 
hATL = 0 'handle of ATL control
cw = 0 'client area width
ch = 0 'client area height

STRUCT Rect,_ 'struct for storing client area rectangle
leftX as long,_ 'upper left x
upperY as long,_ 'upper left y
rightX as long,_ 'lower right x
lowerY as long 'lower right y

WindowWidth=DisplayWidth-200 : UpperLeftX=1
WindowHeight=DisplayHeight-200 : UpperLeftY=1

menu #main, "&File","&Open ATL",[openFile],"Open &URL", [openURL], _
"&Close ATL", [closeATL], |, "E&xit", [quit]
menu #main, "&Options", "&Enable", [EnableMe], "&Disable", [DisableMe],_
"&Show", [ShowMe], "&Hide", [HideMe]

graphicbox #main.g, 0, 0, 100, 100
Open "ATL Demo" For Window As #main
#main "TrapClose [quit]"
#main "resizehandler [resizeMe]"

Open "atl" For DLL As #atl
CallDLL #atl, "AtlAxWinInit", Ret As void

hBox = hWnd(#main.g) 'Windows handle of graphicbox
hMain = hWnd(#main) 'Windows handle of main window

CallDLL #user32, "GetWindowLongA", _
hBox As ulong, _ 'handle of graphicbox
_GWL_HINSTANCE As long, _ 'flag to get instance handle
hInst As ulong 'returns instance handle of graphicbox

calldll #user32,"GetClientRect",_
hMain as ulong,_ 'window handle
Rect as struct,_ 'name of struct
r as long 'return
cw = Rect.rightX.struct
ch = Rect.lowerY.struct
gosub [doResize]
WAIT

[quit] 'quit from menu, or user closes window
close #main
close #atl 'close DLL after closing window
end

[resizeMe] 'activated when user resizes window
cw = WindowWidth 'LB puts client width into WindowWidth
ch = WindowHeight 'LB puts client heigt into WindowHeight
gosub [doResize]
wait

[doResize] 'expects client width and height to be in cw, ch
'resize graphicbox to fill client area of window
#main.g "locate 0 0 ";cw+2;" ";ch+2
#main "refresh"
if hATL then 'resize active template control if it exists
calldll #user32, "MoveWindow",_
hATL as ulong, _ 'handle of ATL
0 as long, 0 as long, cw as long, ch as long,_
1 as long, result as boolean
end if
return

[openFile] 'ATL will use browser capability to open files of many types
filedialog "Open file", "*.txt;*.rtf;*.doc;*.pdf;*.jpg;*.gif;*.xls;*.html;*.htm", fileName$
if fileName$ = "" then wait
gosub [openATL]
wait

[openURL] 'if given a URL, ATL embeds a browser control
prompt "Type URL to website.";urlName$
if urlName$ = "" then wait
fileName$ = urlName$
gosub [openATL]
wait

[openATL] 'expects fileName$ to contain url or filename
if hATL then gosub [closeFile]
style = _WS_CHILD + _WS_VISIBLE +_WS_VSCROLL
CallDLL #user32, "CreateWindowExA", _
_WS_EX_STATICEDGE As long, _'extended type
"AtlAxWin" As ptr, _ 'class name
fileName$ As ptr, _ 'URL, or progID or CLSID
style As long, _ 'window style
0 As long, _ 'left x pos
0 As long, _ 'top y pos
cw As long, _ 'width
ch As long, _ 'height
hBox As ulong, _ 'handle of parent = graphicbox
100 As long, _ 'handle to menu or child window ID
hInst As ulong, _ 'parent instance handle
0 As long, _ 'window creation data
hATL As ulong 'handle of active template library control
return

[closeATL] 'user clicks menu to close file
if hATL then gosub [closeFile]
wait

[closeFile] 'destroy the atl child, nullify hATL variable
CallDLL #user32, "DestroyWindow", _
hATL As ulong, _
r as boolean
hATL = 0
return

[EnableMe] 'menu click to enable ATL
#main.g "enable"
wait

[DisableMe] 'menu click to disable ATL
#main.g "disable"
wait

[ShowMe] 'menu click to show ATL
#main.g "show"
wait

[HideMe] 'menu click to hide ATL
#main.g "hide"
wait