一、前言:
本人由于是个老PowerBasic爱好者,随着64位系统变得越来越普及,32位的PB编程就显得越来越力不从心了。至此选择了FB作为转型的Basic语言,主要考虑是不但其支持32位及64位编程,更重要的是没有任何限制而且长期免费使用。
但是在使用的过程中,由于习惯了PB编程模式及界面,所以就萌生了个想法,在FB代码编辑中实现PB风格的代码编辑风格。
所以想到了就开始着手编写函数库(PBSTYLE.BI)。经过两天的尝试最终完成了PB编程代码风格的实现,并利用这个样式库,实现了第一个窗口程序,并成功转发系统消息。
二、FreeBasic下PB代码演示:
REM #COMPILE EXE
REM #DIM ALL
'------------------------------------------------------------------------------
' ** Includes **
'------------------------------------------------------------------------------
REM #PBFORMS BEGIN INCLUDES
#INCLUDE ONCE "PBStyle.bi"
REM #PBFORMS END INCLUDES
'------------------------------------------------------------------------------
REM #PBFORMS BEGIN CONSTANTS
#define IDD_DIALOG1 101
REM #PBFORMS END CONSTANTS
'------------------------------------------------------------------------------
' ** Declarations **
'------------------------------------------------------------------------------
DECLARE FUNCTION ShowDIALOG1 ( BYVAL hParent AS HWND ) AS HWND
'DECLARE CALLBACK FUNCTION ShowDIALOG1Proc()
GLOBAL CALL_ShowDIALOG1Proc AS WNDPROC = PROCPTR ( ShowDefWindowProc )
'==============================================================================
' ** Main Application Entry Point **
'==============================================================================
FUNCTION PBMAIN ( ) AS LONG
PBFormsInitComCtls ( ICC_WIN95_CLASSES OR ICC_DATE_CLASSES OR ICC_INTERNET_CLASSES )
ShowDIALOG1 HWND_DESKTOP
FUNCTION = 1
END FUNCTION
'==============================================================================
' ** CallBacks **
'==============================================================================
FUNCTION ShowDIALOG1Proc ( ) AS LRESULT
SELECT CASE CB.MSG
CASE WM_INITDIALOG
SetWindowText( CB.HNDL, "系统消息 WM_INITDIALOG" )
function = 1
CASE WM_PAINT
DIM Rct AS RECT
DIM pnt AS PAINTSTRUCT
DIM hDC AS HDC
hDC = BeginPaint( CB.HNDL, @pnt )
GetClientRect ( CB.HNDL, @Rct )
SetBkMode hDC, TRANSPARENT
SetTextColor hDC, BGR ( 255, 0, 0 )
DrawText ( hDC, "Hello, World!", -1, @Rct, DT_SINGLELINE or DT_CENTER or DT_VCENTER )
EndPaint( CB.HNDL, @pnt )
'SetWindowText( CB.HNDL, "系统消息 WM_PAINT" )
FUNCTION = TRUE
CASE WM_CLOSE
IF MessageBox( CBHNDL, "是否退出程序?", "MTSERVER", MB_YESNOCANCEL ) = IDYES THEN
DIALOG_END CBHNDL
EXIT FUNCTION
ELSE
FUNCTION = 0
END IF
CASE WM_DESTROY
DIALOG_END CBHNDL
EXIT FUNCTION
END SELECT
END FUNCTION
'==============================================================================
' ** Dialogs **
'==============================================================================
FUNCTION ShowDIALOG1 ( BYVAL hParent AS HWND ) AS HWND
REM #PBFORMS BEGIN DIALOG %IDD_DIALOG1->->
DIM lRslt AS HWND = DIALOG_NEW ( hParent, "MainWClass", IDD_DIALOG1, "MT SERVER", 467, 361, _
WS_OVERLAPPEDWINDOW, _
WS_EX_DLGMODALFRAME OR WS_EX_CONTROLPARENT OR WS_EX_WINDOWEDGE )
REM #PBFORMS END DIALOG
'AnimateWindow ( lRslt, 500, AW_HOR_POSITIVE )
DIALOG_SHOW_MODAL lRslt, CALL_ShowDIALOG1Proc
REM #PBFORMS BEGIN CLEANUP %IDD_DIALOG1
REM #PBFORMS END CLEANUP
FUNCTION = lRslt
END FUNCTION
运行效果图:
其中关键是模拟PB中CALLBAK FUNCTION回调消息CB结构,这个可以自己定义一个函数如SystemMessage ( hwnd, wMsg, wParam, lParam ),在窗体创建后将系统消息转为CB结构。
PB的CB结构体:
TYPE MESSAGE
hWnd AS HWND
Msg AS UINT
wParam AS WPARAM
lParam AS LPARAM
TIME AS DWORD
PT AS POINT
lPrivate AS DWORD
CTL AS UINT
CTLMSG AS UINT
HNDL AS HWND
NMCODE AS UINT
NMHDR AS ANY PTR
NMHDRSTR AS WSTRING * 255
NMHWND AS HWND
NMID AS UINT
VALUE AS UINT
END TYPE
在接收到不同的系统消息,赋予不同的值,窗口过程没有返回消息的话,则交给DefWindowProc处理。
举例如下形式:
GLOBAL CB AS MESSAGE
GLOBAL CBHNDL AS HWND
'-------------------------------------------------------------------------------
' 转发系统消息
'-------------------------------------------------------------------------------
SUB SystemMessage ( BYVAL hWnd AS HWND, _
BYVAL wMsg AS UINT, _
BYVAL wParam AS WPARAM, _
BYVAL lParam AS LPARAM )
CB.hWnd = hWnd
CB.Msg = wMsg
CB.wParam = wParam
CB.lParam = lParam
IF wMsg = WM_CREATE OR wMsg = WM_NCCREATE THEN
DIM pCreate AS CREATESTRUCT PTR
pCreate = CPTR ( CREATESTRUCT PTR, lParam )
CB.lParam = CAST ( LPARAM, pCreate )
END IF
IF wMsg = WM_COMMAND THEN
CB.CTL = LOWORD ( wParam )
CB.CTLMSG = HIWORD ( wParam )
END IF
IF wMsg = WM_KEYDOWN THEN
CB.VALUE = LOBYTE ( wParam )
END IF
IF wMsg = WM_NOTIFY THEN
DIM pNmh AS NMHDR PTR
pNmh = CPTR ( NMHDR PTR, lParam )
CB.NMHDR = pNmh
CB.NMCODE = pNmh->code
CB.NMHWND = pNmh->hwndFrom
CB.NMID = pNmh->idFrom
END IF
IF wMsg = WM_DRAWITEM THEN
CB.CTL = wParam
CB.NMHDR = CPTR ( DRAWITEMSTRUCT PTR, lParam )
END IF
CB.HNDL = CBHNDL
END SUB
另外在#lang "fb"语系下,FB不支持CALL内部指令,这个需要自己写个函数实现,如下:
TYPE FUNCPROC AS FUNCTION ( ) AS LRESULT '函数指针
'-------------------------------------------------------------------------------
' CALL回调函数
'-------------------------------------------------------------------------------
FUNCTION CALLBACK ( PRO as FUNCPROC ) as LRESULT
dim lRet as LONG
asm call [pro] '过程函数入口地址
asm mov [lRet], eax '取得过程返回值
asm mov eax, eax
FUNCTION = lRet
END FUNCTION
全局变量GLOBAL可以使用宏定义:
#define GLOBAL DIM SHARED
局部变量LOCAL由于与内置函数冲突,需要改名:
#define LOCALL STATIC
最后将新增的PB关键字添加到IDE目录下fbfull.lng的文件中即可。
三、总结:
由于水平问题难免思路及写作存在瑕疵,此文仅仅提供编程技巧作为探讨及对FB编程的应用。