Firststep to Alaska

28
Second Life for Clipper applications (ALASKA XBASE++) You can change your old CLIPPER application to NEW WINDOWS APPLICATION in very short period of time, we talk about minutes, using ALASKA XBASE++. The story is: you have your CLIPPER application source code, get ALASKA XBASE++, install it, read this quid, add our PRG files, make small changes to your PRG modules, make PROJECT file and recompile and link using PBUILD utility. Now you have full WINDOWS 32-bit application. Give it to your users and then get back to ALASKA to learn how to take full power of it. Your users will get new version, you will get time to learn new product and everyone will be satisfied. Aleksandar Stefanovic AS Computer Software

description

tut

Transcript of Firststep to Alaska

Page 1: Firststep to Alaska

Second Life for Clipper applications (ALASKA XBASE++)

You can change your old CLIPPER application to NEW WINDOWS APPLICATION in very short period of time, we talk about minutes, using ALASKA XBASE++. The story is: you have your CLIPPER application source code, get ALASKA XBASE++, install it, read this quid, add our PRG files, make small changes to your PRG modules, make PROJECT file and recompile and link using PBUILD utility. Now you have full WINDOWS 32-bit application. Give it to your users and then get back to ALASKA to learn how to take full power of it. Your users will get new version, you will get time to learn new product and everyone will be satisfied.

Aleksandar Stefanovic

AS Computer Software

Page 2: Firststep to Alaska

Are you Clipper programmer with many DOS applications, someone who wants to

continue to live and someone who think that Windows is not the end? What to do now?

DOS applications can be executed under Windows platform but people want to go on, not

to stay in the past. DOS is the past, and you, as programmer must live with that. So, is

your life as programmer finished? Answer is NO. Your applications, source code can

have second chance. Alaska Xbase++ is solution for you. Is this the only one? No, you

have other options but we believe that this is the best one.

These days there is Alaska Xbase++ version 1.9 from Alaska Software. You can find it

on www.alaska-software.com . First thing that you will read is that this is 100% Clipper

5.x compatible windows 32bit’s compiler. That is a right and that is not the end. This is

only starting point for you to transfer your old DOS Clipper applications to windows

platform. I want you to remember this. Don’t use this compiler only to make your old

DOS applications, as windows consol applications. As you know DOS and Windows are

different operation systems, so logic you have in DOS time must be changed. Logic about

how users use your application has to be changed to. The best reason for this is that your

application doesn’t have full control over PC. This is just another process on it. Another

thing is user interface that have to be changed. You must use things that Windows offer

to you in the way that windows users expect. You don’t have to reinvent hot water again.

I believe that you as DOS Clipper programmer have full “know how” to use Windows. If

you don’t, than this text is not for you.

I believe that Xbase languages have to live on. Easy, effective, clear. And after all there

are so many people who use it for decade (or more). Many other programmers (C/C++,

Delphi…) don’t like Clipper and in one period of time they even don’t think about

Clipper people as programmers at all. But this is not our problem. Clipper was one of the

best that happened in the past. Number of Clipper application is so big, number of

Clipper programmers to. So, be patient and forget what other said about this, and

continue to make you living on it. Only thing that is important is that you want to learn

some new stuff. If you don’t, nothing will help you. If you are one of Clipper

programmer who don’t want to change anything then please, close this book and …

How to start? First, install it. Please, don’t forget to install Xbase TOOLS because there

are many functions that you will need. You will get all you need in ALASKA directory.

Now, use command prompt (CMD.EXE) instead of DOS and find yourself in

environment you know.

In the past you have Clipper.exe now you have xpp.exe.

On your hard drive you will find this directory structure:

<ALASKA\XPPW32\>

|—BIN Compiler and service programs

|—BOOK Online help

|—LIB Runtime library

|—INCLUDE #include files

Page 3: Firststep to Alaska

|—RESOURCE Resource files

|—RUNTIME Runtime libraries

|—SOURCE Source code

|—SYS Source for System level files

|—COMPAT Compatibility functions for

| Clipper ‘87

|—SAMPLES Example programs

<ALASKA\XBTW32\>

|—BIN Compiler and service programs

|—BOOK Online help

|—LIB Runtime library

|—INCLUDE include files

|—SOURCE Source code

|—SAMPLES Example programs

Environment variables are (here is AUTOXBB.BAT and AUTOXBT.BAT)

@echo off

SET XPPROOT=C:\ALASKA\XPPW32

SET LIB=C:\ALASKA\XPPW32\LIB;%LIB%

SET PATH=C:\ALASKA\XPPW32\BIN;C:\ALASKA\XPPW32\LIB;%PATH%

SET INCLUDE=C:\ALASKA\XPPW32\INCLUDE;%INCLUDE%

SET XPPRESOURCE=C:\ALASKA\XPPW32\RESOURCE\BITMAP;%XPPRESOURCE%

SET XPPRESOURCE=C:\ALASKA\XPPW32\RESOURCE\ICON;%XPPRESOURCE%

SET XPPRESOURCE=C:\ALASKA\XPPW32\RESOURCE\FONT;%XPPRESOURCE%

SET XPPRESOURCE=C:\ALASKA\XPPW32\RESOURCE\POINTER;%XPPRESOURCE%

@echo off

rem Environment for XbToolsIII

rem created by XbToolsIII installation 5-18-2006

SET PATH=C:\ALASKA\XBTW32\LIB;%PATH%

SET LIB=C:\ALASKA\XBTW32\LIB;%LIB%

SET INCLUDE=C:\ALASKA\XBTW32\INCLUDE;%INCLUDE%

You can have Clipper and ALASKA on the same system but you need to take care for

environment variables, remember that. This is the reason why we give you these listings.

Please, remember what happened after starting CLIPPER.EXE. You sow compiler

options. Just to remind you.

Copyright © 1985-1993, Computer Associates International, Inc.

Microsoft C Floating Point Support Routines

Copyright © Microsoft Corp 1984-1987. All Rights Reserved.

Options:

/a automatic memvar declaration

/b debug info

Page 4: Firststep to Alaska

/credits credits screen

/d(<id>)[=<val>] #define <id>

/es[<level>] set exit severity

/I<path> #include file search path

/l supress line number information

/m compile module only

/n no implicit starting procedure

/o<path> object file drive and/or path

/p generate pre-processed output (.ppo) file

