Simple tutorial to create first Windows applications

Windows specific questions.
cl4551f13d
Posts: 5
Joined: Jun 01, 2020 1:22

Simple tutorial to create first Windows applications

Post by cl4551f13d »

Hi.

I have looked at some examples of simple applications for windows, I have compiled them, but although I come from VisualBasic 6, I have not been able to make my first program for Windows.

Can someone give me a link to a step-by-step tutorial?
Xusinboy Bekchanov
Posts: 782
Joined: Jul 26, 2018 18:28

Re: Simple tutorial to create first Windows applications

Post by Xusinboy Bekchanov »

There are many GUI libraries here:
https://freebasic.net/forum/viewtopic.php?f=17&t=28510

For a simple try this (Sorry, this is in Russian, found a quick search):

Code: Select all

#include "windows.bi"
#include "win\commctrl.bi"
Dim msg As MSG 'структурированная переменная MSG
Dim As WNDCLASSEX wc 'структурированная переменная WNDCLASSEX
Dim As String NameClass="MyClass" ' переменная имени класса
Dim As HINSTANCE Hinst=GetModuleHandle(0) ' хендл модуля
' функция класса
Function wndproc(hwnd As HWND, msg As UInteger,_
    wparam As WPARAM, lparam As LPARAM) As Integer
    Static As HWND edit1,edit2,edit3,edit4,button
    Select Case msg
        Case WM_CREATE
            edit1=CreateWindowEx(0,"edit","Простой Edit с горизонтальным автоскролом",WS_VISIBLE Or WS_CHILD Or ES_AUTOHSCROLL,10,10,130,20,hwnd,Cast(HMENU,1),0,0)
            edit2=CreateWindowEx(0,"edit","Ввод с клавиатуры только чисел",WS_VISIBLE Or ES_NUMBER Or WS_CHILD,10,40,230,20,hwnd,Cast(HMENU,2),0,0)
            edit3=CreateWindowEx(0,"edit","Пароль",WS_VISIBLE Or ES_PASSWORD Or WS_CHILD,10,70,80,20,hwnd,Cast(HMENU,3),0,0)
            edit4=CreateWindowEx(0,"edit","Многострочный Edit" ,WS_VISIBLE Or ES_MULTILINE Or ES_AUTOVSCROLL Or WS_CHILD,10,100,100,100,hwnd,Cast(HMENU,4),0,0)
            button=CreateWindowEx(0,"button","вставить текст" ,WS_VISIBLE  Or WS_CHILD,130,100,100,20,hwnd,Cast(HMENU,5),0,0)
        Case WM_COMMAND
            If LoWord(wparam)=3 Then
                Dim As ZString*256 text
                GetWindowText(Edit3,@text,256)
                SetWindowText(Edit4,@text)
            ElseIf LoWord(wparam)=5 Then
                Dim As ZString*256 text
                GetWindowText(Edit2,@text,256)
                SendMessage(Edit4,EM_REPLACESEL,1,Cast(Lparam,@text))
            EndIf
        Case WM_DESTROY
            PostQuitMessage(0)
    End Select
    Return DefWindowProc(hwnd,msg,wparam,lparam)
End Function
' Заполнение структуры WNDCLASSEX
With wc
    .cbSize=SizeOf(WNDCLASSEX)
    .style=CS_HREDRAW Or CS_VREDRAW
    .lpfnWndProc=@wndproc
    .hInstance=Hinst
    .hIcon=LoadIcon(0,IDI_QUESTION)
    .hCursor=LoadCursor(0,IDC_ARROW)
    .hbrBackground=Cast(HBRUSH,COLOR_WINDOW)
    .lpszClassName=StrPtr(NameClass)
    .hIconSm=.hIcon
End With
' Регистрация класса окна
If RegisterClassEx(@wc)=0 Then
    Print "Register error, press any key"
    Sleep
    End
EndIf
InitCommonControls
'Создание окна
CreateWindowEx(0,NameClass,"Главное окно",_
WS_VISIBLE Or WS_OVERLAPPEDWINDOW,10,10,300,300,0,0,Hinst,0)
' Цикл сообщений
While GetMessage(@msg,0,0,0)
    TranslateMessage(@msg)
    DispatchMessage(@msg)
