Dear all,
I would like to know if some of you have some tips and tricks about source code migration from PowerBASIC to FreeBASIC.
Now that we have a complete FireFly Visual Designer for both FreeBASIC 32 bits and 64 bits, I will try to convert my PowerBASIC projects to FreeBASIC.
Regards,
Jean-Pierre
Hi Jean-Pierre,
So far in my use of FreeBASIC, I have encountered a few differences that I would like to share:
(1) There is much stronger type checking needed in FreeBASIC. It is VERY close to "C" when you are using WinAPI functions. For example, in PowerBASIC you could almost always use a LONG or DWORD to represent a pointer variable. In FreeBASIC, you should cast (using the Cast function) your variables to the correct type as defined in the WinApi headers (eg. HANDLE, HWND, BITMAP, WNDPROC, HFONT, etc...). for the most part you can get away with still using INTEGER or UINTEGER but you will get a LOT of compiler warnings of pointer conversions.
(2) PowerBASIC has a richer set of built in string functions for manipulating all different kinds of strings.
(3) PowerBASIC currently has better support for COM and Unicode on Windows machines.
(3) FreeBASIC has built in functionality to Print directly to the console screen as your Windows GUI program is running. This is fantastic for debugging your program as it is running. You can easily disable that console window whenever you need to.
(4) In PowerBASIC you need to buy a whole separate compiler for console programs. In FreeBASIC, you get EXE (GUI and console), DLL, and static libraries all built into the one compiler and that compiler is free.
(5) FreeBASIC allows for dynamic strings in TYPE structures!
(6) "Classes" in FreeBASIC are built by extending TYPE structures. TYPE's in FreeBASIC are amazing. They are more like C++ because you use them for OOP.
(7) FreeBASIC can compile to ASM or C so that the backend GCC compiler can optimize the code for speed and size.
(8) FreeBASIC is now 64bit.
(9) FreeBASIC has a large number of converted header files available to interface to existing C libraries.
....must be more that I can not think of right now :-)
You will encounter frustration as you start to convert a program from PowerBASIC to FreeBASIC. That would be no different than any other conversion but if you get stuck then please ask questions here or over in the FB forum. If I don't know the answer then I will try to find it for you.
Paul, i plan to take a look at it, but what about #2? can at least some kind of "wrappers" be created to achieve the same functionality?
For me, it would be too hard to convert my firefly projects to Freebasic, my code relies heavily on pointers and inline assembly. do you think it would be possible to convert such code?
IMO, #5 would be a blessing in PowerBASIC.
Hi Elias, there are many source codes and libraries already available with the FB community that simulate most of the string functionalities and containers (hash, collection, linked lists, queues, etc) that exist in PB. It is just that in PB it is built into the compiler runtime, whereas in FB it is separate external libraries or include files. No big deal in my opinion. FB already has very flexible pointers and inline assembly.
FB help on their site not so nicely structured as here.
The 64bit compiler package lacks a lot of the .bi files.
I have been poking around on the site, saw the notice about the test builds but dont seem to find it.
Where do i get all their header files again?
Hi Peter,
I have links on my FireFly FreeBasic page to the latest test compilers: http://planetsquires.com/firefly_freebasic.html
They can be found at this link: http://sourceforge.net/projects/fbc/files/Test%20Builds/
Those test builds have all of the WinAPI headers.
The official 1.02 release will be very soon: http://www.freebasic.net/forum/viewtopic.php?f=17&t=23439
Got those thanks.
Both versions gives errors, so i cant get anything going yet, but i will give this a shot in a while again.
The studies has to come first now, but i am so darn curious. ???
Will let you know when i had a poke at it again.
I thought that I would give FreeBASIC a try by converting a small program written using FireFly and PowerBASIC. As expected there is some frustration in finding equivalents for the PowerBASIC language in FreeBASIC. It's a learning experience which slows me down but does not create any road blocks. All was going well until I worked on converting procedures I had written to read and write to an INI file. I wrote these procedures before I became aware of the INI procedures in FireFly for PowerBASIC. My procedure made use of the statement:
Line Input #F, Y -- where F is assigned using Freefile and Y is a string variable.
Trying to compile using the latest 32 bit version (1.02.0) of FreeBASIC results in a compile error which I cannot overcome. I checked the forums and others are encountering exactly the same error. See attached image.
I thought I might just go ahead and use the INI functions in FireFly but I found that these functions are not available in FireFly for FreeBASIC.
I suppose that this bug in FreeBASIC will be fixed in the near future so I can continue, but this raises a question in my mind about the reliability of FreeBASIC. How many other issues like this will I encounter with fundamental language constructs which I must depend on? Can I trust that the compiled code is correct?
I'm trying to keep an open mind but I am concerned about using this for major projects.
I find FreeBASIC to be remarkably bug free especially given the size and scope of the project. Of course there are issues here and there but nothing that would prevent me from creating 99% of all programs that I'd want to create. FB expands across several operating systems in both 32 and 64 bit. Not too bad for a free open source project.
That LINE INPUT problem emerged with the last set of Includes because dkl used different/newer C includes to convert using is automated fbfrog program (he wanted a common set of includes for both 32 and 64 bit). You probably already know the fix for the LINE INPUT problem: http://sourceforge.net/p/fbc/code/ci/a92ae2
The fundamental constructs of the language work perfectly well based on my experience.
I am trying to convert a FF-PB program to a FF-FB program.
The forms are Oke thanks to Paul's FireFly.
The syntax however is a bit different e.g.
FF_ComboBox_AddString HWND_FORM1_COMBO2, Using ( " ## ", X + 1) ' This works in PB but not in FB, the compiler gives:
Error 1: Argument count mismatch, found 'Using' in 'FF_ComboBox_AddString HWND_FORM1_COMBO2, Using( " ## ", X + 1)
and after that the program starts the exe that is in the release folder as if nothing happened.
FF_ComboBox_AddString HWND_FORM1_COMBO2, Str (X + 1) ' This works in FB, but I want it like above
1. What am I doing wrong?
2. Why does the program start although an Error occurs?
Hi Klaas,
Happy to hear that you are attempting to do a conversion. Hopefully you will not run into too many problems.
I believe that the USING statement in FB can only be used as part of the PRINT USING statement. I do not think that it can be used standalone. For your purposes, maybe the FORMAT statement would be more appropriate? http://www.freebasic.net/wiki/wikka.php?wakka=KeyPgFormat
Not sure why the program starts. It is quite possible that Firefly is running a previously created EXE. I will have to run some tests on this situation.
Hi Paul,
Thanks, it works this way:
FF_ComboBox_AddString HWND_FORM1_COMBO2, Format( X + 1, " ## ")
Next questions:
1.
When you customize a Combobox and you want to start each item with a blank like " 2010" then
in the executable in the first item the blank is always ignored also in the PB version.
The next items are oke.
2.
In FF-FB the Combobox folds out 20 items although it holds only 16 items.
In FF-PB the Combobox folds out only the 16 items it contains.
3.
How do I connect with a MYSQL-DataBase and where can I find the SQL_statements that can be used in FB.
In PB I use SQL Tools from Perfect Sync.
4.
How can I choose to what printer I want to send a print job.
I hope you can help me with these problems too.
Klaas
Hi Klaas,
1. Yes, I believe that I have been LTRIMing the data prior to saving it in the project files. I will put that in my bugtracker to be fixed.
2. Thanks for that report. I will put that in my bugtracker to be fixed.
3. There should be a fair amount of sample code on the FB site for interfacing with MySQL. The FB distribution comes with header files for MySQL. They are located in \inc\mysql. There is also an example program under \examples\database I did a search for MYSQL on the FB forum and got a lot of hits.
4. Maybe try code in this post: http://www.freebasic.net/forum/viewtopic.php?f=6&t=8285&hilit=printdlg
SQLTools is BSTR centric in its function calls. You might find it useful to write a PB DLL that calls SQLTools with wrapper functions that use ASCIIZ. I never understood why Eric Pearson never built that flexiblitiy into SQLTools.
Klaas,
Please try the new Firefly FB exe attached to this post. I am pretty sure that I have fixed your Issue #1. I have not been able to recreate issue #2 yet.
I have also fixed your earlier reported problem of the exe running after a failed compile.
Quote
FireFly3 - 3.74 (Not Yet Released) [ View Issues ]
==================================
- 0000903: [Bug] FB/PB: ComboBox/ListBox "Custom" property editor does not allow leading spaces for items being added (Paul Squires) - closed.
- 0000905: [Bug] FB/PB: After failed compile, FF is running a previously existing version of the project exe (Paul Squires) - closed.
- 0000902: [Change] FB: Removed % from %SW_SHOWNORMAL|%SW_SHOWMINIMIZED|%SW_SHOWMAXIMIZED in WindowState property (Paul Squires) - closed.
If you could test this new exe for me then that would be appreciated. I have not released it yet as a full update to the general community yet.
Paul,
902 and 905 are fixed.
903 is fixed for the leading spaces but when an item is changed and you click OK then after compiling nothing has changed.
I think the problem lies in the custom item list that does not change the item in FF
Quote from: Klaas Holland on April 15, 2015, 06:44:23 PM
903 is fixed for the leading spaces but when an item is changed and you click OK then after compiling nothing has changed.
I think the problem lies in the custom item list that does not change the item in FF
I have looked at this code and moved the flag that sets the code to "dirty". Hopefully you can test the new version of the exe when I post it again (I should be able to do that soon).
Quote
There is much stronger type checking needed in FreeBASIC. It is VERY close to "C" when you are using WinAPI functions. For example, in PowerBASIC you could almost always use a LONG or DWORD to represent a pointer variable. In FreeBASIC, you should cast (using the Cast function) your variables to the correct type as defined in the WinApi headers (eg. HANDLE, HWND, BITMAP, WNDPROC, HFONT, etc...). for the most part you can get away with still using INTEGER or UINTEGER but you will get a LOT of compiler warnings of pointer conversions.
This is what happens when C programmers try to program in BASIC. They have no idea of how BASIC works...
We can make FreeBasic PB-like when calling external functions just changing the declares. Instead of so many silly BYVAL something PTR, we could use BYREF, and instead of so many silly aliased types, we could use always the standard data types and, to switch from 32-bit to 64-bit, and vice versa, we just need to use longint and ulongint, or LONG_PTR and DWORD_PTR.
Handles are 4 bytes in 32-bit Windows and 8 bytes in 64-bit Windows).
HRESULT is always a LONG.
LPARAM is a longint, WPARAM an ulongint and LRESULT a longint.
I have made a test, changing several API declares, and now I don't need to use as many @ as before, and don't need to remember so many data types. I will also remove all the obsolete ansi stuff that is useless with the current Windows versions, that are fully unicode. I will keep some defines such HINSTANCE, WPARAM, LPARAM and LRESULT for compatibility with 64-bit.
#INCLUDE ONCE "windows.bi"
DECLARE FUNCTION WinMain (BYVAL hInstance AS HINSTANCE, _
BYVAL hPrevInstance AS HINSTANCE, _
BYVAL szCmdLine AS ZSTRING PTR, _
BYVAL iCmdShow AS INTEGER) AS INTEGER
END WinMain(GetModuleHandle(""), NULL, COMMAND(), SW_NORMAL)
' =====================================================================================
' Get the Windows version (based on code from Jose Roca)
' =====================================================================================
FUNCTION AfxGetWindowsVersion () AS SINGLE
DIM dwVersion AS INTEGER
DIM nMajorVer AS INTEGER
DIM nMinorVer AS INTEGER
dwVersion = GetVersion
nMajorVer = LOBYTE(LOWORD(dwVersion))
nMinorVer = HIBYTE(LOWORD(dwVersion))
FUNCTION = nMajorVer + (nMinorVer / 100)
END FUNCTION
' ========================================================================================
' ========================================================================================
' Scales an horizontal coordinate according the DPI (dots per pixel) being used by the application.
' ========================================================================================
FUNCTION AfxScaleX (BYVAL cx AS SINGLE) AS SINGLE
DIM hDC AS DWORD
hDC = GetDC(NULL)
FUNCTION = cx * (GetDeviceCaps(hDC, LOGPIXELSX) / 96)
ReleaseDC NULL, hDC
End Function
' ========================================================================================
' ========================================================================================
' Sets the current process as dots per inch (dpi) aware.
' Note SetProcessDPIAware is subject to a possible race condition if a DLL caches dpi
' settings during initialization. For this reason, it is recommended that dpi-aware be set
' through the application (.exe) manifest rather than by calling SetProcessDPIAware.
' ========================================================================================
FUNCTION AfxSetProcessDPIAware () AS LONG
DIM AS ANY PTR pLib = DyLibLoad("user32.dll")
IF pLib = 0 THEN EXIT FUNCTION
DIM pProc AS FUNCTION () AS LONG
pProc = DyLibSymbol(pLib, "SetProcessDPIAware")
IF pProc = 0 THEN EXIT FUNCTION
FUNCTION = pProc()
DyLibFree(pLib)
END FUNCTION
' ========================================================================================
' =====================================================================================
' Scales a vertical coordinate according the DPI (dots per pixel) being used by the application.
' =====================================================================================
Function AfxScaleY (BYVAL cy AS SINGLE) AS SINGLE
DIM hDC AS DWORD
hDC = GetDC(NULL)
FUNCTION = cy * (GetDeviceCaps(hDC, LOGPIXELSY) / 96)
ReleaseDC NULL, hDC
End Function
' =====================================================================================
' ========================================================================================
' Adjust the bounding rectangle of a window based on the desired size of the client area.
' ========================================================================================
SUB AfxSetClientSize (BYVAL hwnd AS DWORD, BYVAL nWidth AS LONG, BYVAL nHeight AS LONG)
DIM rc AS RECT
DIM rcTemp AS RECT
DIM hMenu AS DWORD
DIM dwStyle AS DWORD
DIM cx AS LONG
DIM cy AS LONG
' // Convert the client rectangle to a window rectangle.
' // The AdjustWindowRectEx function cannot take menu wrapping into account
' // because it doesn't know which menu we are using.
SetRect(rc, 0, 0, AfxScaleX(nWidth), AfxScaleY(nHeight))
hMenu = GetMenu(hwnd)
dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE)
AdjustWindowRectEx (rc, dwStyle, (hMenu <> NULL), GetWindowLongPtr(hwnd, GWL_EXSTYLE))
' // If there is a menu, we need to check how much wrapping occurs when we set
' // the window to the width specified by AdjustWindowRectEX and an infinite
' // amount of height. An infinite height allows us to see every single menu wrap.
IF hMenu <> null THEN
rcTemp = rc
rcTemp.Bottom = &H7FFF ' // "Infinite" height
SendMessage (hwnd, WM_NCCALCSIZE, 0, cast(LPARAM, @rcTemp))
' // Adjust our previous calculation to compensate for menu wrapping.
rc.Bottom = rc.Bottom + rcTemp.Top
END IF
' // The AdjustWindowRectEx function does not take the WS_VSCROLL or WS_HSCROLL
' // styles into account. To account for the scroll bars, we need to call the
' // GetSystemMetrics function with SM_CXVSCROLL or SM_CYHSCROLL.
IF (dwStyle AND WS_HSCROLL) = WS_HSCROLL THEN
rc.Bottom = rc.Bottom + GetSystemMetrics(SM_CYHSCROLL)
END IF
IF (dwStyle AND WS_VSCROLL) = WS_VSCROLL THEN
rc.Right = rc.Right + GetSystemMetrics(SM_CXVSCROLL)
END IF
cx = rc.Right - rc.Left
cy = rc.Bottom - rc.Top
SetWindowPos(hwnd, NULL, 0, 0, cx, cy, SWP_NOZORDER OR SWP_NOMOVE OR SWP_NOACTIVATE)
END SUB
' ========================================================================================
' ========================================================================================
' Window procedure
' ========================================================================================
FUNCTION WndProc (BYVAL hWnd AS DWORD, BYVAL uMsg AS DWORD, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT
FUNCTION = 0
SELECT CASE (uMsg)
CASE WM_CREATE
EXIT FUNCTION
CASE WM_PAINT
DIM rc AS RECT
DIM ps AS PAINTSTRUCT
DIM hDC AS DWORD
hDC = BeginPaint(hWnd, ps)
GetClientRect(hWnd, rc)
DrawText(hDC, _
"Hello, World!", _
-1, _
rc, _
DT_SINGLELINE or DT_CENTER or DT_VCENTER)
EndPaint(hWnd, ps)
EXIT FUNCTION
CASE WM_KEYDOWN
IF (LOBYTE(wParam) = 27) THEN
PostMessage(hWnd, WM_CLOSE, 0, 0)
END IF
CASE WM_DESTROY
PostQuitMessage(0)
EXIT FUNCTION
END SELECT
FUNCTION = DefWindowProc(hWnd, uMsg, wParam, lParam)
END FUNCTION
' ========================================================================================
' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS HINSTANCE, _
BYVAL hPrevInstance AS HINSTANCE, _
BYVAL szCmdLine AS ZSTRING PTR, _
BYVAL iCmdShow AS INTEGER) AS INTEGER
' // Set process DPI aware
AfxSetProcessDPIAware
DIM wcls AS WNDCLASS
DIM hWnd AS DWORD
DIM wszClassName AS WSTRING * 20 = "HelloWin"
FUNCTION = 0
WITH wcls
.style = CS_HREDRAW or CS_VREDRAW
.lpfnWndProc = @WndProc
.cbClsExtra = 0
.cbWndExtra = 0
.hInstance = hInstance
.hIcon = LoadIcon(NULL, IDI_APPLICATION)
.hCursor = LoadCursor(NULL, IDC_ARROW)
.hbrBackground = GetStockObject(WHITE_BRUSH)
.lpszMenuName = NULL
.lpszClassName = @wszClassName
END WITH
IF (RegisterClass(wcls) = FALSE) THEN
MessageBox(NULL, "Failed to register wcls", "Error", MB_ICONERROR)
EXIT FUNCTION
END IF
hWnd = CreateWindowEx(0, _
wszClassName, _
"The Hello Program", _
WS_OVERLAPPEDWINDOW, _
0, 0, 0, 0, _
NULL, NULL, _
hInstance, _
NULL)
IF hWnd = NULL THEN
MessageBox(NULL, "CreateWindowEx failed", "Error", MB_ICONERROR)
EXIT FUNCTION
END IF
AfxSetClientSize(hwnd, AfxScaleX(300), AfxScaleY(200))
ShowWindow(hWnd, iCmdShow)
UpdateWindow(hWnd)
DIM uMsg AS MSG
WHILE (GetMessage(uMsg, NULL, 0, 0) <> FALSE)
TranslateMessage(uMsg)
DispatchMessage(uMsg)
WEND
FUNCTION = uMsg.wParam
END FUNCTION
' ========================================================================================
The official declares have been written as if they were going to be used with a C compiler...
Apparently, my fate is to be always at odds with the official declares for any Basic compiler :)
Hi Jose! Great to see you stop by again and post code. The latest FB package uses a newly translated version of the MinGW C includes. That is what dkl used for the translation. To help automate the translations, dkl uses a program that he wrote called FBFROG. https://github.com/dkl/fbfrog
I have downloaded them tonight and, as I said, they are more suitable for programming in C-style that in Basic-style.
declare function GetMessageW(byval lpMsg as LPMSG, byval hWnd as HWND, byval wMsgFilterMin as UINT, byval wMsgFilterMax as UINT) as WINBOOL
declare function TranslateMessage(byval lpMsg as const MSG ptr) as WINBOOL
declare function DispatchMessageW(byval lpMsg as const MSG ptr) as LRESULT
WHILE (GetMessage(@wMsg, NULL, 0, 0) <> FALSE)
TranslateMessage(@wMsg)
DispatchMessage(@wMsg)
WEND
My translation:
DECLARE FUNCTION GetMessageW (BYREF lpMsg AS MSG, BYVAL hWnd AS DWORD, BYVAL wMsgFilterMin AS DWORD, BYVAL wMsgFilterMax AS DWORD) AS LONG
DECLARE FUNCTION TranslateMessage (BYREF lpMsg AS MSG) AS LONG
DECLARE FUNCTION DispatchMessageW (BYREF lpMsg AS MSG) AS LRESULT
WHILE (GetMessage(uMsg, NULL, 0, 0) <> FALSE)
TranslateMessage(uMsg)
DispatchMessage(uMsg)
WEND
Jose,
With having to use -gen gcc for 64bit I still am scratching my head on why dkl decided to make integers 64bit?? The only data type that changes from 32 -> 64 is pointers on windows.
Or am I missing something??
James
They have made the translations as literal as possible, but this means that aren't very Basic friendly.
int and long are 32-bit values both in 32-bit and 64-bit Windows.
LPARAM, WPARAM and LRESULT types change size to 8 bytes in Windows 64-bit.
Handles are 4 bytes in 32-bit and 8 bytes in 64-bit Windows.
HRESULT is a LONG both in 32-bit and 64-bit Windows.
SIZE_T and SSIZE_T change from 4 to 8 bytes.
size_t, time_t, ptrdiff_t and others from the C runtime change from 4 bytes to 8 bytes.
Whe setting the cbWndExtra member of the WNDCLASS structure, reserve 8 bytes for pointers, because all pointers are 8 bytes in 64-bit Windows.
To access window or class private data that contains pointers use:
GetClassLongPtr
GetWindowLongPtr
SetClassLongPtr
SetWindowLongPtr
instead of GetClassLong, GetWindowLong, SetClassLong and SetWindowLong.
Another difference is the alignment of structures, which is a pain in PB because Bob did choose the rules of VB instead of C. If FreeBasic follows the C rules, then there is not problem.
> Handles are 4 bytes in 32-bit and 8 bytes in 64-bit Windows.
Therefore, in my translation I have to change the hWnd parameter from DWORD to another type, but we can use a generic HANDLE instead of all these HBITMAP, HWND, HFONT, etc.
We can handle 32/64 bit compatibility with just a few defines for the types that change size from 32 to 64 bit, but to have hundreds of them is a nightmare.
I have these polymorphic types in my list:
HANDLE
WPARAM
LPARAM
LRESULT
LONG_PTR
DWORD_PTR
VOID_PTR
Quote from: James Fuller on April 19, 2015, 10:37:42 AM
Jose,
With having to use -gen gcc for 64bit I still am scratching my head on why dkl decided to make integers 64bit?? The only data type that changes from 32 -> 64 is pointers on windows.
Or am I missing something??
James
In C++, INT does not change size in 64-bit Window. It is a 32-bit value.
But in FreeBasic,
Integer is an standard data type, not an alias for INT, and they have decided to do it this way. Of course, this will lead to misunderstandings.
Use LONG instead of INTEGER.
This is my first test with FreeBasic 64-bit, changing the declares of the functions used to be more PB compatible. One or two polymorphic types would be enough for compatibility with 32-bit, but I will use half a dozen for clarity. I will also use only the unicode declares. In WinMain I have changed Integer to Long, since the C++ function uses int, that does not translate to 8 bytes in 64-bit Windows. The similirarity of names between Integer and int is going to cause trouble among FBer's.
#INCLUDE ONCE "windows.bi"
DECLARE FUNCTION WinMain (BYVAL hInstance AS HANDLE, _
BYVAL hPrevInstance AS HANDLE, _
BYVAL szCmdLine AS ZSTRING PTR, _
BYVAL nCmdShow AS LONG) AS LONG
END WinMain(GetModuleHandle(""), NULL, COMMAND(), SW_NORMAL)
' ========================================================================================
' Sets the current process as dots per inch (dpi) aware.
' Note SetProcessDPIAware is subject to a possible race condition if a DLL caches dpi
' settings during initialization. For this reason, it is recommended that dpi-aware be set
' through the application (.exe) manifest rather than by calling SetProcessDPIAware.
' ========================================================================================
FUNCTION AfxSetProcessDPIAware () AS LONG
DIM AS ANY PTR pLib = DyLibLoad("user32.dll")
IF pLib = 0 THEN EXIT FUNCTION
DIM pProc AS FUNCTION () AS LONG
pProc = DyLibSymbol(pLib, "SetProcessDPIAware")
IF pProc = 0 THEN EXIT FUNCTION
FUNCTION = pProc()
DyLibFree(pLib)
END FUNCTION
' ========================================================================================
' =====================================================================================
' Scales a vertical coordinate according the DPI (dots per pixel) being used by the application.
' =====================================================================================
Function AfxScaleY (BYVAL cy AS SINGLE) AS SINGLE
DIM hDC AS HANDLE
hDC = GetDC(NULL)
FUNCTION = cy * (GetDeviceCaps(hDC, LOGPIXELSY) / 96)
ReleaseDC NULL, hDC
End Function
' =====================================================================================
' ========================================================================================
' Scales an horizontal coordinate according the DPI (dots per pixel) being used by the application.
' ========================================================================================
FUNCTION AfxScaleX (BYVAL cx AS SINGLE) AS SINGLE
DIM hDC AS HANDLE
hDC = GetDC(NULL)
FUNCTION = cx * (GetDeviceCaps(hDC, LOGPIXELSX) / 96)
ReleaseDC NULL, hDC
End Function
' ========================================================================================
' ========================================================================================
' Adjusts the bounding rectangle of a window based on the desired size of the client area.
' ========================================================================================
SUB AfxSetClientSize (BYVAL hwnd AS HANDLE, BYVAL nWidth AS LONG, BYVAL nHeight AS LONG)
DIM rc AS RECT
DIM rcTemp AS RECT
DIM hMenu AS HANDLE
DIM dwStyle AS DWORD
DIM cx AS LONG
DIM cy AS LONG
' // Convert the client rectangle to a window rectangle.
' // The AdjustWindowRectEx function cannot take menu wrapping into account
' // because it doesn't know which menu we are using.
SetRect(rc, 0, 0, AfxScaleX(nWidth), AfxScaleY(nHeight))
hMenu = GetMenu(hwnd)
dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE)
AdjustWindowRectEx(rc, dwStyle, (hMenu <> NULL), GetWindowLongPtr(hwnd, GWL_EXSTYLE))
' // If there is a menu, we need to check how much wrapping occurs when we set
' // the window to the width specified by AdjustWindowRectEX and an infinite
' // amount of height. An infinite height allows us to see every single menu wrap.
IF hMenu <> NULL THEN
rcTemp = rc
rcTemp.Bottom = &H7FFF ' // "Infinite" height
SendMessage(hwnd, WM_NCCALCSIZE, 0, cast(LPARAM, @rcTemp))
' // Adjust our previous calculation to compensate for menu wrapping.
rc.Bottom = rc.Bottom + rcTemp.Top
END IF
' // The AdjustWindowRectEx function does not take the WS_VSCROLL or WS_HSCROLL
' // styles into account. To account for the scroll bars, we need to call the
' // GetSystemMetrics function with SM_CXVSCROLL or SM_CYHSCROLL.
IF (dwStyle AND WS_HSCROLL) = WS_HSCROLL THEN
rc.Bottom = rc.Bottom + GetSystemMetrics(SM_CYHSCROLL)
END IF
IF (dwStyle AND WS_VSCROLL) = WS_VSCROLL THEN
rc.Right = rc.Right + GetSystemMetrics(SM_CXVSCROLL)
END IF
cx = rc.Right - rc.Left
cy = rc.Bottom - rc.Top
SetWindowPos(hwnd, NULL, 0, 0, cx, cy, SWP_NOZORDER OR SWP_NOMOVE OR SWP_NOACTIVATE)
END SUB
' ========================================================================================
' ========================================================================================
' Window procedure
' ========================================================================================
FUNCTION WndProc (BYVAL hWnd AS HANDLE, BYVAL uMsg AS DWORD, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT
FUNCTION = 0
SELECT CASE (uMsg)
CASE WM_CREATE
EXIT FUNCTION
CASE WM_PAINT
DIM rc AS RECT, ps AS PAINTSTRUCT, hDC AS HANDLE
hDC = BeginPaint(hWnd, ps)
GetClientRect(hWnd, rc)
DrawText(hDC, "Hello, World!", -1, rc, DT_SINGLELINE or DT_CENTER or DT_VCENTER)
EndPaint(hWnd, ps)
EXIT FUNCTION
CASE WM_KEYDOWN
IF (LOBYTE(wParam) = 27) THEN PostMessage(hWnd, WM_CLOSE, 0, 0)
CASE WM_DESTROY
PostQuitMessage(0)
EXIT FUNCTION
END SELECT
FUNCTION = DefWindowProc(hWnd, uMsg, wParam, lParam)
END FUNCTION
' ========================================================================================
' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS HANDLE, _
BYVAL hPrevInstance AS HANDLE, _
BYVAL szCmdLine AS ZSTRING PTR, _
BYVAL nCmdShow AS LONG) AS LONG
' // Set process DPI aware
AfxSetProcessDPIAware
DIM wcls AS WNDCLASS
DIM hWnd AS HANDLE
DIM wszClassName AS WSTRING * 20 = "HelloWin"
FUNCTION = 0
WITH wcls
.style = CS_HREDRAW or CS_VREDRAW
.lpfnWndProc = @WndProc
.cbClsExtra = 0
.cbWndExtra = 0
.hInstance = hInstance
.hIcon = LoadIcon(NULL, IDI_APPLICATION)
.hCursor = LoadCursor(NULL, IDC_ARROW)
.hbrBackground = GetStockObject(WHITE_BRUSH)
.lpszMenuName = NULL
.lpszClassName = @wszClassName
END WITH
IF (RegisterClass(wcls) = FALSE) THEN
MessageBox(NULL, "Failed to register wcls", "Error", MB_ICONERROR)
EXIT FUNCTION
END IF
hWnd = CreateWindowEx(0, wszClassName, "The Hello Program", WS_OVERLAPPEDWINDOW, _
0, 0, 0, 0, NULL, NULL, hInstance, NULL)
IF hWnd = NULL THEN
MessageBox(null, "Failure in CreateWindowEx", "Error", MB_ICONERROR)
EXIT FUNCTION
END IF
AfxSetClientSize(hwnd, 500, 320)
ShowWindow(hWnd, nCmdShow)
UpdateWindow(hWnd)
DIM uMsg AS MSG
WHILE (GetMessage(uMsg, NULL, 0, 0) <> FALSE)
TranslateMessage(uMsg)
DispatchMessage(uMsg)
WEND
FUNCTION = uMsg.wParam
END FUNCTION
' ========================================================================================
The biggest show stopper for a Windows programmer like me is the lack of native support for OLE strings. Having to use SysAllocString and/or SysFreeString each time I need to use an OLE string is a real pain. You have always to use intermediate steps to get the pointer to the allocated string to free it later.
Since the authors seem to be C programmers mainly working with Linux, I don't blieve this is going to change anytime soon.
I imagine that eventually I will have to create a String class (much like the C++ string class) that will handle all of the string operations including allocation and deallocation, and dynamic bstr and/or fixed and unicode, etc....
If I remember correctly the native fb string has the same format as the PB ole string does it not?
James
Not at all. An ole string descriptor has a field for the length, followed by a pointer to the string data, whereas the FB string descriptor uses a pointer for the string data, followed by the length and the size of the allocated memory block. Besides, memory is allocated using malloc.
I assume they chose that method because there is no such thing as ole strings on Linux, Mac, etc. (basically, non-Windows systems)?
It's interesting to see FB as perhaps my "logical" move from PB. I'm not sure now is the right time. I'm heavily invested in Jose's includes, I use all the FF functions, I have my own custom objects, and, I'm all over the PB Powercollection group of objects. The port over now would be painful and perhaps less so in the future.
Rick Kelly
I'am not a Pro, therefore I need examples how things are done.
Who can help me with the conversion of my Sample Listview to the FB Sample Listview?
The picture is Oke and compiles fine, but now I'am stuck.
Klaas
Hi Klaas,
I took a very quick look at the generated source code and it looks like you have the "ResizeRules" set for the ListView in the FreeBASIC version. The code is generating "FL,FT,FR,FB" resize rules whereas the PB version is outputting nothing.
Hi Paul,
This line is failing in the AppStart, therefore the Format did not work.
#Include Once "string.bi" ' so we can have access to the Format function
Next question is how to point to the Listview Item and Listview Sub_Item and show the Editbox or ComboBox
'--------------------------------------------------------------------------------
Function FORMT1_CUSTOM ( _
hWndForm As HWnd, _ ' handle of Form
wMsg As Integer, _ ' type of message
wParam As WPARAM, _ ' first message parameter
lParam As LPARAM _ ' second message parameter
) As Integer
Dim pNmLvw As NM_LISTVIEW Ptr
Dim RectSub As Rect
Dim sText As String
Select Case wMsg
Case WM_NOTIFY ', WM_VSCROLL, WM_MOUSEWHEEL
Select Case wParam
Case IDC_FORMT1_LISTVIEW1
pNmLvw = lParam
If (@pNmLvw.hdr.Code = NM_CLICK) And (@pNmLvw.iItem > -1) Then 'Click in listview
gLvRow = @pNmLvw.iItem
gLvCol = @pNmLvw.iSubItem
If gLvCol = 1 Or gLvCol = 3 Then EditCell
If gLvCol = 2 Then ComboCell
' ElseIf (@pNmLvw.hdr.Code = NM_DBLCLK) And (@pNmLvw.iItem > -1) Then 'DoubleClick in listview
' gLvRow = @pNmLvw.iItem
' gLvCol = 2 '@pNmLvw.iSubItem
' ComboCell
End If
End Select
End Select
Function = 0 ' change according to your needs
End Function
'--------------------------------------------------------------------------------
Sub EditCell
'--------------------------------------------------------------------------------
Dim RectSub As Rect
Dim sText As String
FF_ListView_SetSelectedItem HWND_FORMT1_LISTVIEW1, gLvRow
ListView_EnsureVisible (HWND_FORMT1_LISTVIEW1, gLvRow, 0)
'get Rect of the Cell
ListView_GetSubItemRect (HWND_FORMT1_LISTVIEW1, gLvRow, gLvCol, LVIR_LABEL, RectSub)
FF_Control_SetLoc HWND_FORMT1_TEXT1, RectSub.nLeft , RectSub.nTop
FF_Control_SetSize HWND_FORMT1_TEXT1, RectSub.nRight - RectSub.nLeft , RectSub.nBottom + 3 - RectSub.nTop
'get Text from Listview to TextBox
FF_ListView_GetItemText HWND_FORMT1_LISTVIEW1, gLvRow, gLvCol To sText
FF_TextBox_SetText HWND_FORMT1_TEXT1, sText
FF_Control_ShowState HWND_FORMT1_TEXT1, SW_SHOW
FF_Control_SetFocus HWND_FORMT1_TEXT1
End Sub
'--------------------------------------------------------------------------------
Sub ComboCell
'--------------------------------------------------------------------------------
Dim RectSub As Rect
Dim Txt As String
Dim Ws As Long
FF_ListView_SetSelectedItem HWND_FORMT1_LISTVIEW1, gLvRow
ListView_EnsureVisible (HWND_FORMT1_LISTVIEW1, gLvRow, 0)
'ermitteln der Label des Subitem
ListView_GetSubItemRect HWND_FORMT1_LISTVIEW1, gLvRow, gLvCol, LVIR_LABEL, RectSub
FF_Control_SetLoc HWND_FORMT1_COMBO2, RectSub.nLeft, RectSub.nTop
FF_Control_SetSize HWND_FORMT1_COMBO2, RectSub.nRight - RectSub.nLeft , RectSub.nBottom - RectSub.nTop
'get Text from Listview to ComboBox
FF_ListView_GetItemText HWND_FORMT1_LISTVIEW1, gLvRow, gLvCol To Txt
FF_ComboBox_FindString HWND_FORMT1_COMBO2, 1, Txt To Ws
FF_ComboBox_SetCurSel HWND_FORMT1_COMBO2, Ws
FF_Control_ShowState HWND_FORMT1_COMBO2, SW_SHOW
FF_Control_SetFocus HWND_FORMT1_COMBO2
End Sub
Klaas
Paul, I don't know how you can handle it all for free - but great job on the FF3FB. If you put more into in the upcoming months - don't hesitate to charge me. I'm totally funded. I'm one of those willing to pay for great software.
I'm currently staying with PBWin10, (both versions of FF) for the moment. With that said;
However, for those of you who really want to move on, Visual Studio Express 2013 for VB, C# and C++ is free also - up to 5 Users for commercial software. I recommend getting your IIS working correct before installing.
1) Visual Studio Desktop (install this 1st)
2) Visual Studio Web (install this 2nd)
https://www.visualstudio.com/en-us/products/visual-studio-express-vs.aspx
(note: it's a confusing website - but make sure you download the ISO's - not the online install)
These are huge files - 6.5GB ISO.
Net isn't going away - so I'm just stating that fact here. I'll keep praying - hoping - wondering if PowerBasic can pull off a big one and come out with PBWin64.
We can always hope and dream.
Thanks
Mike
Hi Paul, Jose
Do we need a way to use Jose-Includes in FreeBasic to use i.e. ListView_GetSubItemRect
or is there a workaround.
Klaas
The main problem is that the official FB declares aren't well suited for BASIC type programming. Someone has decided that despite being a BASIC compiler you must use it as if it was a C compiler.
So what do you suggest Jose.
Isn't there another suitable compiler?
The FB includes are okay to work with. It takes a little more effort because you need to remember to use the right data types otherwise you will get compiler warnings. So, instead of always using a LONG or DWORD as in PowerBASIC, you would use types like HANDLE, BITMAP, HWND, LPARAM, WPARAM, etc. It does lead to your code being a little more self-documenting but it also means that you need to know what type to use for each situation.
I am getting used to it now. It is like everything with programming, the more you do it - the easier it gets.
Klaas,
The ListView_GetSubItemRect function is already defined in the FB include files. Look at "commctrl.bi" (line 3024):
private function ListView_GetSubItemRect(byval hwnd as HWND, byval iItem as long, byval iSubItem as long, byval code as long, byval prc as RECT ptr) as WINBOOL
if prc then
prc->top = iSubItem
prc->left = code
end if
function = SNDMSG(hwnd, LVM_GETSUBITEMRECT, cast(WPARAM, iItem), cast(LPARAM, prc))
end function