📄 g-po.gml
字号:
.chap Windows 3.x 32-bit Programming Overview
.*
.np
.ix 'Windows 3.x extender' 'programming notes'
This chapter includes the following topics:
.begbull
.if '&lang' eq 'FORTRAN 77' .do begin
.bull
WINAPI.FI and WINDOWS.FI
.do end
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.bull
WINDOWS.H
.do end
.bull
Environment Notes
.bull
Floating-point Emulation
.bull
Multiple Instances
.bull
Pointer Handling
.bull
When To Convert Incoming Pointers
.bull
When To Convert Outgoing Pointers
.bull
SendMessage and SendDlgItemMessage
.bull
GlobalAlloc and LocalAlloc
.bull
Callback Function Pointers
.bull
Window Sub-classing
.bull
Calling 16-bit DLLs
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.bull
Making DLL Calls Transparent
.bull
Far Pointer Manipulation
.do end
.bull
_16 Functions
.endbull
.*
.if '&lang' eq 'FORTRAN 77' .do begin
.*
.section WINAPI.FI
.*
.np
.ix 'WINAPI.FI'
.ix 'WINDOWS.FI'
When developing programs, make sure
.fi WINAPI.FI
is included at the start of all source files and the necessary include
files (particularly
.fi WINDOWS.FI
.ct )
are included in each function or subroutine.
.np
.ix 'Windows API'
It is especially important to get the correct function and argument
typing information for Windows API functions.
.ix 'default type'
Due to the default typing rules of FORTRAN, many Windows API functions
have a default result type of REAL when they may in fact return an
INTEGER or INTEGER*2 result.
By including the appropriate include files, you ensure that this never
happens.
.ix 'WINDLG.FI'
For example, the function
.id CreateDialog
is described in
.fi WINDLG.FI.
as a function returning an INTEGER*2 result.
.exam begin
external CreateDialog
integer*2 CreateDialog
.exam end
.np
Failure to specify the correct type of a function will result in code
that looks correct but does not execute correctly.
Similarly, you should make sure that all symbolic constants are
properly defined by including the appropriate include files.
.ix 'WINFONT.FI'
For example, the constant
.id DEFAULT_QUALITY
is described in
.fi WINFONT.FI
as an INTEGER constant whose value is 0.
.exam begin
integer DEFAULT_QUALITY
parameter ( DEFAULT_QUALITY = 0 )
.exam end
.np
Without this information,
.id DEFAULT_QUALITY
would be assumed to be a REAL variable and would not have any assigned
value.
.np
.ix 'EXPLICIT option'
The "EXPLICIT" compiler option is useful in this regard.
It requires that all symbols be explicitly typed.
.do end
.*
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.*
.section WINDOWS.H
.*
.np
.ix 'WINDOWS.H'
When developing programs, make sure
.fi WINDOWS.H
is included as the first include file in all source files.
This header file contains only the following lines:
.millust begin
#ifdef _WINDOWS_16_
#include <win16.h>
#else
#include <_win386.h>
#endif
.millust end
.np
.ix 'WIN16.H'
The file
.fi WIN16.H
is the regular 16-bit Windows header file, and is only conditionally
included for 16-bit Windows applications.
.ix '_WIN386.H'
The file
.fi _WIN386.H
contains all the prototypes and macros for the 32-bit environment, as
well as including and modifying
.fi WIN16.H.
These modifications are changing int to short, and changing the
.kw far
keyword to nothing.
These changes (that ONLY apply to things defined in
.fi WIN16.H
.ct )
cause all integers to be 16-bit integers, and all LP... pointer types
to be near pointers.
.np
.ix 'WINDOWS.H'
Other include files for Windows must be specifically requested by
defining macros before including
.fi WINDOWS.H.
This is required so that the same changes made to the primary Windows
header file will apply to routines declared
in the other header files.
.np
.begnote $compact $setptnt 30
:DTHD.Macro name
:DDHD.File included
.note #define INCLUDE_COMMDLG_H
.ix 'COMMDLG.H'
.fi COMMDLG.H
.note #define INCLUDE_CUSTCNTL_H
.ix 'CUSTCNTL.H'
.fi CUSTCNTL.H
.note #define INCLUDE_DDE_H
.ix 'DDE.H'
.fi DDE.H
.note #define INCLUDE_DDEML_H
.ix 'DDEML.H'
.fi DDEML.H
.note #define INCLUDE_DRIVINIT_H
.ix 'DRIVINIT.H'
.fi DRIVINIT.H
.note #define INCLUDE_LZEXPAND_H
.ix 'LZEXPAND.H'
.fi LZEXPAND.H
.note #define INCLUDE_MMSYSTEM_H
.ix 'MMSYSTEM.H'
.fi MMSYSTEM.H
.note #define INCLUDE_OLE_H
.ix 'OLE.H'
.fi OLE.H
.note #define INCLUDE_PENWIN_H
.ix 'PENWIN.H'
.fi PENWIN.H
.note #define INCLUDE_PENWOEM_H
.ix 'PENWOEM.H'
.fi PENWOEM.H
.note #define INCLUDE_PRINT_H
.ix 'PRINT.H'
.fi PRINT.H
.note #define INCLUDE_SHELLAPI_H
.ix 'SHELLAPI.H'
.fi SHELLAPI.H
.note #define INCLUDE_STRESS_H
.ix 'STRESS.H'
.fi STRESS.H
.note #define INCLUDE_TOOLHELP_H
.ix 'TOOLHELP.H'
.fi TOOLHELP.H
.note #define INCLUDE_VER_H
.ix 'VER.H'
.fi VER.H
.endnote
.do end
.*
.section Environment Notes
.*
.begbull
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.bull
.ix 'Windows API functions' 'Catch'
.ix 'Windows API functions' 'Throw'
The Windows functions
.kw Catch
and
.kw Throw
save only the 16-bit state.
Instead of these functions, use the
.kw setjmp
and
.kw longjmp
functions.
.do end
.bull
The 32-bit Windows Supervisor uses the first 256 bytes of the 32-bit
application's stack to save state information.
If this is corrupted, your application will abnormally terminate.
.bull
The 32-bit Windows Supervisor provides resources for up to 512 callback
routines.
Note that this restriction is only on the maximum number of active callbacks.
.endbull
.*
.section Floating-point Emulation
.*
.ix 'Windows 3.x extender' 'floating-point'
.np
.ix 'WEMU387.386'
The file
.fi WEMU387.386
is included to support floating-point emulation for 32-bit applications
running under Windows.
.ix '386enh'
.ix 'SYSTEM.INI'
This file is installed in the
.mono [386Enh]
section of your
.fi SYSTEM.INI
file.
By using the floating-point emulator, your application can be compiled
with the "fpi87" option to use inline floating-point instructions,
and it will run on a machine without a numeric coprocessor.
.np
.ix 'WDEBUG.386'
Only one of
.fi WEMU387.386
and
.fi WDEBUG.386
may be installed in your
.mono [386Enh]
section.
.ix 'distribution rights'
.fi WEMU387.386
may be distributed with your application.
.*
.section Multiple Instances
.*
.np
.ix 'Windows 3.x extender' 'multiple instances'
Since the 32-bit application resides in a flat memory space, it is NOT
possible to share code with other instances.
This means that you must register new window classes with callbacks
into the new instance's code space.
A simple way of accomplishing this is as follows:
.if '&lang' eq 'FORTRAN 77' .do begin
.code begin
integer*2 function FWINMAIN( hInstance,
& hPrevInstance,
& lpszCmdLine,
& nCmdShow )
integer*2 hInstance
integer*2 hPrevInstance
integer*2 nCmdShow
integer*4 lpszCmdLine
~b
.code break
include 'win386.fi'
include 'wincreat.fi'
include 'wincurs.fi'
include 'windefn.fi'
include 'windisp.fi'
include 'winmsg.fi'
include 'winmsgs.fi'
include 'windtool.fi'
include 'winutil.fi'
~b
.code break
external WndProc
integer*2 hWnd
record /MSG/ msg
record /WNDCLASS/ wndclass
character*14 class
~b
.code break
wndclass.style = CS_HREDRAW .or. CS_VREDRAW
wndclass.lpfnWndProc = loc( WndProc )
wndclass.cbClsExtra = 0
wndclass.cbWndExtra = 0
wndclass.hInstance = hInstance
wndclass.hIcon = NULL_HANDLE
wndclass.hCursor = LoadCursor( NULL_HANDLE, IDC_ARROW )
wndclass.hbrBackground = GetStockObject( WHITE_BRUSH )
wndclass.lpszMenuName = NULL
write( class, '(''Ellipses'',i5.5,a)' ) hInstance, char(0)
wndclass.lpszClassName = Loc( class )
call RegisterClass( wndclass )
~b
.code break
hWnd = CreateWindow( class,
& 'Application'c,
& WS_OVERLAPPEDWINDOW,
& CW_USEDEFAULT,
& 0,
& CW_USEDEFAULT,
& 0,
& NULL_HANDLE,
& NULL_HANDLE,
& hInstance,
& NULL )
.code end
.do end
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.millust begin
int PASCAL WinMain( HANDLE hInstance,
HANDLE hPrevInstance;
LPSTR lpCmdLine,
int nCmdShow );
{
WNDCLASS wc;
HWND hWnd
char class[32];
.millust break
wc.style = NULL;
wc.lpfnWndProc = (LPVOID) MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = GetStockObject( WHITE_BRUSH );
wc.lpszMenuName = "Menu";
sprintf( class,"Class%d",hInstance );
wc.lpszClassName = class;
RegisterClass( &wc );
.millust break
hWnd = CreateWindow(
class,
"Application",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
.millust end
.do end
.pc
The variable
.kw class
contains a unique name based on the instance of the application.
.*
.section Pointer Handling
.*
.np
.ix 'Windows 3.x extender' 'pointer handling'
Windows 3.x is a 16-bit operating system.
Function pointers that Windows deals with are 16-bit far pointers,
and any data you communicate to Windows with are 16-bit far pointers.
16-bit far pointers occupy 4 bytes of data, and are capable of
addressing up to 64K.
For data objects larger than 64K, huge pointers are used (a sequence of far
pointers that map out consecutive 64K segments for the data object).
16-bit far pointers are expensive to use due to the overhead of selector
loads (each time you use the pointer, a segment register must have
a value put in it).
16-bit huge pointers are even more expensive: not only is there the
overhead of selector loads, but a run-time call is necessary to perform
any pointer arithmetic.
.np
In a 32-bit flat memory model, such as that of the &cmpname for Windows
environment, all pointers are 32-bit near pointers (occupying 4 bytes of
data as well).
However, these pointers may access objects of up to 4 gigabytes in
size, and there is no selector load overhead.
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.np
All Windows defined pointer types (e.g., LPSTR) are by default near
pointers, not far pointers.
To obtain a far pointer, the far keyword must be explicitly coded,
i.e.,
.mono char far *foo
.ct , rather than
.mono LPSTR foo.
A 32-bit near pointer is the same size as a 16-bit far
pointer, so that all Windows pointers are the same size in the
32-bit flat memory model as they are in the original 16-bit segmented
model.
.do end
.np
For a 32-bit environment to communicate with Windows 3.x, there are
some considerations.
All pointers sent to Windows must be converted from 32-bit near
pointers to 16-bit far pointers.
These conversions are handled by the Supervisor.
.np
It is important to remember that all API functions which accept
pointers (with the exception of functions that accept function
pointers) accept 32-bit near pointers in this 32-bit model.
If you attempt to pass a 32-bit far pointer, the conversion will
not take place correctly.
.np
16-bit far pointers to data may be passed into the API functions, and
the Supervisor will not do any conversion.
.np
Incoming pointers must be converted from 16-bit far pointers to 32-bit
far pointers.
This conversion is a trivial one: the offset portion of the 16-bit far
pointer is extended to 32-bits.
.if '&lang' eq 'FORTRAN 77' .do begin
The pointer conversion will occur automatically when you map a
dynamically allocatable array to the memory pointed to by the 16-bit
pointer using the
.kw LOCATION=
specifier of the
.kw ALLOCATE
statement.
You must also declare the array as
.kw far
using the
.kw array
pragma.
The syntax for the
.kw array
pragma is:
.millust begin
$*pragma array ARRAY_NAME far
.millust end
.pc
where
.id ARRAY_NAME
is the array name.
.do end
Pointers from Windows are by their nature far (that is, the data is
pointed to by its own selector), and must be used as far in the 32-bit
environment.
Of course, conversions are only required if you actually need to
reference the pointer.
.np
Function pointers (i.e., pointers to callback routines) used by
Windows are not converted from 32-bit to 16-bit.
Rather, a 16-bit thunking layer that transfers control from the 16-bit
environment to the 32-bit environment must be used.
This thunking layer is provided by the Supervisor.
.*
.beglevel
.*
.section When To Convert Incoming Pointers
.*
.np
.ix 'Windows 3.x extender' 'pointer conversion'
.if '&lang' eq 'FORTRAN 77' .do begin
Whenever you wish to use a pointer passed to you by Windows, you must
map a dynamically allocatable array to the memory pointed to by the
pointer using the
.kw LOCATION
specifier of the
.kw ALLOCATE
statement.
You must also declare the array as
.kw far
using the
.kw array
pragma.
The pointer conversion will occur automatically.
.do end
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
Whenever you wish to use a pointer passed to you by Windows, you must
convert it to a 32-bit far pointer.
If you are passed a 16-bit far pointer, the macro
.kw MK_FP32
can be used to convert it to a 32-bit far pointer.
If you are passed a 16-bit near pointer (e.g., from
.kw LocalLock
.ct ), then the macro
.kw MK_LOCAL32
can be used to convert it to a 32-bit far pointer.
.do end
.np
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -