Author Topic: Fred's Tutorial #4: Windows API Tutorial: Basic Menu With Resource Script File  (Read 8696 times)

0 Members and 1 Guest are viewing this topic.

Offline Frederick J. Harris

  • Hero Member
  • *****
  • Posts: 914
  • User-Rate: +16/-0
    • Frederick J. Harris
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:

Code: [Select]
#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.

Code: [Select]
'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

« Last Edit: April 07, 2011, 10:07:50 PM by Frederick J. Harris »

Offline Paul Squires

  • Jr. Member
  • **
  • Posts: 90
  • User-Rate: +11/-5
    • PlanetSquires
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




Paul Squires
FireFly Visual Designer SQLitening Database System JellyFish Pro Editor
http://www.planetsquires.com

Offline Frederick J. Harris

  • Hero Member
  • *****
  • Posts: 914
  • User-Rate: +16/-0
    • Frederick J. Harris
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.

 

Offline Frederick J. Harris

  • Hero Member
  • *****
  • Posts: 914
  • User-Rate: +16/-0
    • Frederick J. Harris
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.

Code: [Select]
'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