/q quiet

/r[<lib>] request linker to search <lib> (or none)

/s syntax check only

/u[<file>] use command def set in <file> (or none)

/v variables are assumed m->

/w enable warnings

@file compile list of modules in <file>

Do you remember?

What will happen if you start xpp.exe?

XBT0023: Command-line error: no input file specification

Usage: xpp [<options>] <filename>

Valid options are:

/a automatic MEMVAR declaration

/b include debug information

/coff create COFF object file

/com Compatibility-Mode (max. 10 significant chars for ident.)

/d<id>[=<val>] #define <id>

/dll[:DYNAMIC|STATIC] create output file that can be used in a

dynamic or static DLL; default: static

/err:<count> abort compilation after <count> errors (default: 20)

/es compiler returns with error code if warnings are detected

/ga convert string characters ANSI -> OEM

/go convert string characters OEM -> ANSI

/i<path> include file search path

/l suppress linenumber embedding

/link[:"<options>"] invoke linker with <options> to build exe file

/m do not process SET PROCEDURE TO (ProcRequest)

/n no implicit starting procedure (MAIN)

/nod suppress request for default library in output file

/o<name> rename output file

/omf create OMF object file

/p create pre-processed output file

Page 5: Firststep to Alaska

/pptrace trace preprocessor's work

/profile generate profiling information

/q quiet mode

/r<libname> add request for library <libname>

/s syntax check only

/u[<filename>] use command definition set in <filename> (or none)

/v undeclared variables are assumed to be MEMVARs

/w enable standard warnings

/wi warn about access of uninitialized lex. variables

/wl warn about use of dynamic scoped variables

/wn warn about suspicious implicitly declared NILs

/wu warn about unused lexical variables

/z suppress short-cut optimization

We believe that you will find the difference but many things are the same. So you can use

xpp.exe as you use clipper.exe compiler. Output is not the same but you can live with

that. The Xbase++ compiler knows the same compiler-switches like the Clipper compiler.

There is as you see more compiler-switches that allow detecting more errors in the PRG

code. Keep this in mind: the Xbase++ compiler detects more errors in your code during

compile time than Clipper.

As Clipper programmer we believe that you don’t need “Hello World” sample. You have

your own applications and if you compile and link that with ALASKA you will get your

WINDOWS application. Because Clipper language is only a part of ALSAKA you have

to read all of help files for description of new functions, commands and objects. This

story is not about that only how to start in very short time to transfer your old DOS

Clipper application into NES WINDOWS ALASKA application. You can find in users

guide that you have only to recompile your project but then you will keep old DOS look

and here is short solution how to get new 32-bit application and how to get new look.

After that you will get time to change your application using other ALASKA functions,

command and objects but your users can use your NEW application in transition time.

Here we will not talk about linker, you can find that using alink is the same process but at

the start please forget this and use PBUIL.EXE utility to compile and link your

application. To use it you only have to make PROJECT.XPJ text file. It is easy but new

to you. The Xbase++ ProjectBuilder is a tool for managing entire software projects. You

can make one or more EXE or DLL (yes) files. This is ASCII file with XPJ extension. In

Xbase help documentation you can find one example

01: [PROJECT] 02: COMPILE = xpp // Missing compiler and linker 03: COMPILE_FLAGS = /q // information is added 04: DEBUG = yes

Page 6: Firststep to Alaska

05: GUI = no 06: LINKER = alink 07: LINK_FLAGS = 08: RC_COMPILE = arc 09: RC_FLAGS = 10: CUSTOMER.XPJ 11: 12: [CUSTOMER.XPJ] 13: CUSTOMER.EXE 14: 15: [CUSTOMER.EXE] // Automatically created 16: // $START-AUTODEPEND // dependencies 17: COLLAT.CH 18: GET.CH 19: MEMVAR.CH 20: PROMPT.CH 21: SET.CH 22: STD.CH 23: CUSTOMER.OBJ 24: GETCUST.OBJ 25: PRINT.OBJ 26: VIEWCUST.OBJ 27: // $STOP-AUTODEPEND 28: CUSTOMER.PRG 29: GETCUST.PRG 30: PRINT.PRG 31: VIEWCUST.PRG

Page 7: Firststep to Alaska

Don’t be afraid of this. It is easy to manage. You have only to remember that there is

sections that describe you compiler and linker options and list of all includes, source code

prg and obj files. Read users guide about this options.

Options for compiler and linker you will write only once and after that you have only to

add your files names.

So, look at one very simple project

01: [PROJECT] 02: DEBUG = yes // Project-wide definitions 03: GUI = no 04: CUSTOMER.XPJ // The root of the project 05: 06: [CUSTOMER.XPJ] // List all EXE and DLL 07: CUSTOMER.EXE // files of the project here 08: 09: [CUSTOMER.EXE] // List all sources for each 10: CUSTOMER.PRG // EXE and/or DLL file separately 11: GETCUST.PRG 12: PRINT.PRG 11: VIEWCUST.PRG

You can create this using editor. Numbers are not part of file body and here are they just

to make things clear and easy for reference. So if you have to make PROJECT file for

your project, start editor, write [PROJECT], go to the next line, write DEBUG=yes (use

this for testing, and when you get no errors, change it to DEBUG=no), go to next line

Write name for your project (in this case it is CUSTOMER) CUSTOMER.XPJ and you

have finished first section. Now go to next line and write [CUSTOMER.XPJ] starting

point for your application description. Go to next line and write CUSTOMER.EXE, this

is the name of EXE file that will be generated. Now we have to list from what ours

programs modules we want EXE file. Write [CUSTOMER.EXE] and after that make a

list of PRG files. That’s it. Save this file as PROJECT.XPJ and under command prompt

type PBUILD. This utility will open our PROJETCT.XPJ file and invoke compiler and

linker for us. After that you will have your EXE. Full win32 application. It will not be so

difficult to make PROJECT.XPJ that describe your old DOS application for start. You

Page 8: Firststep to Alaska

have more options that PBUILD can use. If you start transition to windows environment

and if you use your old DOS source Clipper code without changes, this is good start

point. Please use

GUI= NO . Whenever a program performs graphic output, be it with Gra..() functions or

by using Xbase Parts, GUI=YES must be defined.

Your application will look as your DOS application. But only look is the same. If you try

to use it on DOS you will not be able to start it because this is full windows application.

