Form4.bas (For PowerBASIC For Windows Versions Before 10 - See Post #4 In This Thread For version 10)
The program below - Form4.bas - shows how to create a menu on a form or dialog using a resource file. Compile Tested with PB 8.03, CC4.03
Form4.rc Directions For Creating Menu For Form4.bas
An easy way to get a menu on a form/dialog is to create a resource file as seen below.
1) Open new file in PowerBASIC and paste the following:
#include "resource.h"
#define IDM_OPEN 1000
#define IDM_SAVE 1002
#define IDM_EXIT 1004
#define IDM_HELP 1006
#define IDM_ABOUT 1008
Form4 MENU
{
POPUP "&File"
{
MENUITEM "&Open...", IDM_OPEN
MENUITEM "&Save...", IDM_SAVE
MENUITEM SEPARATOR
MENUITEM "E&xit", IDM_EXIT
}
POPUP "&Help"
{
MENUITEM "&Help...", IDM_HELP
MENUITEM "&About Form6...", IDM_ABOUT
}
}
2) Save file as Form4.rc;
3) Compile within PBEdit by clicking little gear or Compile from menu. You'll quickly in succession be presented with two messages, the first informing you that Form4.res was successfully created, then that Form4.pbr was success fully created;
4) Copy Form4.bas to another PBEdit 'New' window, and save in same folder/directory as Form4.rc;
5) Compile and run Form4.bas. Note! You can use the Console Compiler but you must comment out all message boxes! (MsgBox() is a PBWin fn).
6) I've attempted to include the two necessary files in an attachment to this post.
'Form4.bas
#Compile Exe
#Include "Win32api.inc"
#Resource "Form4.pbr"
%IDM_OPEN = 1000 'These are known as equates and serve as 'proxy' identifiers for the objects/windows
%IDM_SAVE = 1002 'they are associated with. Note, for example, the nineth parameter in the Create
%IDM_EXIT = 1004 'Window Call below under WM_CREATE for the button control - hBtn=CreateWindow(...).
%IDM_HELP = 1006
%IDM_ABOUT = 1008
%IDC_BUTTON = 1010
Function WndProc(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Select Case As Long wMsg
Case %WM_CREATE 'The WM_CREATE message occurs once for each window. It is an ideal
Local hBtn As Dword 'place to create child windows of the main Form/Dialog of your program
Local hInst As Dword 'such as buttons, labels, text boxes, list boxes, combo boxes, etc.
hInst=GetWindowLong(hWnd,%GWL_HINSTANCE)
hBtn=CreateWindowEx _
( _
0, _ 'No Extended Window Styles
"button", _ 'We're creating a window of the predefined Window Class 'Button'.
"Command Button", _ 'This is the caption of the window (button caption).
%WS_CHILD Or %WS_VISIBLE, _ 'Its a 'child' of the main window and we want to see it.
85, _ 'x coordinate on main window of upper left corner of button.
40, _ 'y coordinate on main window of upper left corner of button.
140, _ 'button width
30, _ 'button height
hWnd, _ 'Parent of button (main window)
%IDC_BUTTON, _ 'Control identifier of button, that is, %IDC_BUTTON = 1010
hInst, _ 'Program instance handle
Byval 0 _ 'This is a very useful parameter but we're not using it here
)
Case %WM_COMMAND 'When you interact in any way with child windows on your
Select Case LoWrd(wParam) 'Form/Dialog, or the menu, WM_COMMAND messages are sent by
Case %IDM_OPEN 'Windows to the parent of the child windows. The particular
MsgBox("You Clicked File >> Open File!") 'control/child window sending the message can
'Print "You Clicked File >> Open File!" 'be differentiated through the Lowrd(wParam),
Case %IDM_SAVE 'as this number will be the control identifier
MsgBox("You Clicked File >> Save File!") 'associated with the control when it was
'Print "You Clicked File >> Save File!" 'created in the CreateWindow Call.
Case %IDM_EXIT
MsgBox("Send A Message To Windows To Close The Application.")
'Print "Send A Message To Windows To Close The Application."
Call SendMessage(hWnd,%WM_CLOSE,0,0)
Case %IDM_HELP
MsgBox("You Clicked Help >> Help!")
'Print "You Clicked Help >> Help!"
Case %IDM_ABOUT
MsgBox("You Clicked Help >> About...")
'Print "You Clicked Help >> About..."
Case %IDC_BUTTON
MsgBox("You Clicked The Command Button!")
'Print "You Clicked The Command Button!"
End Select
WndProc=0
Exit Function
Case %WM_CLOSE
If MsgBox("Do You Wish To Exit This Program?", %MB_YESNO, "MsgBox() Function Demo") = %IDYES Then
Call DestroyWindow(hWnd)
End If 'Note the two ways that this program can receive a WM_CLOSE
WndProc=0 'message. The first way is if you click the 'x' close button
Exit Function 'in the program's title bar. Windows will automatically send
Case %WM_DESTROY 'this message in that case. But we 'manually' SendMessage()
Call PostQuitMessage(0) 'a WM_CLOSE in the Case above under IDM_EXIT from the Exit
WndProc=0 'menu.
Exit Function
End Select 'Another very important point to grasp that is
'somewhat subtle is that when we handle a message
WndProc=DefWindowProc(hWnd,wMsg,wParam,lParam) 'we do an Exit Function. If we don't handle a
End Function 'message DefWindowProc() gets called!
Function WinMain(ByVal hIns As Long, ByVal hPrev As Long,ByVal lpCL As Asciiz Ptr, ByVal Is As Long) As Long
Local winclass As WndClassEx
Local szAppName As Asciiz*8
Local hMainWnd As Dword
Local Msg As tagMsg
szAppName="Form4"
winclass.lpszClassName=VarPtr(szAppName) : winclass.lpfnWndProc=CodePtr(WndProc)
winclass.cbSize=SizeOf(winclass) : winclass.style=%CS_HREDRAW Or %CS_VREDRAW
winclass.cbClsExtra=0 : winclass.cbWndExtra=0
winclass.hInstance=hIns : winclass.hIcon=LoadIcon(%NULL,ByVal %IDI_APPLICATION)
winclass.hCursor=LoadCursor(%NULL, ByVal %IDC_ARROW) : winclass.hbrBackground=%COLOR_BTNFACE+1
winclass.lpszMenuName=VarPtr(szAppName) : winclass.hIconSm=LoadIcon(%NULL, ByVal %IDI_APPLICATION)
Call RegisterClassEx(winclass)
hMainWnd=CreateWindowEx(0,szAppName,"Form4",%WS_OVERLAPPEDWINDOW,350,400,325,225,0,0,hIns,ByVal 0)
ShowWindow hMainWnd,Is
UpdateWindow hMainWnd
While GetMessage(Msg,%NULL,0,0)
Call TranslateMessage(Msg)
Call DispatchMessage(Msg)
Wend
'
Function=msg.wParam
End Function
Excellent Fred - keep the SDK articles coming. We need to keep spreading the word that SDK is the way to go.
A couple of minor things for us to discuss:
- You use CreateWindowEx to create the main dialog/window, but then you used CreateWindow for the child button control. Maybe sticking with CreateWindowEx would be the better and less confusing choice especially for newbies.
- You use the CALL syntax for calling subs/functions. Do many people use that approach these days? Just curious for my own interest.
- You use hIns in the LoadIcon for the small icon rather than %Null.
winclass.hIconSm=LoadIcon(hIns, ByVal %IDI_APPLICATION
My mistake Paul. Thanks for catching that! I see it should be null if using default (small icon). I had it in the others too and changed it.
In terms of my use of 'Call', now that is REALLY a heavy matter! If I use call the syntax highlighting feature of most editors including yours turns the word blue and I like color. As much as I can get. Code kind of looks bland to me without color!
I DO need to try and stick to CreateWindowEx() because if for no other reason that would allow Console Compiler users who may be thinking of trying GUI to compile the programs successfully. For whatever reason the CC hangs up on CreateWindow(). I believe its a conditional define somewhere. I'll edit the post and test it with CC. I was meaning to do that yet.
I decided to make an edit to this as a result of the release of PowerBASIC For Windows Version 10. In version 10 a *.pbr file isn't created after creation of the *.res file from the *.rc file. Rather, the *.res file is directly linked into the exe by the compiler. Here is an updated version for PB Win 10. Note the Form4.rc file can remain the same.
'Form4.bas
#Compile Exe
#Include "Win32api.inc"
#Resource Res, "Form4.res"
%IDM_OPEN = 1000 'These are known as equates and serve as 'proxy' identifiers for the objects/windows
%IDM_SAVE = 1002 'they are associated with. Note, for example, the nineth parameter in the Create
%IDM_EXIT = 1004 'Window Call below under WM_CREATE for the button control - hBtn=CreateWindow(...).
%IDM_HELP = 1006
%IDM_ABOUT = 1008
%IDC_BUTTON = 1010
Function WndProc(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Select Case As Long wMsg
Case %WM_CREATE 'The WM_CREATE message occurs once for each window. It is an ideal
Local hBtn As Dword 'place to create child windows of the main Form/Dialog of your program
Local hInst As Dword 'such as buttons, labels, text boxes, list boxes, combo boxes, etc.
hInst=GetWindowLong(hWnd,%GWL_HINSTANCE)
hBtn=CreateWindowEx _
( _
0, _ 'No Extended Window Styles
"button", _ 'We're creating a window of the predefined Window Class 'Button'.
"Command Button", _ 'This is the caption of the window (button caption).
%WS_CHILD Or %WS_VISIBLE, _ 'Its a 'child' of the main window and we want to see it.
85, _ 'x coordinate on main window of upper left corner of button.
40, _ 'y coordinate on main window of upper left corner of button.
140, _ 'button width
30, _ 'button height
hWnd, _ 'Parent of button (main window)
%IDC_BUTTON, _ 'Control identifier of button, that is, %IDC_BUTTON = 1010
hInst, _ 'Program instance handle
Byval 0 _ 'This is a very useful parameter but we're not using it here
)
Case %WM_COMMAND 'When you interact in any way with child windows on your
Select Case LoWrd(wParam) 'Form/Dialog, or the menu, WM_COMMAND messages are sent by
Case %IDM_OPEN 'Windows to the parent of the child windows. The particular
MsgBox("You Clicked File >> Open File!") 'control/child window sending the message can
'Print "You Clicked File >> Open File!" 'be differentiated through the Lowrd(wParam),
Case %IDM_SAVE 'as this number will be the control identifier
MsgBox("You Clicked File >> Save File!") 'associated with the control when it was
'Print "You Clicked File >> Save File!" 'created in the CreateWindow Call.
Case %IDM_EXIT
MsgBox("Send A Message To Windows To Close The Application.")
'Print "Send A Message To Windows To Close The Application."
Call SendMessage(hWnd,%WM_CLOSE,0,0)
Case %IDM_HELP
MsgBox("You Clicked Help >> Help!")
'Print "You Clicked Help >> Help!"
Case %IDM_ABOUT
MsgBox("You Clicked Help >> About...")
'Print "You Clicked Help >> About..."
Case %IDC_BUTTON
MsgBox("You Clicked The Command Button!")
'Print "You Clicked The Command Button!"
End Select
WndProc=0
Exit Function
Case %WM_CLOSE
If MsgBox("Do You Wish To Exit This Program?", %MB_YESNO, "MsgBox() Function Demo") = %IDYES Then
Call DestroyWindow(hWnd)
End If 'Note the two ways that this program can receive a WM_CLOSE
WndProc=0 'message. The first way is if you click the 'x' close button
Exit Function 'in the program's title bar. Windows will automatically send
Case %WM_DESTROY 'this message in that case. But we 'manually' SendMessage()
Call PostQuitMessage(0) 'a WM_CLOSE in the Case above under IDM_EXIT from the Exit
WndProc=0 'menu.
Exit Function
End Select 'Another very important point to grasp that is
'somewhat subtle is that when we handle a message
WndProc=DefWindowProc(hWnd,wMsg,wParam,lParam) 'we do an Exit Function. If we don't handle a
End Function 'message DefWindowProc() gets called!
Function WinMain(ByVal hIns As Long, ByVal hPrev As Long,ByVal lpCL As Asciiz Ptr, ByVal Is As Long) As Long
Local winclass As WndClassEx
Local szAppName As Asciiz*8
Local hMainWnd As Dword
Local Msg As tagMsg
szAppName="Form4"
winclass.lpszClassName=VarPtr(szAppName) : winclass.lpfnWndProc=CodePtr(WndProc)
winclass.cbSize=SizeOf(winclass) : winclass.style=%CS_HREDRAW Or %CS_VREDRAW
winclass.cbClsExtra=0 : winclass.cbWndExtra=0
winclass.hInstance=hIns : winclass.hIcon=LoadIcon(%NULL,ByVal %IDI_APPLICATION)
winclass.hCursor=LoadCursor(%NULL, ByVal %IDC_ARROW) : winclass.hbrBackground=%COLOR_BTNFACE+1
winclass.lpszMenuName=VarPtr(szAppName) : winclass.hIconSm=LoadIcon(%NULL, ByVal %IDI_APPLICATION)
Call RegisterClassEx(winclass)
hMainWnd=CreateWindowEx(0,szAppName,"Form4",%WS_OVERLAPPEDWINDOW,350,400,325,225,0,0,hIns,ByVal 0)
ShowWindow hMainWnd,Is
UpdateWindow hMainWnd
While GetMessage(Msg,%NULL,0,0)
Call TranslateMessage(Msg)
Call DispatchMessage(Msg)
Wend
Function=msg.wParam
End Function