Wend
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Simple tutorial to create first Windows applications

Post by BasicCoder2 »

jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Simple tutorial to create first Windows applications

Post by jj2007 »

A template with a menu, a WM_PAINT handler and an edit control. The last line starts the program

Code: Select all

#Include "windows.bi"	' JJ 18.4.2020
Dim Shared as Handle hEdit
Function WndProc(hWnd As HWND, msg As  UINT, wParam As WPARAM, lParam As LPARAM) As LRESULT
  Dim As RECT rc
  Dim As PAINTSTRUCT ps
  Dim As HANDLE PtDC
  Dim As HMENU hMenu, hPopup, hEsi
  Select Case msg
  Case WM_CREATE
	hMenu=CreateMenu()					' create the main menu
	hPopup=CreatePopupMenu()					' create a sub-menu
	AppendMenu(hMenu, MF_POPUP, hPopup, "&File")		' add it to the main menu
	AppendMenu(hPopup, MF_STRING, 101, "&Open") 		' one more main item
	hEsi=CreatePopupMenu()					' create a sub-menu
	AppendMenu(hEsi, MF_STRING, 121, "&sources")		' fill it
	AppendMenu(hEsi, MF_STRING, 122, "&includes")		' with various
	AppendMenu(hEsi, MF_STRING, 123, "&DLLs")			' options
	AppendMenu(hPopup, MF_POPUP, hEsi, "&Dir")		' and add it to the main menu as "Dir"
	AppendMenu(hPopup, MF_STRING, 102, "&Save") 		' one more main item
	AppendMenu(hPopup, MF_STRING, 103, "E&xit") 		' one more main item
	SetMenu(hWnd, hMenu)					' attach menu to main window
	hEdit=CreateWindowEx(WS_EX_CLIENTEDGE, "edit", "Hello, I am an edit control",_
	WS_CHILD Or WS_VISIBLE or ES_MULTILINE, 0, 0, 100, 100, hWnd, 100, 0, 0)
  Case WM_COMMAND
	Select Case wParam
 		Case 101: MessageBox(hWnd, "Open not implemented", 0, MB_OK)
 		Case 102: MessageBox(hWnd, "Save not implemented", 0, MB_OK)
 		Case 121: MessageBox(hWnd, "No *.bas files found", 0, MB_OK)
 		Case 122: MessageBox(hWnd, "No *.inc files found", 0, MB_OK)
 		Case 123: MessageBox(hWnd, "No *.dll files found", 0, MB_OK)
 		Case 103: SendMessage(hWnd, WM_CLOSE, 0, 0)
	End Select
  Case WM_PAINT
	PtDC=BeginPaint(hWnd, @ps)
	TextOut(PtDC, 3, 3, "TextOut in the WM_PAINT handler", 31)
	EndPaint(hWnd, @ps)
  Case WM_KEYDOWN
  	if wParam=VK_ESCAPE then SendMessage(hWnd, WM_CLOSE, 0, 0)
  Case WM_SIZE
	GetClientRect(hWnd, @rc)
	MoveWindow(hEdit, 3, 28, rc.right-6, rc.bottom-30, 0)
  Case WM_DESTROY
      PostQuitMessage(0)
  End Select
  return DefWindowProc(hwnd, msg, wParam, lParam)
End Function