Now you are Windows programmer. It is not so difficult for Clipper programmer to write

PROJECT.XPJ and became Windows programmer. You are back.

In Xbase help file you can find full description of options you can (and will) use in your

project file. Please read it.

All information that may be listed in the [PROJECT] section is described below. Each project file must begin with the [PROJECT] section which contains definitions valid for the entire project (project-wide definitions): COFF_LINKER= This optional definition can be used to define the linker to be invoked by the

ProjectBuilder when OBJ_FORMAT= is set to COFF (Common Object File Format). If COFF_LINKER= is not defined in this case, the ProjectBuilder uses the linker defined with LINKER=.

COMPILE= This indicates the name of the Xbase++ compiler. It is always XPP. COMPILE_FLAGS= All compiler switches to be set for compilation are defined here. Note that

separate definitions OBJ_DIR= and DEBUG= exist for the switches /o and /b.

DEBUG= This definition can be set to YES (debug version) or NO (non debug

version). Executable files are created accordingly with or without debug information. An executable file must be created with DEBUG=YES so that it can be monitored with the debugger.

GUI= If a program is to run as text mode application, GUI=NO must be set.

Whenever a program performs graphic output, be it with Gra..() functions or by using Xbase Parts, GUI=YES must be defined.

INCLUDE= Add a search path to find .CH - files to the INCLUDE path inherited by the process which calls PBuild.exe.

LIB= Add a search path to find .LIB and .OBJ files to the LIB path inherited by the process which calls PBuild.exe.

LINKER= This definition indicates the name of the linker that is used to create EXE

or DLL files from OBJ files. It is the linker that is shipped with the operating system-specific Xbase++ version.

LINK_FLAGS= All linker flags which are not covered by GUI= and DEBUG= are listed in

this definition. However, if the flags /PM and /DE are used here as well, they override the corresponding definitions GUI= and DEBUG=.

OBJ_DIR= Optionally, the directory for OBJ files can be defined. The compiler creates

OBJ files in this directory, and the linker searches it for these files. Only one directory can be set for each target.

Page 9: Firststep to Alaska

Note: The OBJ_DIR setting affects only the OBJ files listed in the section of a project file that is delimited with // $START-AUTODEPEND and // $STOP-AUTODEPEND. PBuild completes these OBJ file names with the OBJ_DIR directory so that no path information may be specified for the files listed in the auto-dependency section. Additional OBJ files can be specified with a full qualified path outside the auto-dependency section. OBJ_FORMAT= Two values can be used for this definition to select the object file format:

COFF (Common Object File Format) or OMF (Object Module Format). The ProjectBuilder then starts the Compiler and invokes AIMPLIB.EXE, if necessary, using the corresponding switches /coff or /omf. In addition, the linker specified with COFF_LINKER= or OMF_LINKER= is used in the build process.

OMF_LINKER= This optional definition can be used to define the linker to be invoked by the

ProjectBuilder when OBJ_FORMAT= is set to OMF (Object Module Format). If OMF_LINKER= is not defined in this case, the ProjectBuilder uses the linker defined with LINKER=.

POST_BUILD= This definition can be used to execute a command after the target is built.

The statement that follows the equal sign ("=") is then executed in a command shell. More than one POST_BUILD definition can be present in a section. In this case, the commands are executed sequentially, in the order they were defined. If a command returns an error, execution of PBUILD.EXE is aborted. This behaviour can be overridden by specifying a hyphen character ("-") as first character behind the equal sign ("=").

POST_CLEAN= This definition can be used to execute a command after the target is

cleaned. The statement that follows the equal sign ("=") is then executed in a command shell. More than one POST_CLEAN definition can be present in a section. In this case, the commands are executed sequentially, in the order in which they were defined. If a command returns an error, execution of PBUILD.EXE is aborted. This behaviour can be overridden by specifying a hyphen character ("-") as first character behind the equal sign ("=").

PRE_BUILD= This definition can be used to execute a command before the target is built.

The statement that follows the equal sign ("=") is then executed in a command shell. More than one PRE_BUILD definition can be present in a section. In this case, the commands are executed sequentially, in the order in which they were defined. If a command returns an error, execution of PBUILD.EXE is aborted. This behaviour can be overridden by specifying a hyphen character ("-") as first character behind the equal sign ("=").

PRE_CLEAN= This definition can be used to execute a command before the target is

cleaned. The statement that follows the equal sign ("=") is then executed in a command shell. More than one PRE_CLEAN definition can be present in a section. In this case, the commands are executed sequentially, in the order in which they were defined. If a command returns an error, execution of PBUILD.EXE is aborted. This behaviour can be overridden by specifying a hyphen character ("-") as first character behind the equal sign ("=").

RC_COMPILE= This definition contains the name of the resource compiler as it is shipped

with Xbase++. Normally, additional resources are used for GUI applications only.

Page 10: Firststep to Alaska

OS/2 - There are additional notes at the end of this section for the OS/2 platform. RC_FLAGS= The flags for the resource compiler are set with this definition. <SECTION> All entries in the [PROJECT] section defined without equal signs are used as a reference to subsequent user-defined sections which are to be analyzed by the ProjectBuilder. Normally, only one additional section (the root section) is referenced. There must be at least one user-defined section. Note: Definitions listed in the [PROJECT] section are valid for the entire project. However, they may appear in user-defined sections as well. In this case, they are valid for one section only. If definitions are passed to PBUILD.EXE on the command line using the /d switch, all definitions in a project file with the same name are ignored. Resource compiler for OS/2 Depending on whether resources are declared in ARC or RC files, the option RC_COMPILE= must be set to arc or rc . If ARC files are used, the Project Builder invokes first ARC.EXE (Alaska resource compiler) and then RC.EXE (OS/2 resource compiler). ARC.EXE translates ARC files to RC files which can be compiled by RC.EXE.

Use what you need.

If you get large EXE file consider breaking it into one or more DLL files. Please don’t

ask me what is it. I believe you know. How you will do that. Using PBUILD. If you have

prg files like this

** File MAIN.PRG ** // This file is used to

PROCEDURE Main // create an EXE file.

SayHello() // Procedures are contained

SayHi() // in a DLL file.

RETURN

** File SAYHELLO.PRG ** // These two files are used

PROCEDURE SayHello // to create a DLL file.

? "Hello world"

RETURN