Function WinMain(hInstance As HINSTANCE, hPrevInstance As HINSTANCE, lpCmdLine As LPSTR, nShowCmd As Integer) As Integer
  Dim As WNDCLASSEX wc
  Dim As MSG msg
  Dim As string classname="FbGui"
  Dim As HANDLE hIconLib, hDll
  type pCall as function (xy as any ptr) as long
  Dim As pCall pGetVersion
  type DLLVERSIONINFO
	cbSize as long
	dwMajorVersion as long
	dwMinorVersion as long
	dwBuildNumber as long
	dwPlatformID as long
  end type
  Dim As DLLVERSIONINFO dvi
  dvi.cbSize=sizeof(DLLVERSIONINFO)
  hIconLib=LoadLibrary("shell32")
  wc.hIcon = LoadIcon(hIconLib, 239)	' get the butterfly icon
  FreeLibrary(hIconLib)
  hDll=LoadLibrary("ComCtl32")
  pGetVersion=GetProcAddress(hDll, "DllGetVersion")
  pGetVersion(@dvi)
  if @dvi.dwMajorVersion then print "Using common controls version ";str(dvi.dwMajorVersion);".";str(dvi.dwMinorVersion)
  FreeLibrary(hDll)
  wc.cbSize = sizeof(WNDCLASSEX)
  wc.hbrBackground = COLOR_BTNFACE+1
  wc.hCursor = LoadCursor(0, IDC_ARROW)
  wc.hIconSm = wc.hIcon
  wc.hInstance = hInstance
  wc.lpfnWndProc = @WndProc
  wc.lpszClassName = StrPtr(classname)
  wc.style = CS_HREDRAW Or CS_VREDRAW
  RegisterClassEx(@wc)
  if CreateWindowEx(0, wc.lpszClassName, "Hello World",_
	WS_OVERLAPPEDWINDOW Or WS_VISIBLE, (GetSystemMetrics(SM_CXSCREEN) / 2) - 150,_
	(GetSystemMetrics(SM_CYSCREEN) / 2) - 150, 300, 300, 0, 0, hInstance, 0)=0 then
		    MessageBox(0, "Creating hMain failed miserably", 0, MB_OK)
		    return 0
  End If

  While GetMessage(@msg, 0, 0, 0)
      TranslateMessage(@msg)
      DispatchMessage(@msg)
  Wend

  return msg.wParam
End Function
WinMain(GetModuleHandle(NULL), NULL, COMMAND(), SW_NORMAL)
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Simple tutorial to create first Windows applications

Post by dodicat »

Really neat jj2007.
You packed a lot in there.
The warnings can be suppressed by doing things like
wc.hbrBackground = cast(HBRUSH__ PTR,(COLOR_BTNFACE+1))
and
wc.hIcon = LoadIcon(hIconLib, cptr(any ptr,239)) ' get the butterfly icon

etc
etc

(To conform to freebasic's windows.bi)
But I shall probably refer to your template now and then, thank you.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Simple tutorial to create first Windows applications

Post by jj2007 »

dodicat wrote:Really neat jj2007
Thanks, dodicat. I hesitate to apply the cast acrobatics because IMHO FB should deal better with the requirements of the Windows API - there is nothing worth a warning, it's all correct. Btw which common controls version do you see? I get 6.16, but that depends on the commandline including a resource file, and the manifest in that rc file.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Simple tutorial to create first Windows applications

Post by Tourist Trap »

jj2007 wrote:Btw which common controls version do you see? I get 6.16.
Just for info it's 5.82 here. Works fine whatever.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Simple tutorial to create first Windows applications

Post by jj2007 »

5.82 gives you ugly pre-XP look. Try to specify a manifest file in a resource file as follows:

Code: Select all

32512 ICON "SomeFile.ico"
1 24 "XpManifest.xml"
This is XpManifest.xml:

Code: Select all

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<description>MasmBasic</description>
<dependency>
	<dependentAssembly>
	<assemblyIdentity
		type="win32"
		name="Microsoft.Windows.Common-Controls"
		version="6.0.0.0"
		processorArchitecture="*"
		publicKeyToken="6595b64144ccf1df"
	/>
	</dependentAssembly>
</dependency>
</assembly>
Your batch file or commandline should contain something similar:

Code: Select all

set rcfile=
if exist rsrc.rc set rcfile=rsrc.rc
fbc.exe %options% %rcfile% %1 
Macq
Posts: 24
Joined: Feb 18, 2021 4:01
Location: Queensland, Australia

Re: Simple tutorial to create first Windows applications

Post by Macq »

I'm learning windows programming too, so I thought I'd post some code here in the hope that it may help someone.

This is from a book released in 1990 for windows 3.0. Old but still informative. It demonstrates the use of child windows.
Every time you click on a child window, its state is inverted.
Change the value of DIVISIONS for a ridiculous number of tiny windows.

Code: Select all

'
' checker3  from Programming Windows 3.0 (c) 1990 Charles Petzold
'
' Demonstrates child windows, childWndProc(), mouse use, line drawing
'
#include once "windows.bi"
#define DIVISIONS 8

const szAppName    = "Checker3"
const szChildClass = "Checker3_Child"
dim shared hInst as HINSTANCE ' global copy of hInstance from WinMain()

' This is just an empty declaration.  See below for the definition of this fuction
' Without this, WinMain() is not called automatically, and nothing happens...
Declare Function        WinMain     ( ByVal hInstance As HINSTANCE, _
                                      ByVal hPrevInstance As HINSTANCE, _
                                      szCmdLine As String, _
                                      ByVal iCmdShow As Integer ) As Integer
	End WinMain( GetModuleHandle( null ), null, Command, SW_NORMAL )

Function WndProc ( ByVal hw As HWND, _
                   ByVal message As UINT, _
                   ByVal wParam As WPARAM, _
                   ByVal lParam As LPARAM ) As LRESULT

    static hwndChild(DIVISIONS,DIVISIONS) as hwnd ' holds all the handles to all the child windows
    dim as short  cxBlock, cyBlock, x, y
    select case(message)
        case WM_CREATE
            for x = 0 to DIVISIONS-1 step 1
                for y = 0 to DIVISIONS-1 step 1
                    'hwndChild(x,y) = CreateWindow(szChildClass,Null,_ ' Compiler bug with handling comments after _
                    hwndChild(x,y) = CreateWindowEx(WS_EX_CLIENTEDGE,szChildClass,Null,_
                    WS_CHILDWINDOW OR WS_VISIBLE,_
                    0,0,0,0,_
                    hw,_
                    cptr(HMENU,(y shl 8) or x),_
                    hInst,_
                    0)
                next y
            next x
            exit function ' return (0)
        
        case WM_SIZE
            cxBlock = LoWord(lParam) / DIVISIONS 'width of parent window divided by number of child windows per line
            cyBlock = Hiword(lParam) / DIVISIONS 'height of parent window ...
            for x = 0 to DIVISIONS-1 step 1
                for y = 0 to DIVISIONS-1 step 1
                    MoveWindow(hwndChild(x,y),x*cxBlock,y*cyBlock,cxBlock,cyBlock,TRUE)
                next y
            next x
            exit function

        case WM_LBUTTONDOWN
            MessageBeep(0) ' Beep if we get a click in the display area of the main window.
            exit function  ' There may be a small area at the bottom that is not covered by children
            
        case WM_DESTROY
            PostQuitMessage(0)
            exit function
    end select
    ''
    '' The message doesn't concern us so we send it to the default handler and return the result
    '' You MUST call DefWindowProc() for all messages that your window proceedure does not process
    Function = DefWindowProc( hw, message, wParam, lParam )    
   
End Function ' exit WndProc() and return a value

function ChildWndProc ( ByVal hw As HWND, _
                   ByVal message As UINT, _
                   ByVal wParam As WPARAM, _
                   ByVal lParam As LPARAM ) As LRESULT
    dim as HDC hdc
    Dim as PAINTSTRUCT ps
    dim as RECT rect
    
    select case(message)
        case WM_CREATE
            if(rnd > 0.5) then SetWindowWord(hw,0,1) else  SetWindowWord(hw,0,0)' On/Off flag
            exit function ' return 0
        case WM_LBUTTONDOWN
            SetWindowWord(hw,0,1 xor GetWindowWord(hw,0))
            InvalidateRect(hw,null,false)
            exit function
        case WM_PAINT
            hdc = BeginPaint(hw,@ps)
            GetClientRect(hw,@rect)
            Rectangle(hdc,0,0,rect.right,rect.bottom) ' This paints the entire child-window with the default brush
            if(GetWindowWord(hw,0)) then: ' Draw an X in the child window on every odd numbered click
                SelectObject(hdc,GetStockObject(LTGRAY_BRUSH))
                Ellipse(hdc,0,0,rect.right,rect.bottom)
                MoveToEx(hdc,0,0,null)
                LineTo(hdc,rect.right,rect.bottom)
                MoveToEx(hdc,0,rect.bottom,null)
                LineTo(hdc,rect.right,0)
            :end if
            EndPaint(hw,@ps)
            exit function
    end select
    Function = DefWindowProc( hw, message, wParam, lParam )
end function

Function WinMain ( ByVal hInstance As HINSTANCE, _
                   ByVal hPrevInstance As HINSTANCE, _
                   szCmdLine As String, _
                   ByVal iCmdShow As Integer ) As Integer    

    Dim hWin As HWND
    Dim msg As MSG
    Dim wndclass As WNDCLASS    
    Dim As HANDLE hIconLib
    hInst = hInstance ' for use when creating child windows, in WndProc()
    hIconLib = LoadLibrary("shell32")
    randomize
    
    if(not hPrevInstance) then:
        with wndclass
            .Style              = CS_HREDRAW or CS_VREDRAW
            .lpfnWndProc        = @WndProc
            .cbClsExtra         = 0
            .cbWndExtra         = 0
            .hInstance          = hInstance
            .hIcon              = LoadIcon(hIconLib,cptr(any ptr,173)) ' 173-yellow star. 239-butterfly
            .hCursor            = LoadCursor( NULL, IDC_ARROW )
            .hbrBackground      = GetStockObject(LTGRAY_BRUSH)
            .lpszMenuName       = null
            .lpszClassName      = strptr(szAppName)
        end with
        RegisterClass(@wndclass)    ' register a class for the main window
        with wndclass
            .lpfnWndProc        = @ChildWndProc
            .cbWndExtra         = sizeof(word)
            .hIcon              = null ' Child windows have no Icon
            .lpszClassName      = strptr(szChildClass)
        end with
        RegisterClass(@wndclass)    ' register a class for the child windows
    :endif

    hWin = CreateWindow(szAppName,"Checker3 Mouse Hit-Test Demo",_
        WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,_
        NULL,NULL,hInstance,null)
    ShowWindow(hWin,iCmdShow )
    UpdateWindow(hWin)
  
     While( GetMessage( @msg, NULL, 0, 0 ) <> FALSE )    
        TranslateMessage( @msg )
        DispatchMessage( @msg )
    Wend
    ''
    '' Program has ended
    ''
    Function = msg.wParam

End Function
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Simple tutorial to create first Windows applications

Post by jj2007 »

Dear MacQ,
Unfortunately, your code fails for all 4 of my frequently used compiler options. Two don't compile, two fail at CreateWindow (btw we use CreateWindowEx nowadays, as shown above). In particular, it's a good idea to do some error checking, see last line:

Code: Select all

    hWin = CreateWindow(szAppName,"Checker3 Mouse Hit-Test Demo",_
        WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,_
        NULL,NULL,hInstance,null)
        if hWin=0 Then MessageBox(0, "bad luck", "CwEx:", MB_OK) : ExitProcess(1)
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Simple tutorial to create first Windows applications

Post by srvaldez »

@Macq
compiles and runs OK with -gen gas/gas64 but not with -gen gcc
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Simple tutorial to create first Windows applications

Post by jj2007 »

gcc version 8.1.0 (2018)
FreeBASIC Compiler - Version 1.07.1 (2019-09-27)
TmpFb.c:342:30: error: wrong type argument to bit-complement
if( (struct $11HINSTANCE__*)~HPREVINSTANCE$1 == (struct $11HINSTANCE__*)0u ) goto label$100;
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Simple tutorial to create first Windows applications

Post by dodicat »

line ~116
use
if( hPrevInstance=0) then:
bla
bla
(not hPrevInstance doesnt work in gcc).
You should be careful using not at any time.

OR
You should
if(not cint(hPrevInstance)) then:
bla
bla
If you must use not.(see the help file for not)
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Simple tutorial to create first Windows applications

Post by jj2007 »

dodicat wrote:line ~116
use
if( hPrevInstance=0) then:
That did the trick, plus
#define Unicode
#include once "windows.bi"
#define DIVISIONS 8

Apparently, Macq has a setting in his IDE that defines Unicode via the commandline (?) instead of doing it in the source.
Macq
Posts: 24
Joined: Feb 18, 2021 4:01
Location: Queensland, Australia

Re: Simple tutorial to create first Windows applications

Post by Macq »

Sorry guys. I didn't mean to create such a stir. I'm using WinFBE Version 2.1.8 (64-bit). I haven't changed any compiler options.

Thanks for the input about not using not.

If I
#define Unicode

then I get

.lpszClassName = Strptr(szAppName) <-- Warning: Suspicious pointer assignment

The executable sits in the background and doesn't open a window.
Post Reply