** File SAYHI.PRG **

PROCEDURE SayHi

? "Hi folks"

RETURN

You will use next PROJECT file

// File: PROJECT.XPJ

[PROJECT]

ROOT

Page 11: Firststep to Alaska

[ROOT]

MAIN.EXE

MYFUNCS.DLL

[MAIN.EXE]

MAIN.PRG

MYFUNCS.LIB

[MYFUNCS.DLL]

SAYHELLO.PRG

SAYHI.PRG

When you start PBUILD you will make MAIN.EXE and MYFUNCS.DLL. In your

directory you will find MYFUNCS.LIB this file will be used by linker only. So when you

want to use functions from some DLL you need LIB file for it. Just add it to your

PROJECT.

Remember XB TOOLS? If you use functions from it you will need to add LIB files

XBTBASE1.LIB and XBTBASE2.LIB. You will find it in ALASKA XBTW32\LIB

directory. Just add it and you will get more then 800 functions. If you as Clipper

programmer use some libraries that are not part of standard Clipper library you will have

to change it with functions from XBTOOLS library. Believe us, you will find them there.

Some functions you will not find, but this is the price to start your WINDOWS life. On

the other hand clipper functions and commands are only one part of ALASKA XBASE.

When you want to make full 32-bit Windows application without any text based support

you will find much more commands and functions new to Clipper programmers. But

about them we will talk later.

For now this is all you need to make your new (old DOS) Windows application. Once

againg You are now Windows programmer.

Let’s make our applications to look more Windows then DOS application. This is

something that in ALASKA you can find under HYBRID system.

First we have to say something about APPSYS. This is new for Clipper users. Alaska will

use DEFAULT APPSYS function if you don’t write one. In this function you can make

all initialization you need, but many programmer use this only to set starting windows

properties.

This function is normally executed prior to the call of the MAIN procedure and if we

want to use some GUI device output we must use it. This file you can write ONLY once

and forget about it. Just add it in your project file. What you will get. Window that you

can control in old DOS way. But you will have 80 rows and 30 col. Why 30 instead of

25. This looks better and you will get some extra space where you can add some

graphics. Your source code that control display will not have to be changed. We add one

more thing. Functions that will check are we have any other instance of our application

and how we can avoid it. Under windows you can start many applications and one more

Page 12: Firststep to Alaska

then once, but this is sometimes that not is what we want. For this we use function

just_one(). This function use some windows API functions, this is the reason why we

need DLL.CH and some other DLL declaration. We don’t have LIB files for Windows

libraries and we must use functions that can load libraries and find functions in it. What

you are see here is the way you can use to access any function from any DLL library if

you know function name, where to find it and how to use it. Remember, you are in

Windows now and there is no reason not to use functions from it. In old day’s we use

DOS internal functions, interrupts and now we can use WINDOWS API functions.

For this we must find documentations for it. This is another story, but we believe that

sometimes you will ask for it.

////////////////////////////////////////////////////////////////////

// APPSYS.PRG

//////////////////////////////////////////////////////////////////////

#include "DLL.CH"

#include "appevent.ch"

#include "xbp.ch"

#include "aboutbox.ch"

***********************************************************************

*****

* Function AppSys() to create default output devices

***********************************************************************

*****

PROCEDURE AppSys()

#define DEF_ROWS 30

#define DEF_COLS 80

//#define DEF_FONTHEIGHT 16

//#define DEF_FONTWIDTH 8

//#define DEF_FONTHEIGHT 23

//#define DEF_FONTWIDTH 10

LOCAL oCrt, nAppType := AppType()

LOCAL aSizeDesktop, aPos

local DEF_FONTHEIGHT:=16

local DEF_FONTWIDTH:=8

// uncomment this 3 lines if you need to disable more then one instance

of application

// If just_one( "XbpPmtClass" )

// QUIT

// EndIF

// uncomment this if you want SPLASH screen

//ShowSplashScreen(ID_ABOUT_BITMAP)

//sleep(100)

DO CASE

CASE nAppType == APPTYPE_PM

aSizeDesktop := AppDesktop():currentSize()

aPos := { (aSizeDesktop[1]-(DEF_COLS * DEF_FONTWIDTH))/2, ;

Page 13: Firststep to Alaska

(aSizeDesktop[2]-(DEF_ROWS * DEF_FONTHEIGHT)) /2 }

Do Case

Case aSizeDeskTop[1] = 800

Def_FontHeight := 18

Def_FontWidth := 10

Case aSizeDeskTop[1] = 1024

Def_FontHeight := 22

Def_FontWidth := 12

Otherwise

Def_FontHeight := 16

Def_FontWidth := 8

Endcase

oCrt := XbpCrt():New ( NIL, NIL, aPos, DEF_ROWS, DEF_COLS )

oCrt:FontWidth := DEF_FONTWIDTH

oCrt:FontHeight := DEF_FONTHEIGHT

oCrt:title := "CHANGE windows Title" //put your title here

oCRT:icon := ID_AS_ICON

oCrt:FontName := "Alaska Crt"

// oCRT:Pointer := ID_AS_CURSOR

// oCrt:FontName := "Terminal"

//

oCRT:XBPCRT():setpointer(,ID_AS_CURSOR,XBPWINDOW_POINTERTYPE_ICON)

oCrt:Create()

// ::setpointer(,ID_AS_CURSOR,XBPWINDOW_POINTERTYPE_ICON)

oCrt:PresSpace()

SetAppWindow ( oCrt )

CASE nAppType == APPTYPE_VIO .OR. nAppType == APPTYPE_NOVIO

oCrt := RootCrt():New()

oCrt:CreateBuffer := .T.

oCrt:Create()

SetAppWindow ( oCrt )

ENDCASE

RETURN

DLLFUNCTION GetClassNameA( nHwnd, @cBuf, nBufLen ) USING STDCALL FROM

USER32.DLL

/*

* ShowWindow() Comande, iz WINUSER.H

*/

#define SW_HIDE 0

#define SW_SHOWNORMAL 1

#define SW_NORMAL 1

#define SW_SHOWMINIMIZED 2

#define SW_SHOWMAXIMIZED 3

#define SW_MAXIMIZE 3

#define SW_SHOWNOACTIVATE 4

Page 14: Firststep to Alaska

#define SW_SHOW 5

#define SW_MINIMIZE 6

#define SW_SHOWMINNOACTIVE 7

#define SW_SHOWNA 8

#define SW_RESTORE 9

#define SW_SHOWDEFAULT 10

#define SW_MAX 10

DLLFUNCTION FindWindowA( @ClassName, @WinName ) USING STDCALL FROM USER32.DLL

// DLLFUNCTION FindWindowA( @ClassName, WinName ) USING STDCALL FROM USER32.DLL

DLLFUNCTION GetForegroundWindow() USING STDCALL FROM USER32.DLL

DLLFUNCTION IsIconic( nHwnd ) USING STDCALL FROM USER32.DLL

DLLFUNCTION GetLastActivePopup( nHwnd ) USING STDCALL FROM USER32.DLL

DLLFUNCTION ShowWindow( nHwnd, nCmdShow ) USING STDCALL FROM USER32.DLL

DLLFUNCTION BringWindowToTop( nHwnd ) USING STDCALL FROM USER32.DLL

DLLFUNCTION SetForegroundWindow( nHwnd ) USING STDCALL FROM USER32.DLL

DLLFUNCTION GetWindowThreadProcessId( nForgroundHwnd, @nRetProcId ) USING

STDCALL FROM USER32.DLL

FUNCTION just_one( cClass, cWinTitle )

LOCAL lRet := .F.

LOCAL nHwndFind, nHwndForeground, nForegroundId

LOCAL nFindId, nHwndLast

If VALTYPE( cWinTitle ) = "C"

nHwndFind := FindWindowA( @cClass, @cWinTitle )

Else

nHwndFind := FindWindow2( @cClass )

Endif

If nHwndFind # 0

nHwndForeground := GetForegroundWindow()

nForeGroundId := GetWindowThreadProcessId( nHwndForeground, 0 )

nFindId := GetWindowThreadProcessId( nHwndFind, 0 )

If nForeGroundId != nFindId .OR. IsIconic( nHwndFind ) # 0

nHwndLast := GetLastActivePopup( nHwndFind )

If IsIconic( nHwndLast ) # 0

ShowWindow( nHwndLast, SW_RESTORE )

EndIF

BringWindowToTop( nHwndLast )

SetForegroundWindow( nHwndLast )

EndIF

Page 15: Firststep to Alaska

lRet := .T.

EndIF

RETURN lRet

FUNCTION FindWindow2(cClass)

LOCAL nDll:=DllLoad("USER32.DLL")

LOCAL xRet:=DllCall(nDll, DLL_STDCALL, "FindWindowA", @cClass, 0)

DllUnLoad(nDll)

RETURN xRet

This file (appsys.prg) you have only to add in project.xpj and forget about it. Once again,

this procedure is executed when application start, so if you want other things at that

moment you can add it here. YOU HAVE ONLY TO CHANGE TEXT FOR WINDOW

TITLE BAR (find it in listing).

Information about application have every Windows application and this is ABOUTBOX

function. Lets add real windows ABOUTBOX to your application.

In this PRG file we use ABOUTBOX.CH

////////////////////////////////////////////////////////////////////// //

// ABOUTBOX.CH

//

// Copyright:

// Alaska Software Inc., (c) 1997-2001. All rights reserved.

//

// Contents:

// Bitmap Id for function AboutBox()

//

//////////////////////////////////////////////////////////////////////

#define ID_AS_ICON 101

#define ID_AS_CURSOR 102

#define ID_ABOUT_BITMAP 4242

#define ID_ABOUT_OKSLIKA 4243

Here is ABOUTBOX.PRG

//////////////////////////////////////////////////////////////////////

//

// ABOUTBOX.PRG

//

//////////////////////////////////////////////////////////////////////

#include "Aboutbox.ch"

#include "Appevent.ch"

#include "Common.ch"

#include "Font.ch"

Page 16: Firststep to Alaska

#include "Gra.ch"

#include "Xbp.ch"

#define BITMAP_MAX_WIDTH 200

#define BITMAP_MAX_HEIGHT 240

//this function we will use to show info about our application

function AboutAS()

AboutBox( "AS Computer Software – Application NAME " , ; // title

"TEST APPLICATION" , ; // program

"Version 1.0",;

"Aleksandar Stefanovic dipl.ing.", ;

"program for" + Chr(13) + ;

" WINDOWS"+chr(13)+" OS" , ; // miscellaneous

ID_ABOUT_BITMAP ) // bitmap max.

200x240

RETURN (0)

// this function we will use to inform user about something

function AboutOK(swhat)

AboutBox( "AS Computer Software – Application Name " , ; // title

"TEST APPLICATION" , ; // program

"Version 1.0",;

" ", ;

swhat,;

ID_ABOUT_OKSLIKA ) // bitmap max.

200x240

RETURN (0)

/*

* Display program information and an optional bitmap logo

*/

PROCEDURE AboutBox( cTitle, cProgram, cVersion, cCopyright, cMisc,

nBitmap )

LOCAL nEvent, mp1, mp2, oXbp, nDX, lExit := .F.

LOCAL oDlg, drawingArea, oLogo, oBtn, aPos, aSize, oFocus

DEFAULT cTitle TO "" , ;

cProgram TO "" , ;

cVersion TO "" , ;

cCopyright TO "" , ;

cMisc TO ""

aSize := { 250, 280 }

aPos := CenterPos( aSize, AppDesktop():currentSize() )

Page 17: Firststep to Alaska

oDlg := XbpDialog():new( AppDesktop(), SetAppWindow(), aPos, aSize,

, .F.)

oDlg:taskList := .F.

oDlg:minButton:= .F.

oDlg:maxButton:= .F.

oDlg:border := XBPDLG_DLGBORDER

oDlg:title := cTitle

oDlg:create()

oDlg:Close := { || lExit := .T. }

drawingArea := oDlg:drawingArea

drawingArea:setFontCompoundName( FONT_HELV_SMALL )

oXbp := XbpStatic():new( drawingArea, , {16,204}, {216,24} )

oXbp:caption := cProgram

oXbp:setFontCompoundName( FONT_HELV_MEDIUM + FONT_STYLE_BOLD )

oXbp:options := XBPSTATIC_TEXT_VCENTER+XBPSTATIC_TEXT_CENTER

oXbp:create()

IF nBitmap <> NIL

aPos := oXbp:currentPos()

aPos[2] += oXbp:currentSize()[2]

ENDIF

oXbp := XbpStatic():new( drawingArea, , {16,180}, {216,12} )

oXbp:caption := cVersion

oXbp:options := XBPSTATIC_TEXT_VCENTER+XBPSTATIC_TEXT_CENTER

oXbp:create()

oXbp := XbpStatic():new( drawingArea, , {16,132}, {216,36} )

oXbp:caption := cCopyRight

oXbp:options :=

XBPSTATIC_TEXT_WORDBREAK+XBPSTATIC_TEXT_TOP+XBPSTATIC_TEXT_CENTER

oXbp:create()

oXbp := XbpStatic():new( drawingArea, , {16,120}, {216,2} )

oXbp:type := XBPSTATIC_TYPE_RAISEDLINE

oXbp:create()

oXbp := XbpStatic():new( drawingArea, , {16,60}, {216,48} )

oXbp:caption := cMisc

oXbp:options :=

XBPSTATIC_TEXT_WORDBREAK+XBPSTATIC_TEXT_TOP+XBPSTATIC_TEXT_CENTER

oXbp:create()

/*

* The pushbutton reacts to the Return and Esc keys due to

* the :keyboard code block

*/

oBtn := XbpPushButton():new( drawingArea, , {86,12}, {67,24} )

oBtn:caption := "Ok"

oBtn:setpointer(,ID_AS_CURSOR,XBPWINDOW_POINTERTYPE_ICON)

oBtn:create()

oBtn:activate := {|| lExit := .T. }

oBtn:keyboard := {|nKey| IIF( nKey == xbeK_RETURN .OR. nKey ==

xbeK_ESC, ;

lExit := .T., NIL ) }

Page 18: Firststep to Alaska

IF nBitmap <> NIL

oXbp := XbpStatic():new( drawingArea )

oXbp:type := XBPSTATIC_TYPE_RAISEDBOX

oXbp:create()

oLogo := XbpStatic():new( oXbp, , {2,2} )

oLogo:type := XBPSTATIC_TYPE_BITMAP

oLogo:caption := nBitmap

oLogo:autoSize := .T.

oLogo:create()

/*

* Size of the bitmap is limited

*/

aSize := oLogo:currentSize()

aSize[1] := Min( BITMAP_MAX_WIDTH , aSize[1] )

aSize[2] := Min( BITMAP_MAX_HEIGHT, aSize[2] )

nDX := aSize[1] + 12

mp1 := oDlg:currentSize()

oDlg:setSize( { mp1[1] + nDX + 4, mp1[2] } )

ChangePos( oDlg, { -nDX / 2, 0 } )

mp1 := { nDX, 0 }

AEval( drawingArea:childList(), {|o| ChangePos( o, mp1 ) } )

aSize[1] += 4

aSize[2] += 4

oXbp:setSize( aSize )

oXbp:setPos( { 12, aPos[2] -aSize[2] } )

ENDIF

oDlg:show()

oDlg:setModalState( XBP_DISP_APPMODAL )

oXbp:setpointer(,ID_AS_CURSOR,XBPWINDOW_POINTERTYPE_ICON)

oFocus := SetAppFocus( oBtn )

DO WHILE ! lExit

nEvent := AppEvent( @mp1, @mp2, @oXbp )

oXbp:handleEvent( nEvent, mp1, mp2 )

ENDDO

oDlg:setModalState( XBP_DISP_MODELESS )

oDlg:destroy()

SetAppFocus( oFocus )

RETURN

/*

* Change the position of an XBP by distance

*/

STATIC PROCEDURE ChangePos( oXbp, aDistance )

LOCAL aPos := oXbp:currentPos()

aPos[1] += aDistance[1]

aPos[2] += aDistance[2]

Page 19: Firststep to Alaska

oXbp:setPos( aPos )

RETURN

/*

* Calculate the center position from size and reference size

*/

STATIC FUNCTION CenterPos( aSize, aRefSize )

RETURN { Int( (aRefSize[1] - aSize[1]) / 2 ) ;

, Int( (aRefSize[2] - aSize[2]) / 2 ) }

With this function we will create some dialogs with picture in it. For this we need this

ARC file

//////////////////////////////////////////////////////////////////////

//

// ABOUTBOX.ARC

//

//////////////////////////////////////////////////////////////////////

#include "Aboutbox.ch"

ICON ID_AS_ICON = "as.ico"

BITMAP ID_ABOUT_BITMAP = "as.bmp"

BITMAP ID_ABOUT_OKSLIKA = "ok.bmp"

ICON ID_AS_CURSOR = "AS_CUR.ICO"

Of course, we need some ico and bmp files. Use it with your files.

We will use it as splash screen and in some windows (AS.BMP)

Page 20: Firststep to Alaska

This means IMPORTANT.(OK.BMP)

Please use this files as is. You can change bitmap names or some text and you will get

ABOUTBOX and one notifies functions with windows.

Just another file we need is splashscreen file.

// splash.PRG

#include "XBP.CH"

#include "FONT.CH"

#include "GRA.CH"

STATIC oStartUp

PROCEDURE ShowSplashScreen(BITMAPID)

LOCAL oXbp, aSize, aRect

oStartUp := XbpDialog():New(,,,{ 1, 1 },, .F. )

oStartUp:MinButton := .F.

oStartUp:MaxButton := .F.

oStartUp:HideButton := .F.

oStartUp:TitleBar := .F.

oStartUp:SysMenu := .F.

oStartUp:TaskList := .F.

oStartUp:Border := XBPDLG_NO_BORDER

oStartUp:Title := ""

oStartUp:Create()

oStartUp:DrawingArea:SetColorBG ( -255 )

oXbp := XbpStatic():New( oStartUp:DrawingArea,,,,, .F. )

oXbp:Type := XBPSTATIC_TYPE_BITMAP

oXbp:Caption := BITMAPID

oXbp:AutoSize := .T.

oXbp:ClipChildren := .F.

Page 21: Firststep to Alaska

oXbp:Create()

oXbp:Show()

aSize := oXbp:CurrentSize()

aRect := oStartUp:CalcFrameRect( { 0, 0, aSize[1], aSize[2] } )

oStartUp:SetSize ( { aRect[3] - aRect[1], aRect[4] - aRect[2] } )

CenterXbp ( oStartUp )

oStartUp:Show()

oStartUp:ToFront()

RETURN

PROCEDURE RemoveSplashScreen()

oStartUp:Destroy()

RETURN

STATIC FUNCTION CenterXbp ( oXbp )

LOCAL aSizeParent, aSize, aPos

aSizeParent := oXbp:SetParent():CurrentSize()

aSize := oXbp:CurrentSize()

aPos := Array(2)

aPos[1] := ( aSizeParent[1] - aSize[1] ) / 2

aPos[2] := ( aSizeParent[2] - aSize[2] ) / 2

oXbp:SetPos ( aPos )

RETURN aPos

For now we have main splash screen, appsys function and main window that act like

DOS screen. These files you can write only ones and use it again in other projects.

Our application has modules in different PRG files. We can use Windows menu to access

them and we will do it in this way. Our Main procedure will look like this.

//////////////////////////////////////////////////////////////////////

//

// MENUDEMO.PRG

//

//////////////////////////////////////////////////////////////////////

#include "Appevent.ch"

#include "Xbp.ch"

#include "Aboutbox.ch"

#include "gra.ch"

#include "dll.ch"

Page 22: Firststep to Alaska

PROCEDURE Main

LOCAL nEvent, mp1, mp2, oXbp,w_w,oPS,oBMP,obmpp

public u_programu:=.f.

private oStatusL,oStatusT,nDLL,oSTatusL1,OstatusT1

SetColor( "N/W" )

SetCancel( .F. )

SetMouse(.T.)

set scoreboard off

set cursor off

set century on

set date german

set wrap on

firmatxt1:=space(40)

firmatxt2:=space(40)

firmatxt3:=space(40)

RemoveSplashScreen()

oPS := SetAppWindow():presSpace()

oBMP:= XbpBitmap():new():create( oPS )

oBMP:loadfile("as.jpg")

oBMP:draw(oPS)

oStatusL:=XbpStatic():new(,oPS,{3,3},{635,21})

oStatusL:type:=XBPSTATIC_TYPE_RAISEDBOX

oStatusL:create()

oStatust:=XbpStatic():new(,oStatusL,{04,4},{633,20})

oStatust:type:=XBPSTATIC_TYPE_TEXT

oStatust:create()

setcolor("W/N")

oStatust1:=XbpStatic():new(,oPS,{200,120},{300,240})

oStatust1:type:=XBPSTATIC_TYPE_TEXT

oStatust1:create()

SetAppWindow():useShortCuts := .T.

AS_MENU( SetAppWindow():menuBar() )

setcolor("W/N")

//ok when we start let’s play one AVI file

pustiavi()

DO WHILE nEvent <> xbeP_Close

nEvent := AppEvent( @mp1, @mp2, @oXbp )

oXbp:handleEvent( nEvent, mp1, mp2 )

oBMP:draw(oPS)

porukas(" ")

set cursor off

set confirm off

ENDDO

RETURN

/*

Page 23: Firststep to Alaska

• We will create manu

• */

PROCEDURE AS_MENU( oMenubar )

LOCAL oMenu

oMenu := XbpMenu():new( oMenuBar )

oMenu:title := "~System"

oMenu:create()

oMenu:itemSelected := {|nItem| MenuDispatcher( 100+nItem ) }

oMenu:addItem( {"~a) End" , NIL} )

oMenu:addItem( {"~b) Reindex files", {|| k_ind()}} )

omenu:addItem( {"~c) Empty databases",{|| k_dbf()}} )

oMenubar:addItem( {oMenu, NIL} )

oMenu := XbpMenu():new( oMenuBar )

oMenu:title := "~Option 1"

oMenu:create()

oMenu:itemSelected := {|nItem| MenuDispatcher( 200+nItem ) }

oMenu:addItem( {"~a) Option 1.1" ,{||p0101()}} )

oMenu:addItem( {"~b) Option 1.2", {||p0102()}} )

oMenubar:addItem( {oMenu, NIL} )

oMenu := XbpMenu():new( oMenuBar )

oMenu:title := "~Option 2"

oMenu:create()

oMenu:itemSelected := {|nItem| MenuDispatcher( 300+nItem ) }

oMenu:addItem( {"~a) Option 2.1" ,{||p0201()}} )

oMenu:addItem( {"~b) Option 2.2” ,{||p0202()}} )

oMenu := XbpMenu():new( oMenuBar )

oMenu:title := "~AS Software"

oMenu:create()

oMenu:itemSelected := {|nItem| MenuDispatcher( 700+nItem ) }

oMenu:addItem( {"~a) Aout us" ,{||aboutas()}} )

oMenubar:addItem( {oMenu, NIL} )

RETURN

PROCEDURE MenuDispatcher( nSelection )

DO CASE

CASE nSelection == 101

if !u_programu

QUIT

else

aboutok("You have to leve modul first"+chr(13)+"thn quit

application")

endif

ENDCASE

RETURN

//manage our status bar caption

function porukas(sta)

oStatust:setcaption(sta)

return (NIL)

Page 24: Firststep to Alaska

// our avi file is TEST.AVI

DLLFUNCTION mciSendString(@por,@vr,duz,ko) USING STDCALL FROM WINMM.DLL

function pustiavi()

local nDLL:=DLLLoad("WINMM.DLL")

local poruka1:= "OPEN TEST.AVI TYPE AVIVIDEO ALIAS AVI WAIT"

local poruka2

local poruka3:="PUT AVI DESTINATION AT 200 200 320 240 wait"

local poruka4:="play avi WAIT"

local poruka5:="window avi handle default wait"

local poruka6:="close avi wait"

local baffer:=space(200)

local nazad:=0

local n

//n:=alltrim(str(SetAPPWindow():gethwnd(),10))

n:=alltrim(str(oStatust1:gethwnd(),10))

poruka2:= "WINDOW AVI HANDLE "+n+" WAIT"

nazad:=dllCall(nDLL,DLL_STDCALL,"mciSendStringA",@poruka1,@baffer,0,0)

nazad:=dllCall(nDLL,DLL_STDCALL,"mciSendStringA",@poruka2,@baffer,0,0)

//nazad:=dllCall(nDLL,DLL_STDCALL,"mciSendStringA",@poruka3,@baffer,0,0

)

//? "3 "+str(nazad,10)

nazad:=dllCall(nDLL,DLL_STDCALL,"mciSendStringA",@poruka4,@baffer,0,0)

nazad:=dllCall(nDLL,DLL_STDCALL,"mciSendStringA",@poruka5,@baffer,0,0)

nazad:=dllCall(nDLL,DLL_STDCALL,"mciSendStringA",@poruka6,@baffer,0,0)

DLLUnload(nDLL)

oStatust1:destroy()

return (NIL)

We here use NEW MAIN function, we make window display, play AVI in it, draw

picture and make menu to access other parts of our application.

Don’t be afraid because you can see many new things in these listings and maybe you

don’t understand them but please remember, you can use it as is, change only what we

told you and you are safe. Later you have time to debate about this. We will say it again,

if you copy these listings you will have application with splash screen like other do, you

have window that can be controlled as dos screen, AVI video in it at start (this is not

important, but just for you to see how it is easy) and menu at last like other standard

windows application. Sorry, this IS WINDOWS APPLICATION.

We set PUBLIC variable U_PROGRAMU so we can check when we are in some

application module and we want to prevent other modules from starting. You can manage

menu options but we believe that this is best solution for start. This is something that you

Page 25: Firststep to Alaska

have to rewrite later and add more windows event logic support. For now we just want to

have NEW LOOK and minimal changes under the hood.

In every module you have to add at start

If u_programu

Return (NIL)

Endif

U_programu:=.t.

When we get to end of our module we have to set

U_programu:=.f.

This is our flag. We need it because we don’t want to control menu options. We can

enable and disable them but this is much better from our point of view at start.

We have our own status bar to. You can use status bar part of xbase but sometimes it is

better to have our own.

And in lower left corner we put our bitmap. Now our application doesn’t look like DOS

one.

You can easy add other your modules. I thing that you get the picture how to very easy

transfer your DOS application to Windows world. You can use this files as your start

point. Other modules don’t have to be changed. Just add CLR command when you eneter

your procedure and CLR at the end. For now it will be all you need.

This is our CRT Window and we control it. On this windows you can use SAY,GET

QOUT, TBROWSE ,SAVESCREEN,RESTSCREEN…

Just one more thing, you can have more then one, let’s say DOS window. How?

Use this function

#include "inkey.ch"

#include "xbp.ch"

#include "box.ch"

#include "gra.ch"

FUNCTION CrtBox( nT, nL, nB, nR, cTitle, bAction )

LOCAL oAppWindow, cColor, nCursor, oError

LOCAL oCrt, nRowCount, nColCount, nX, nY, xReturn

oAppWindow := SetAppWindow()

IF .NOT. oAppWindow:isDerivedFrom( "XbpCrt" )

oError := Error():new()

oError:description := "SetAppwindow() mora vratiti XbpCrt

window"

Page 26: Firststep to Alaska

oError:canDefault := .F.

oError:canRetry := .F.

oError:canSubstitute := .F.

oError:operation := "CrtBox"

oError:args := { nT, nL, nB, nR, cTitle, bAction }

Break( oError )

ENDIF

// DEFAULT nT TO 0 , ;

// nL TO 0 , ;

// nB TO MaxRow() , ;

// nR TO MaxCol() , ;

// cTitle TO " "

/*

*/

nRowCount := nB - nT + 1

nColCount := nR - nL + 1

nX := nL * oAppWindow:fontWidth

nY := ( MaxRow() - nB ) * oAppWindow:fontHeight

nX += oAppWindow:currentPos()[1]

nY += oAppWindow:currentPos()[2]

cColor := SetColor()

nCursor := SetCursor()

oCrt := XbpCrt():new( AppDeskTop(), oAppWindow, {nX,nY}, nRowCount,

nColCount, cTitle )

oCrt:minmax := .F.

oCrt:sysmenu := .F.

oCrt:closeable := .F.

oCrt:clipChildren := .F.

oCrt:border := XBPDLG_RECESSEDBORDERTHICK_FIXED

oCrt:fontName := oAppwindow:fontName

oCrt:fontHeight := oAppWindow:fontHeight

oCrt:fontWidth := oAppWindow:fontWidth

oCrt:create()

SetAppWindow( oCrt )

SetColor( "N/W" )

CLS

SetColor ( cColor )

SetCursor( nCursor )

SetMouse ( .T. )

oCrt:setModalState( XBP_DISP_APPMODAL )

SetAppFocus( oCrt )

xReturn := Eval( bAction )

oCrt:setModalState( XBP_DISP_MODELESS )

oCrt:destroy()

SetAppWindow( oAppWindow )

SetAppFocus ( oAppWindow )

RETURN xReturn

Page 27: Firststep to Alaska

How to use it. If you have some PRG module that have screen input or output you can do

it on our main window and CLEAR it when you finished. To be more clear you have

PART1.PRG with function part1() in it.

PART1.PRG

Function part1()

return (NIL)

change it to

PART1.PRG

Function part1()

Loacal baction:={||bpart1()}

If u_programu

Return (NIL)

Endif

Crtbox(5,5,20,50,”New title”, baction)

U_programu:=.f.

Return (NIL)

Function bpart1()

Return (NIL)

New function bpart1() is old part1(), we have change it’s name ONLY. New part1() is

add to make new window and call our old function in it. If you make this little change in

every modules you have, you will get always new window and you will control it like

you do in the past. So, you can have MANY, let’s say DOS screens. This is not realy

DOS screens, ALASKA will do the job for you so you SAY, GET functions will work in

the way you know.

As you can see, with this little change you will get NEW window when you start this

module with dimensions 15x45. Numbers 5,5,20,50 are only initial positions to MAIN

window upper left corner for new window. Remember this. After that SAY, GET

coordinate use NEW window, not the main one.

If you remember functions from main prg file in many options (p0101(),p0102()…)

example function names from modules (in p0101.prg…), edit these files and add changes

like we just said.

Page 28: Firststep to Alaska

In this way you have next window when user choose one menu option. Nice. As you can

sow you have CRT window but dimensions are under your control, so it will not be

80x25, 80x30, it can be smaller, just as you need.

Believe us, this is all you need to know and to use and your DOS application will be

NEW Windows application in very, very short period of time.

There is one another important thing that you have to remember. When you start XBASE

application it’s act as it is in NETWORK environment, SET EXCLUSIVE OFF is

default. Change it to SET EXLUSIVE ON (CLIPPER default) and there will be no

problem.

Now you can go on.