Académique Documents
Professionnel Documents
Culture Documents
User’s Manual
Jacob Navia
Logiciels/Informatique
41 rue Maurice Ravel
93430 Villetaneuse
1991-2001
Table of Contents 2
Organization of the Documentation of lcc-win32 7
Installing lcc-win32 8
Troubleshooting 9
Getting Started 10
Keyboard shortcuts 11
The Linker 56
Command Line Options Syntax 56
Command Line Switches 56
Libraries Distributed with lcc-win32 60
Other Libraries Distributed with lcc-win32 : 60
Projects 78
Configuring Wedit 83
Exporting/Importing Projects 84
Complex Projects 86
Editing Text 94
Selecting and Moving Text 94
Searching Text 94
Replacing Text 95
Goto 95
Matching Parentheses, Brackets, etc. 97
Bookmarks 97
Redefining what is a keyword 97
Wedit’s Debugger 99
Configuring the Debugger 100
Using the Debugger: The Basics 101
Switching between the Different Displays 102
Setting/Unsetting Breakpoints 103
Displaying Information about the Program 103
CPU 104
Machine Instructions 106
The Stack Display 106
The Locals Display 107
The Events Display 108
The Memory Window 108
The Watch Window 109
The ‘Auto’ Window 109
Evaluating an Expression 111
Setting Data Breakpoints 111
Calling Up the Debugger if your Program Crashes 111
The debugger configuration tab 111
Debugging Windows Programs 111
CMS 209
Changing the CMS Project Parameters 209
Get: Retrieving a Version from a CMS File 210
Retrieving all Default Versions from a Project 211
Saving a File under CMS 212
Saving All Files 213
Searching for Differences between Two Versions of the Same Module 213
Viewing all Versions of a Given File 214
Visualizing the Log Files 215
Building a Release 215
Inspecting the Stored Releases 217
Retrieving a Release 217
Advanced 225
Compiling a DLL 225
Using the Intrinsics Utility 228
The Dynamic Loader 234
Eiffel Support within lcc-win32 236
Bibliography 269
Over time, the only representation of the original knowledge becomes the code
itself, which by now is something we can run but not exactly understand. It has
become a process, something we can operate but no longer rethink deeply. Even
if you have the source code in front of you, there are limits to what a human
reader can absorb from thousands of lines of text designed primarily to function,
not to convey meaning. When knowledge passes into code, it changes state; like
water turned to ice, it becomes a new thing, with new properties. We use it; but in
a human sense we no longer know it.
Ellen Ullman
1 Ellen Ullman is the author of the book, Close to the Machine: Technophilia and its
If you have the auto-installable version, you can happily skip this section. There are no
special instructions and everything is automatic. The system installs in the ‘Programs’
menu item of the ‘Start menu’ of windows.
Depending how did you obtain the software, you can start either with a zip file, or with a
CDROM. In both cases, you should execute in this order:
In the \lcc\bin directory you should have the executables for (at least):
•Wedit.exe The IDE
•lcc.exe The compiler
•lcclnk.exe The linker
•lcclib.exe The librarian
•buildlib.exe Utility for building import libraries
•Weditres.exe Resource editor
•lrc.exe Resource compiler
•make.exe The program maintenance utility
•dolibs.exe Automatic construction of the libraries.
After the copying of the system files is finished, the lcc setup program will call the
‘dolibs.exe’ utility to build all the import libraries from their ASCII descriptions. This
saves download time, since the megabytes of import libraries are not transmitted but
generated at your machine.
Sometimes for various reasons2, the dolibs.exe utility does not work properly. In this case
you can do the work manually. Do the following:
The buildlib utility is called with each ASCII description of the import library, building
the import lib. The newly created libs should be moved to \lcc\lib so that the linker finds
them when it needs them.
The registry keys that lcc-win32 uses are stored under the key
HKEY_CURRENT_USER, i.e.; if you log in under another user ID after installing lcc-
win32, you will be forced to install it again. If you install under the same directory,
everything will work properly.
The lcc-win32 system assumes the software is under a directory called ‘lcc’. Please do
not change this name.
Another possible problem are paths with spaces in them, for instance “Program Files”. I
have tried to do my best to account for this, and the latest versions of the software should
handle those paths without problems, I have installed my own copy of lcc in Program
2 In some systems, there is an old command.com present that gets called instead of the correct win32
command interpreter. In this case, a DOS session is opened and other things fail completely. The
command can fail for lack of disk space, or other reasons.
Getting Started
To start using lcc-win32, a simple application will be used as an example. Start the editor
(Wedit), go to the Project menu, and choose Create. You will be prompted for the name
of the new project. Enter a short name, without spaces in it.3
The project definition dialog box appears. You should specify a source directory, where
your project will be built. If that directory does not exist, it will be created. Choose a
Windows application as the type of application, and press the Create button.
You will be prompted if the wizard should write the project skeleton for you. You should
answer: Yes. Wedit minimizes itself, and the wizard definition dialog box appears. You
can select several types of applications, but to get started easily, maintains all of the
default settings, and press Continue until the wizard informs you that the files have been
created. Wedit will restart, and it will make a ‘Makefile’ from the files generated.
When the ‘Makefile’ has been created, press the F9 key to compile your application. This
should go very quickly since the application is very small. Then press Ctrl+F5 to start
your new application. A window will appear with the name of the application in the title
bar.
You can debug your application by using the F5 key — Wedit’s debugger. Press F4 to go
line by line to execute the application. The F8 key is used for stepping into procedure
calls. The F4 key skips procedure calls and always stays at the same level.
You can modify the dialog boxes or other types of resources using the integrated resource
editor. Go to the Resources menu, and choose Open. This will open the resource editor in
which you can add new dialog box definitions, menus, resource strings, or other types of
resources to your application.
To define a dialog box, choose Resources, then New, then dialog box. An empty dialog
box will be created, and the resource editor will automatically bring up the properties of
the dialog box. You can then change the title, style, etc.
To populate your dialog box with controls, just select a control type in the floating
toolbar of Wedit, drag and drop it in the desired position. You can test your dialog box by
using the Test option in the Resources menu at any time. You can change the properties
of any control by double-clicking on the specified control. This also applies to the dialog
box as a whole.
Wedit has many settings for fonts, compiler configuration, links, etc. All of them are in
the Project menu, under Configuration.
If you do not want to create a project, you can load any C source file, and press Compile.
Wedit will create a default project for the Windows application if it finds a WinMain
procedure or Console application if it finds a main() function. In this case, you should
have a file that needs no other source files. You can create a project easily within a few
seconds.
Keyboard shortcuts
Key Meaning
F1 Help for a system function under the cursor
F2 Toggle breakpoint
F4 Debugger, next line, without tracing calls
Ctrl+F4 Close current document
F5 Start the debugger
F7 Set Bookmark
Ctrl+F7 Goto bookmark
F8 Debugger: Trace into
F8 Go to definition
Ctrl+F8 Show all calls to the function under the cursor
F9 Make executable
F11 Find matching brace, bracket, #endif
Ctrl+F11 Recenter cursor in the window
F12 List defined functions in current file
Ctrl+Ins Copy into clipboard
Shift+Ins Paste from keyboard
Esc Complete the word under the cursor
Ctrl+S Save
Ctrl+G Goto line number
Ctrl+Right arrow Goto next word
Alt+Up arrow History of visited functions
Alt+Left arrow Go to the last visited function
Shift+Left arrow Select to the left
Shift+Right arrow Select to the right
Shift+Down arrow Select one line towards the bottom
Shift+Up arrow Select one line to the top
• The language level. Lcc-win32 implements the C89 standard, and most of the C99
standard from ANSI. In addition, several enhancements such as operator overloading,
references, etc., make the language supported more powerful and simpler to use.
• The intrinsics. These pseudo functions allow you to access any feature of the CPU
you have inside your machine at very high speed. You can, for example, access the
extremely accurate time stamp counter, updated at each clock. You can also access
any of the new MMX instructions or test the overflow flag.4
• The runtime level. Lcc-win32 features an incorporated memory manager (gc). This
feature simplifies the programming, relieving you from memory
allocation/deallocation troubles.
• The libraries provided. Several libraries enhance the runtime: A regular expression
library, an image processing library, an unlimited precision library and several others.
Of course, you have access to all standard libraries of the Windows system and to all
of the Windows API.
• The dynamic loader. This facility allows you to load object files (.objs) as if they
were DLLs. This means you can store them in databases, etc., sparing your user the
core of building DLLs.
This features are described in detail below. It follows a description of the command line
tools, (linker compiler, etc.) and then the user interface (Integrated Development
Environment, IDE).
The Memory Manager (Garbage collector)
This part of the manual covers one of the central features of the system runtime. It
requires some basic understanding of C. If you are a beginner, skip this chapter and
remember: To get more memory, use the function GC_malloc(), and forget the rest. No
free() or other items are required.
4 Although it seem unlikely, there is no portable (ANSI standard) way of testing this flag ! Since the
language does not provide any exception for overflow, testing if overflow occurs is almost impossible
in a standard compiler.
The well-known problem with manual memory management is that it is very difficult for
a person to specify without any error when each memory block used will be destroyed
and recycled by the runtime system.
This is a task that is better left to a machine, i.e., a computer. The authors of this software
have solved the memory management problem, eliminating countless debugging hours.
There are, of course, applications where real-time requirements make the usage of the
automatic memory manager impossible. Those applications can still use the default
memory manager (a much slower solution) or devise a memory manager tailored to the
application, as all C programmers do, in one way or another.
For most applications, however, the time required for the memory manager to accomplish
its task will be unnoticeable. The authors’ years of development have fine tuned the
software. The speed of the automatic memory manager exceeds that of the standard
“malloc” implementation by a factor of greater than 10!
The development speed is another important factor. You can concentrate more on what
the program is doing and if its doing it well now without having to focus on each bit of
RAM you are using. It is no longer necessary to develop a memory manager for each
application. A DLL and a link time import library are the only requirements.
The debugging time required by manual collection must also be taken into consideration.
Problems in this area are quite difficult to locate. A memory leak or a mistake like calling
free twice can cause a long search and hours lost in the debugger, if you ever find the
problem at all. There are numerous examples of programs with this type of problem that
are never corrected: it is just too hard to follow. When the symptoms appear, there is a
crash, etc., the real problem can be far removed. Reconstructing the route from the
destroyed data to the error can take an immense amount of time.
Consider too, the realities of the lcc-win32 implementation. The malloc runtime function
furnished with the Windows system is quite possibly the worst implementation available.
When compiled for the standard memory allocator, Wedit takes 80 seconds to load an 8
MB project. This time is reduced to only 5 seconds with the collector.
You should know, however, that the memory manager requires a few simple rules to
operate properly. These rules are common sense, so they are easy to understand and
follow.
Function Description
void *GC_malloc(size_t size) ; Returns to the address of a new
memory block start. The object can
contain pointers to other objects.
5 The memory manager must be informed by the system when the program starts a new thread. The
stack of the new thread must be recorded. This is not possible with a static library. The collector data
structures are protected with semaphores, but the collector must stop all other threads to avoid being
called when a collection is not finished.
Operator Overloading
Operator overloading is a powerful feature. It gives you the ability to replace the standard
infix notation with your own, i.e., writing a+b will be understood as a function call to a
function defined by you called ‘+’. This feature has a multitude of applications. Among
these are arrays bound checking and implementation of new numeric types, etc. Its usage
has been utilized extensively in the C++ language, so many people should be familiar
with it.
Usage
Operator overloading will be considered by the compiler as an option only for user
defined types, i.e., structures. Please note that this makes it impossible to redefine the
basic types, such as int or double.
Assume then that after this definition is seen by the compiler, you write the following
code:
int example(void)
{
COMPLEX a = {2.0,0.0},b = {3.0,0.0},c;
c = a+b;
}
c = _op_plus_COMPLEX_COMPLEX(a,b);
Rules
1. All operators should have at least one argument that is a user defined structure.
2. Type conversions can be realized by defining different operators for different input
arguments. You can write several operators +, each with different arguments.
6 In lcc-win32 you can use pointers or references, and the ‘const’ attribute is not required. You can
modify the arguments to a plus operator, but that could cause problems.
COMPLEX c = a + 5.9;
and the compiler will call the right operator for you. Note that the compiler-generated
name for this operator will be _op_plus_COMPLEX_double, which differentiates it from
the preceding example.
Operator Arguments
In this table, arguments that are preceded with const should not be modified by the
operator function. This has not yet been verified in lcc-win32, but you should not rely on
this.
The column titled ‘Pointer args?’ refers to the arguments of the operator redefining
function. Can it use just pointers as argument or must it have at least one argument that is
a structure or a reference to it?
In general, operations that are defined by the C language for pointers need at least one
argument that is NOT of pointer type to avoid ambiguities in the language. When you
write
char *p = “Hello”;
p++;
should the compiler call the redefined operator ++ or just increment the pointer? There is
no way to know, so an operator ++ should never have a pointer as an argument. On the
other side, division of pointers is not defined. If the redefined operator ‘/’ uses pointers as
arguments, no problems can arise. Note that this is much more general than C++, which
prohibits an operator to be redefined when only pointers are used as arguments.
7 Note that in C++ the operator [ ] can only be redefined at the class level. Since there are no
classes here, this restriction does NOT apply.
Differences to C++
In the C++ language, you can redefine the operators && (and) || (or) and , (comma). You
cannot do this in C. The reasons are very simple.
In C (as in C++), logical expressions within conditional contexts are evaluated from left
to right. If, in the context of the AND operator, the first expression returns a FALSE
value, the others will NOT be evaluated. This means that once the truth or falsehood of
an expression has been determined, evaluation of the expression ceases, even if some
parts of the expression haven't yet been examined.
Now, if a user wanted to redefine the operator AND or the operator OR, the compiler
would have to generate a function call to the user-defined function, giving it all the
arguments of BOTH expressions. To make the function call, the compiler would have to
evaluate them both, before passing them to the redefined operator&&.
Consequence: all expressions would be evaluated and expressions that rely on the normal
behavior of C would not work. The same reasoning can be applied to the operator OR. It
evaluates all expressions, but stops at the first that returns TRUE.
A similar problem appears with the Comma operator, which evaluates in sequence all the
expressions separated by the comma(s), and returns as the value of the expression the last
result evaluated. When passing the arguments to the overloaded function, however, there
is no guarantee that the order of evaluation will be from left to right. The C standard does
not specify the order for evaluating function arguments. Therefore, this would not work.9
Another difference with C++ is that here you can redefine the operator []=, i.e., the
assignment to an array is a different operation than the reference of an array member. The
reason is simple: the C language always distinguishes between the operator + and the
operator +=, the operator * is different from the operator *=, etc. There is no reason why
the operator [] should be any different.
This simple fact allows you to do things that are quite impossible for C++ programmers:
You can easily distinguish between the assignment and the reference of an array, i.e., you
can specialize the operation for each usage. In C++ doing this implies creating a “proxy”
object, i.e., a stand-by construct that senses when the program uses it for writing or
reading and acts accordingly. This proxy must be defined, created, etc., and it has to
redefine all operators to be able to function. In addition, this highly complex solution is
not guaranteed to work! The proxies have subtle different behaviors in many situations
References are pointers that are always initialized in their declarations to some existing
object, and cannot be re-assigned to point to other objects. They will always be
dereferenced when used, so their usage differs from pointers in their syntax. The formal
description of their usage is:
Examples:
int a = 7;
int &ra = a;
This is a reference to an integer that is initialized to point to the address of the integer ‘a’.
Note that you should not specify the address-of operator, as you would do with a normal
pointer. It is the compiler that internally takes the address of the resulting object.
10 In a (rather lively) discussion in the comp.std.c newsgroup jepler epler pointed that in Python:
“The expression i = x[j] will call the method x.__getitem__(j) and assign the returned value to i.
The expression x[j] = i will call the method x.__setitem__(j, i)
I make the first out as being analogous to operator [], and the second as the proposed operator []=.”
11 This construct is needed by the problem of the operator [ ]. To avoid having the construct
Vector[5] = 6; be forced to be written as *Vector[5] = 5; or add a new operator [ ]= incompatible with
the C++ language, I decided to add the references to lcc-win32. This has ancillary benefits because in
general, references are cleaner than pointers: you can do fewer things with them. Since they always
have to be initialized to a known object, there is less room for error.
12 These rules are the same as in the C++ language.
In C++, passing arguments by reference avoids calling the automatic constructors and
destructors for the object. Since there are no destructors or constructors called
automatically here, the need for references is less pronounced. C is not C++, and there
are no functions being called ‘behind your back’ by the compiler. All implicit function
calls are those redefined explicitly by the program.
Examples:
Given
To demonstrate how to use this, a simple implementation of the “<<” syntax of C++ for
output is illustrated.
The left shift operator will be redefined with each of the basic types. Start by defining a
structure that will contain the necessary information for output.
Start defining the different types of operator << for the different types of right hand
values. The simplest is the character string.
You call fprintf with the underlying value, and put as many of the fill chars as needed to
fill the current width. Note that the return value is the structure iostream received in
input, so that several of these operators can be linked together.
Fill a buffer containing the different possible representations of an int, and then call the
previously defined operator << for strings, that will handle the width options.
Provide a function that will return a new iostream with an open file pointer as input.
Allocate the new structure with the standard “malloc” function, set the default fields, and
return it.
Hello 7
If you want to change the settings (output base say), you must manipulate the iostream
structure directly. A more elegant solution is to define a new structure that will be a place
holder. An appearance of that structure in the output stream would provoke no new
output, but a change to the settings of the underlying iostream structure. Define the new
structure as follows:
Define a structure that contains just one field: a member of the enumeration of possible
actions to perform. With this defined, you only have to add a new operator<< to assign
meaning to those structures embedded in the output stream:
F->O
f->hex = 0;
No output is performed, but the settings of the stream are changed. Use the following
program to test this:
int main(void)
{
iostream out = new_ios(stdout);
int a = 12345;
cout << "Dec: " << a << oct << " Octal " << a <<
" Hex: " << hex << a << nl;
close_ios(out);
}
See the iostream library documentation for a more detailed description of this feature and
the source code of iostream.c in \lcc\src\iostream.
Generic Functions
Generic functions allow you to specify different arguments list for an abstract function
type. This allows the programmer more flexibility in specifying the argument list for a
function.
This declares two different functions that will get an automatic name furnished by the
compiler. Those functions will be selected at the call site according to their arguments
list: if the argument list is a double, the first function will be called and the type of the
Short form:
Example:
double overloaded sqrt(double);
The compiler will supply here automatically a name for this function. The name will be
constructed from the overloaded identifier and the argument list.
Long form:
<return type> overloaded identifier . identifier ( argument-
list )
Example:
The long form allows the programmer to override the automatic name of the function and
furnish its own. This is important since it allows for easy interfacing of the software that
uses this extension with other software.
This extension doesn’t introduce a new keyword. You can still define
int overloaded = 0;
or
or even
and this will compile as you would expect. In the last example the typedef definition is
used, since overloaded functions can’t have an implicit “int” result: they must be given a
full prototype.
If you need (for whatever reason) to force the compiler to choose one of the overloaded
functions, you should use the long notation and just call the function in question:
double s = DblSqrt(4.9);
The DblSqrt function will be visible in the current scope after the “overloaded”
declaration is seen.
etc.
int example(void)
{
int a = 2,b = 3,c = 4,d;
d = a+b;
int e = d+a; // e is now declared as an int.
e += 34;
return e;
}
The scope of the identifier extends to the end of the current block. Note that this is NOT
an extension of the C language, since the new ANSI C standard accepts this as normal
usage.
#include <stdio.h>
int main(void)
{
for (int i = 0; i< 2;i++) {
printf("outer i is %d\n",i);
Note that the scope of the identifiers declared within a ‘for’ scope ends just when the for
statement ends, and that the ‘for’ statement scope is a new scope. Modify the above
example as follows to demonstrate this:
#include <stdio.h>
int main(void)
{
for (int i = 0; i< 2;i++) { 1
printf("outer i is %d\n",i); 2
int i = 87; 3
for (int i = 0;i<2;i++) { 4
printf("i=%d\n",i); 5
} 6
} 7
return 0; 8
}
Example :
int foo(int a,int b = 45,double c = 0.777) ;
The function « foo » needs always the first argument in a call, but if arguments b or c
aren’t supllied they will default to 45 and 0.777 respectively.
There are then three types of call in this example :
foo(1) ; // This is equivalentd to foo(1,45,0.777) ;
foo(1,2) ; // This is equivalent to foo(1,2,0.777) ;
foo(1,3,0.1) ;
This will still allow you to compile C++ code with minimal changes.
Creating a Stream
A stream can be created using two functions:
1. iostream_new_from_file(FILE *); This function will create a file based iostream
using the given file name.
2. iostream_new_from_string(char *,int); This function will create a string based
stream using the given character string buffer and its length.
13 The objective for this first version is just a minimal functionality, and some compatibility with
C++, but not 100% compatibility.
Examples:
Using iostreams
Below is a very simple example:
#include <iostream.h>
int main(void)
{
iostream *cout = iostream_new_from_file(stdout);
cout << "Hello" ;
cout << "world" << “\n”;
}
This example will produce the well-known words in your screen. Note that “\n” and NOT
‘\n’, is used, since single quotes are not supported. The problem is that in C, single quotes
are just integers, which will provoke the numerical value of the character to be added to
the stream instead of the character itself.
You can use the entire system without any GUI interface or even another editor, Make
utility, etc. Following is brief description of al ofl the command line switches accepted by
each utility.
If you choose to use the standard settings, however, skip this section for now. You can
perform these steps from the integrated development environment (Wedit).
In order for the utilities mentioned here to function, you must add the directory in which
the executables are saved (normally \lcc\bin) to your PATH environment variable.
Technically, this is just a convenience, but it is recommended.
Utility Function
apilist.dll Answers queries on which library exports a given API
bind.exe Binds an object file to prepare it for the dynamic loader
browsegen Builds a file with definition information for a given source file
buildlib Builds import libraries for making DLLs
buildapi Builds the list of all windows APIs in \lcc\lib\apilist.txt
dllwiz Manages the export definitions file for a DLL
dolibs Rebuilds all import libraries. Normally it runs only once when
lcc-win32 is installed, but it can be used at any time.
dynloader.dll The dynamic loader
iedit Icon/cursor/bitmap editor
f2c Fortran to C translator
gc.dll The memory manager DLL
lburg Compiler compiler. Not needed in normal operation. Only needed
if you modify the machine description of the compiler.
lc.exe Compilation driver. Calls the compiler, and if there were no
errors when compiling the source, it calls the linker.
lcc Preprocessor, C Compiler and assembler
lcclib Librarian. Used for maintaining object file libraries.
lcclnk Linker
lrc Resource compiler
make Utility for project maintenance
mc Message compiler
pedump Binary file dumper
rundos Utility to run an executable in a console window
This means that you give it all the compiler options first, then the files you want to
compile, then the options you want for the linker pass. Things in brackets are optional.
You can just use lc file.c and the driver will call the compiler without any options, as
well as the linker if all compilation steps happen without any error.
Note that you can pass to the driver an ambiguous file specification like
The “-o” option is to name the executable output file, and it is a linker option, that’s why
it is placed after the c files proper.
The driver will assume that rc files should be compiled with the resource compiler lrc,
and asm files will be assembled with lcc.
If more than one source file is given, the driver will write to stderr the name of the file
that is currently being compiled, and will echo the linker command line.
If there are errors during the compilation of any one file, the compilation goes on with
the next file, but the process will stop before the link step. The result code will be the
number of errors in either the compilation or in the linking step.
The Compiler
The technical documentation for the compiler (how it works) is described in the ‘lcc-
win32.doc’ document. Only the recognized command line options are listed below.
lcc-win32 Command Line Options
Option Meaning
-A All warnings will be active.
-ANSI Disallow the language extensions of lcc-win32: operator overloading and
references will not be accepted.
-E Generate an intermediate file with the output of the preprocessor. The
output file name will be deduced from the input file name, i.e., for a
compilation of foo.c you will obtain foo.i.
-E+ Like the -E option, but instead of generating a #line xxx directive, the
preprocessor generates a # xxx directive. Some systems need this option,
specifically some versions of gcc.
-EP Like the -E option, but no #line directives will be generated.
-Fo<file This forces the name of the output file. Normally lcc deduces that name
name> from the name of the input file, i.e., for foo.c, foo.obj, or foo.asm, or foo.i
will be generated.
This option allows you to specify another name. Please, be careful using
it, since no checks are run on the name. You can, in principle, make
careless errors, such as: lcc foo.c –Fogg.c and the output binary object
file will be called gg.c..., which is not recommended.
-g2 Generate the debugging information. Two types of debug information
will be generated: COFF and CodeView (NB09).
-g3 Arrange for function stack tracing. If a trap occurs, the function stack
will be displayed.
-g4 Arrange for function stack and line number tracing.
-g5 Arrange for function stack, line number, and return call stack corruption
tracing.
-D Define the symbol following the ‘D’. Example:
Name Description
long long Returns a long long integer (64 bits) containing the number of cycles
_rdtsc(void) that the machine has done since it was turned on. Since this counter is
automatically incremented at each cycle, to get a time in seconds you
have to divide by the clock speed of your machine. For example if you
divide the value by 166 x 1e6 you get the number of seconds elapsed
for a 166 MHz machine. This intrinsic value will use up some cycles
for converting the 64 bit value into a floating point number, so there
will be an overhead of at most 1000 cycles: at 200 MHz this should be
5 millionths of a second.
int Returns the byte swapped long integer.
_bswap(long)
double Returns sin(arg), and stores the cosine in the address pointed by cos *.
_fsicncos(arg
,cos *)
double Returns the cosinus of its argument.
_fcos(double)
double Returns the sinus of its argument.
_fsin(double)
double Returns the constant pi in floating point format.
_fldpi(void)
double Returns the logarithm base 2 of e.
_fldl2e(void)
double Returns the logarithm base 10 of e.
_fldlg2(void)
double Returns the natural logarithm (base e) of 2.
_fldln2(void)
int Returns the carry flag as an integer. This value is VERY volatile, since
_carry(void) most calculations set/unset it. You should not assume that the value
returned is the value of the last C instruction performed, since the lcc’s
optimizer could re-arrange the instructions. The best way to do this is
to write only one operation, immediately followed by an assignment
expression. For example you should write:
a = b+c;
instead of
a = b+foo(5)+78;
If you test the carry/overflow flag at the end of a complicated
expression, you cannot know the exact operation that produced the
error. Besides, since many operations change this flag, an actual
int Returns a long integer from the given double using the rounding mode
_fistp(arg) that is in effect at the time of the call. Normally this should be
rounding to nearest number, since lcc-win32 never changes this
setting. This allows for very fast rounding. Remember that to satisfy
the rules of ANSI C, lcc-win32 is forced to set the rounding to
truncation, round the figure, and then restore the original mode. This
can be avoided by using this intrinsic function to round floating point
data.
int Returns the value of the overflow flag. The same considerations apply
_overflow(voi as to the carry() function above.
d)
int Rounds the given floating point number to an integer using the current
rint(double) rounding mode. By default, the rounding mode is round to nearest
number. To use this, you should include <math.h>.
int Returns an integer with the index of the first non-zero bit in the given
_bsr(long) integer, starting with the most significant bit.
int Returns an integer with the index of the first non-zero bit in the given
_bsf(long) integer starting with the least significant bit.
Usually, it is the EBP register that points to the stack frame. This register is used to
address all local variables and arguments. When possible, and when the user has
specified the –O (optimization) flag, lcc will not build a full stack frame, but just a
minimal one, consisting only of the saved return address and the registers used by the
procedure.
14 Note that none of this identifiers can be undefined with the #undef macro directive.
15The standard gives the following definition for this:
“The identifier _ _func_ _ shall be implicitly declared by the translator as if, immediately
following the opening brace of each function definition, the declaration static const char
_ _func_ _[]="function-name"; appeared, where function-name is the name of the
lexically-enclosing function.”.
WG14/N843 ANSI standard page 45. Note that the behavior of lcc-win32 is more
lenient: the symbol still has a valid value outside a function.
Symbol Meaning
_asm(“ “); In-line assembly instruction(s).
_stdcall Call convention declaring a function that cleans
up the stack before executing the return
statement.
_try Introduces a try block in the Win32 structured
exception handling.
_except Finishes a structured try block.
__declspec Declare special. Its arguments can be:
__declspec(dllimport)
meaning the symbol following this declaration is
imported from a foreign DLL, or:
__declspec(dllexport)
meaning this symbol should be exported from the
DLL being compiled.
One line should have only one file name. This option is especially useful if you have too
many files in the command line, which is limited by Win32.
This is an ASCII_Z key that contains the full path of the libraries directory. If the linker
does not find this key, you will be prompted for it at the command line. If you enter a
correct path, lcclnk will always use it later.
Command Line Switches
-o <filename>
-reloc
This option instructs the linker to build a .reloc section. This section is a table of
relocations to apply if the executable cannot be loaded at its preferred load address. This
option is necessary under Win32s.
This option is automatically turned on for DLLs.
-dll
This option indicates to the linker that a .dll should be created instead of an .exe. The
process of building a DLL is very simple:
1. Compile the source(s) files for your DLL as you would compile normal sources.
2. Link the resulting object files using the option -DLL and provide the linker with the
names of the functions exported in a .def file that you include in the link.
3. Produce an import library using the implib utility.
EXAMPLE:
lcc mylib.c
lcclnk -DLL mylib.obj mylib.def
implib mydll.dll
The format of the .def file is as follows:
EXPORTS
Function
AnotherFunction
YetAnotherFunction
You write the EXPORTS keyword, followed by the name of each function of the DLL
you want to export (i.e., to make visible for use in another executable) in a single line.
This option is not compatible with the -s option, i.e., if you ask to strip all symbols, no
line number information can be generated.
When creating an executable with the -s option to ship to customers, it is better to do the
link twice: One with the debugging information and a mapfile; the other stripped. First
create the stripped version and then the full one. The reason behind this is that when both
options -s and -map are specified, the linker writes a smaller link file without any line
number information. If you create the full link first, and then the stripped, this smaller
map file will overwrite the good one.
Example:
-map myexe.map
-s
This option indicates that the linker should strip all symbolic and debugging information
from the executable. This means the executable cannot be debugged with a debugger, but
that its size will be considerably smaller. In addition, the linking speed is increased
because the linker has less work to do. Use this option with debugged programs if you
believe this to exist.
-version nn.nn
This option adds the version number to the executable. The numbers are the major
version number and the minor version number. A period character separates them.
Example:
-version 3.8 or -version 99.01
-x
Analyzes the symbols that are declared 'extern', but which are never referenced in any
other object in the link. There are two cases:
1. The symbol is in the .text section (code section).
Even if this symbol is not used in other modules, it can be used in the same module. The
linker cannot determine this (without disassembling the whole object file), but you can
easily check this. Declare the function 'static' and recompile your source. If it is not used,
the compiler will issue a warning.
2. The symbol is in the .data or .bss section.
This is a data item and it is surely not used. Delete it from your source.
errout=<filename>
The regular expressions library. This library, developed several years ago by Henry
Spencer at the University of Toronto, implements the functions needed to compile and
execute a regular expression and apply it to a character string. The library is called
regexp.lib, and the include file is regexp.h.
The arbitrary precision library. This library defines the « bignum » data type. Bignums
are numbers of arbitrary precision that can be used instead of integers or floating point
numbers. The documentation for using this library is in Appendix 3. The include file is
« bignums.h » and the library is « bignums.lib ».
The GNU GDBM library is a hash based (key) database package that allows you to
associate arbitrary data with a key. To see the complete documentation for this package,
go to the index in the “Help” tab of wedit, and then click in the GDBM link.
The zlib2 compression library is distributed with the examples/CD-sources distribution.
This library allows you to compress data, so that it uses less space but keeping the same
information (without looses).
The Berkeley DB library is distributed in a separate file with sources (lccdb.exe)
The resource compiler receives an .rc file as input that is written in a special language for
describing resources. It will produce a binary file as output with the .res extension that
can be used with the other object files by the linker to build an executable.
Usage:
lrc [options] .RC input file
Switches:
Option Meaning
/r Build a .res file. This is assumed, so this option is there just for compatibility
with earlier versions of rc.
/v Verbose output
/m Build a map file. The name of the map file will be the same as the output file
with a .map extension.
/dSYM Define symbol. This is for Lrc's pre-processor.
/ofile Write the output into <file>. No space should be left between the o and the name
of the file.
/fo Same as above.
/l Default language number follows in hexadecimal.
/I Add an include path.
/p Print in the standard output a list of file dependencies of the given input resource
file.
Option Description
/A Includes everything in the output. All sections, all data dumps, etc. The
code sections will be disassembled and if debug information is available,
the line numbers will be annotated in the resulting output.
/D Dumps the code view or gcc debug information. This option supports the
NB09 Standard from Microsoft, and the STABS format from gcc.
/E Dump the resources section.
/EXP If given an import library, pedump will generate a list of the exported
functions in a format suitable for the buildlib utility. See FAQ question 12
for further explanation. If given a DLL, pedump will print a list of the
exported symbols from the DLL, in the same format. If given an object
file, this option will trigger pedump to print a list of all public symbols
defined in the object file, in the same format.
/functionsize Will produce a table of all functions defined in the object or executable file
sorted by their size in bytes. The executable should have a symbol table
(debug information should be present).
/H Includes a hexadecimal dump of the sections in the file.
/HEX Dump contents in hexadecimal form, without any concern for structures in
the file. This allows you to dump any type of file.
/L Includes line number information.
/OUT:file Prints the output into <file> instead of standard output. If the given file
name contains spaces it should be enclosed in quotes.
/REL Shows the relocations.
/R Shows the resources in an executable.
/SUMMARY Shows the sizes for the main parts of the file only.
/S Dumps the symbol table. All the symbols are dumped with all the details.
SYNOPSIS
f2c [option ... ] file ...
DESCRIPTION
F2c converts Fortran 77 source code in files with names ending in `.f' or `.F' to C source
files in the current directory, with `.c' substituted for the final `.f' or `.F'.
The lcc compiler is invoked if the compilation finished without error and an object file is
generated in the current directory.
If no Fortran files are named, f2c reads Fortran from standard input and writes C on
standard output.
File names that end with `.p' or `.P' are taken to be prototype files, as produced by option
`-P', and are read first.
The following options have the same meaning as in other Fortran compilers.
-C Compiles code to check that subscripts are within declared array limits
-Idir Looks for a non-absolute include file first in the directory of the current input file,
then in directories specified by -I options (one directory per option). Options -I2 and -I4
have precedence, thus a directory named 2 should be specified by -I./2.
-onetrip Compiles DO loops that are performed at least once if reached. (Fortran 77 DO
loops are not performed at all if the upper limit is smaller than the lower limit.)
-U Honors the case of variable and external names. Fortran keywords must be in lower
case.
-u Makes the default type of a variable `undefined' rather than using the default Fortran
rules.
-w Suppresses all warning messages, or if the option is `-w66', just Fortran 66
compatibility warnings.
The resulting C invokes the support routines of f77; object code should be linked with
lcclnk specifying libf77.lib at the end of the command line. Wedit will automatically add
this library when any of the project files end with .f.
FILES
f2c.h This file is used by the generated C code. It should be in the \lcc\include directory.
libf77.lib This file is the runtime of the Fortran system. It should be in the \lcc\lib
directory with all other libraries.
f2c.exe The is the compiler itself. It should be located in the \lcc\bin directory together
with all other executables.
DIAGNOSTICS
The diagnostics produced by f2c are intended to be self-explanatory. lcc-win32 will not
generate any warnings when called from f2c. The resulting C file can be invalid,
however, this provokes an error message from lcc-win32. This happens when you do not
adhere to the prototypes given or you have an error in the calling sequence: you are
calling a subroutine with different numbers of arguments within the same program. The
error issued by lcc-win32 follows the warning of the Fortran compiler.
BUGS
Floating-point constant expressions are simplified in the floating-point arithmetic of the
machine running f2c, so that they are typically accurate to, at most 16 or 17, decimal
places.
Untypable EXTERNAL functions are declared int.
The browsegen Utility
This utility is a modified version of the compiler that will produce a browse file
containing the position in the given source file or its included headers of the symbols
used. The format of the generated browse files is described in the technical
documentation. Use this utility only if you want to build browse information for use in
another software. Normally, this utility is only used by the IDE (Wedit) to answer
queries. A more detailed description of how it works is found in the technical
documentation.
Option Description
-P or –P1 Will write all the prototypes for the public (i.e. not static) functions defined
in the module.
-P2 Will write the public prototypes and data definitions for the given module.
-P3 Will write the prototypes for both the public and static functions, and the
public data dependencies.
-P4 Will write the public and static function prototypes, and the public and
static data definitions.
Note that only definitions at the global level will be written. Local or external variables
will never be written.
The buildlib Utility
This utility reads an ASCII description of symbols and produces an import library that
allows you to link your executable with a specific DLL.
It has no command line options and the input arguments are as follows:
The first argument has to be a text file that contains the list of symbols to be built into the
library; the second argument is the name of the library.
Normally, the extension used in lcc-win32 for this textual description is .exp. See the
directory \lcc\buildlib for numerous examples of these file types.
First line: Name of the DLL this import library should bind to. This is mandatory.
All other lines have a column format with 1 mandatory column and two optional
columns.
The first column should contain the symbol name as emitted by the compiler, i.e., with all
decorations, such as leading underscore, and '@nn' decoration for _stdcall symbols.
The second column is optional. It indicates the name of the symbol as it is exported from
the DLL. This can be different from the decorated form. For example, you may want to
The third column is also optional, consisting of a single keyword 'data'. If present, this
means that the exported symbol is not a function, but a data item, i.e., a variable.
The lcclib Utility
The purpose of this utility is to build library files (.lib) from a list of object files. The
general format of the command line is:
Options:
Option Meaning
/out:libfile.lib Specifies the name of the output library file.
/extract:<object file> Extracts the specified object file from the library.
/remove:<object file> Removes the specified object file from the library.
/verbose Progress report will be printed to standard output.
IMPORTS
CRTDLL.dll
_fprintf fprintf
USER32.dll
_LoadLibrary@4 LoadLibrary
...
$$END$$
In words: The list starts with the keyword ‘IMPORTS’, followed by a DLL list. Each
DLL starts with the name, followed by the imported functions from that DLL in the
object file.
Usage:
The syntax is:
bind <file name>
This will read the corresponding C input file and merge it with the assemble file
input.asm, producing a merged « MergedOutput. asm » file.
Argument Meaning
/prj : project-name Opens « project-name » at startup. This name should be a
valid project already created in previous sessions. Example :
Wedit /prj :parser
This opens the « parser » project.
/f Opens no projects or windows.
/w Opens no projects or windows and does not show the startup
banner.
executable-name Starts the debugger and debugs the executable named in the
more args command line. Passes all further arguments to the program
that will be started. For instance, if you want to debug foo.exe
with arguments silent and fast, write :
Wedit foo.exe /silent /fast
Note that the .exe extension is mandatory.
The Main Menu
To know the purpose of any menu option in Wedit, open the menu and run the mouse
over each item. A short explanatory text will be shown at the lower right of Wedit’s
window.
Following is a description of all menu entries:
• File: Opens and closes files, renames or saves the current file, opens or closes a
project.
Item Description
New Creates a new text file, a new Wedit window, or a new project.
Open Opens an existing file.
Open binary Opens an existing file and calls the binary editor to edit it.
Insert a file Inserts a text file at the current cursor position.
Save Writes the current document to disk.
Save as Renames the current document and writes it to disk.
Save all Writes to disk all modified files.
• Edit: Text manipulation including moving blocks of text, reformatting the current
document, inserting a file, and other commands.
• Project. Project-related options (reading, opening, creating, modifying, etc.) and the
general configuration wizard.
Configuration All the configuration options for the compiler, editor, debugger, linker,
help files, etc.
Create Starts the creation of a new project.
Open Loads an existing project.
Close Closes the current project.
Erase Erases a project you choose.
Add/Delete Inserts or deletes files from the current project.
files
Import Allows the user to browse for a project file (with the .prj extension),
and loads it into the projects list. This closes the current project (if
any).
Open all files Opens all the files defined in the current project.
Workspace Shows the modules of the current project. You can add/delete
modules, switch from one source file to the next, and many other
options. You turn on those options using the right mouse click.
After this entry All user-defined menu commands, added with the add utility option in
the configuration tab, start at this point.
• Debug. This menu option appears when the debugger is active, in the place of the
compiler menu, assuming you do not compile when the program is being debugged.
• Utils: Several help programs such as diff, generating a hypertext file from a
program file, information about variables, structures, etc.
• Analysis. These commands allow you to browse or get other information about a
specific file or about the project as a whole.
Import foreign Allows the user to read a dll import library in the Microsoft format,
library and transform it into a library in the lcc format.
• Versions: Versioning system. Get, put, seeing revisions, maintain CMS files and
in general all versioning options.
• Window: All loaded files are listed here.
Wedit has a status window at the bottom. Here, you can see the output of different things:
GREP, make, the debugger, the locals display, etc. This window can be shown using the
button at the lower left of Wedit, or hidden, using the same button. At the bottom right,
you will find the current function for where the cursor is located, if any, and the current
line and column number.
The list in the output window is a ‘dockable’ window. You can detach it from the main
Wedit window, and so that it becomes an independent floating window that you can place
anywhere in the desktop.
To force this window into its home position, just double-click in the window’s title bar.
C language keywords are displayed in blue, commentaries in light green, text in black.
You can alter these colors as desired using the corresponding option in the Configuration
property sheet. Lines that are bigger than the display window are finished with a white
square. The name of the current function, the line number, and the current column are
displayed at the lower right corner of Wedit’s window. If the file has been modified, an
asterisk will be added after the column number.
There is no horizontal scrollbar. Click near the vertical scrollbar and the screen will
move to the left, click at the opposite side and the screen will move right.16
You can make Wedit show you the braces level by choosing the ‘Level’ option in the
‘Edit’ menu. A column with the level of each line appears at the left. To make the ‘level’
disappear just choose the same option again.17
16 An horizontal scrollbar takes at least one line of text away from the display. No matter how big
your screen is, there will be always a shortage of space. A 'virtual' scrollbar as implemented in Wedit
has the same functionality but takes zero lines of text to show!
17 This is useful to see where your are missing a brace.
If you have made changes and want to discard them, the fastest thing to do is to choose
the ‘Reload’ option in the ‘File’ menu. This will reload the file from disk, disregarding
all changes.
If you want to see what changes you have made to a file, use the ‘Show changes’ option
in the ‘Edit’ menu.18
To display two files side by side, use the ‘Disposition’ option in the ‘Window’ menu.
You can position the files side by side vertically or horizontally.
The button at the lower left corner is used to show/hide the output window. This window
can be detached and moved freely around by clicking in the bands of free space between
the output window and the borders. In addition, its height can be arranged by moving the
slider in the middle. To do this, press and hold your mouse button for more than one-half
second when the mouse is over the slider. The slider window will then be ready for
resizing. It will show a horizontal bar that can be used to adjust the height of the output
window.
Pressing the right mouse button above the area of the output window will bring up a
contextual menu. With this, you can save the actual contents in the output window to a
file.
18 This option just saves the current file in a temporary file, and invokes the 'diff' utility.
The object files and the executable are placed by default in a directory named 'lcc' under
the sources directory. For instance. if you use the directory c:\myproject for the sources,
the output of the compiler will be placed in a directory named 'c:\myproject\lcc'. This
method is not obligatory in this version, but it was in earlier versions of Wedit. Still, it is
better (as always) to use the defaults.19
Avoid placing two completely unrelated projects in the same directory. The makefiles
would be erased and several object files could be lost. For example, if you have a file
called main.c in two projects, the object files of both projects would be the same and the
linker would be confused.
Four types of projects are supported:
1. Windows executable. This means that your program will start at the ‘WinMain’
function, that it will not use the standard input or standard output functions and that it
will not use the ‘console’ window.20
2. Console application. This means that your program uses ‘printf’ and assumes, for
example, that stdin and stdout are initialized and it will appear in a text mode window.21
3.Static library. This means that you want to create a library containing a set of object
files. This library is linked statically, i.e., each executable will contain its own copy of the
routines in the library.
4.Dynamic link library. This means that you will create an executable that is
dynamically attached to another process when the other executable starts.
19The current directory can be determined easily: just go to the configuration menu option. In the
‘General’ tab, you will find what the current directory is.
20Of course windows program can open an own console if they wish to. This refers to what is present
by default at the program startup.
21 Again, console programs can use any window API. The system opens a console for them by default
at the program startup, that’s all.
Here you should enter the names of all files that will create this project. You can enter
them quickly if you click on the ‘Add all’ button.
If your project uses special libraries, add them to the project files here. For instance, if
you want to use the Windows sockets primitives for network programming add
ws2_32.lib. You can enter the library without a path. If no library is found in the current
directory with the name you typed, Wedit will search in the system \lcc\lib directory, and
determine the path for you.
If you are building a Windows executable, you should add your resources, either by
adding a .rc file or a binary .res file. Use the combination box with ‘List files of type’
header to choose the different files that you want to add to the project.
When you have chosen all the files, click the ‘Validate’ button and the following dialog
box will appear.
This dialog box lets you change/add/modify the settings for the compiler, choose the
level of debugging support, etc. This will be explained in full in the corresponding
chapter. This is the same dialog box that you reach from the ‘Configuration’ tab in the
‘Options’ main menu. It is just displayed differently.
This is the first of a series of three dialog boxes that the system presents to you in the
event that you want to modify some of the settings at the start of a project. Choosing the
‘Next’ button allows you to continue.
This is a good place for adding the #defines that your project may need or a special
library that is not included in the default libraries. By default, the compiler will start the
project with a debug setting (debug information turned on, optimizations off), but you
can also change this here.
The next two dialog boxes (shown later in the ‘Compiler’ chapter) concern the linker and
the debugger settings. Once finished with the settings, Wedit will generate a Makefile for
your application using the available information.
The project is then ready. You can compile and execute your application. You should
wait, however, until Wedit finishes generating the Makefile for your application. This
This option allows you to change the current project. All open files will be closed and the
current project will be saved. The windows with the files of the new project will be
opened as you left them the last time you worked in them.
To open an existing project, click in a project and Wedit will open it. When Wedit opens
a project, it will hide the main window to accelerate the file loading time without any
unnecessary repainting. You may be concerned that Wedit has crashed/disappeared if it
takes a long time to open. This is not the case.
You can open several projects by checking the button at the bottom of the dialog box. If
that button is checked, Wedit will open a new window with the new project instead of
closing the current project and opening a new one.
When you have a project file and you want to add the project to the list of your projects
you can use the « File Æ open » menu option to open the project file and automatically
read-in the project description.
22 It could be argued that calling the compiler for this is an overkill, and just scanning for #include
statements would suffice. The problem is that #ifdef ... #endif statements, that need to be processed in
order to know which files are actually used by a source module.
Here you can customize several options, such as the what an editor will do at a new line
(indentation or not), which font to use, whether or not a backup copy should be made, the
language definition, etc.
HKEY_CURRENT_USER\Software\lcc\Wedit\<project name>
You can ask Wedit to write all the values of all the keys of a given project with the
‘Export’ option in the ‘Project’ menu. The values will be written into a file called
<project name>.prj, in the project’s sources directory. This file will be used by the
corresponding ‘Import project’ option to read all the values into the registry.
If you are moving a project from one place to another on your disk or to a different
machine in another context, you can edit the paths in this file so that they correspond to
the configuration you changed. For instance, if you move a project from drive
D:\projects\work to drive K:\shared\lcc, you should edit the paths in the generated text
file to reflect this new configuration.
The keys used by Wedit are:
These options allow you to modify the fonts and the colors used by the editor.
The purpose of this tab is to allow you to define simple macros using the keys Ctrl+’A-
Z’, which will insert the desired text at the current position.
You must supply Wedit with the following information:
1. The letter (a-z) that will be used for the macros. This is entered in the small square at
the top.
2. The replacement text you want introduced at the current position when this macro is
used.
3. When you have entered the information in both fields, press the ‘Add’ button to enter
the new macro into the list of defined macros.
For example, if you want the macro Ctrl+i to represent
i = MyCurrentStructureWithLongName[MyCurrentIndex]
you would enter ‘i’ in the box, and the contents in the edit field below, then press the add
button. This creates the macro.
Wedit constructs implicit links between symbols in your source files as you edit them. It
records where functions are defined, where structures are used, and other 'important
places'. It can show you the definition of symbols by pressing F8 .
Information can be displayed in several forms, according to their type: variables,
structures, functions, globals, locals, etc.
Press and hold down the right mouse button to recall the definition of any symbol under
the mouse pointer. A contextual menu appears, showing you the different options
available. The different options are:
• Definition. Wedit will show you where this symbol is defined.
• Usage. Wedit will show you where this symbol is used in the current file. Comments
and character strings are ignored.
• Documentation. Wedit will call up the Windows help with the given symbol. You
should use this with symbols that are documented in the windows API.
If you click with the right mouse button where no symbols are defined, Wedit will show
you the following options:
• Globals. This will show all global variables in the given file.
• Functions. This will display the list of all functions defined in the current file.
In addition to these options, the following options are always available, regardless of
where you clicked:
• Metrics. This will show you the software metric measurements for either a symbol or
the whole file.
• Edit description. This will prompt you with the standard function description dialog
box.
• Properties. This will show you the exact path of the current file.
If you right click on include statement, Wedit will automatically open the included file. If
you right click on an ifdef, a new item will appear prompting you to bring the cursor to
the matching endif. The same occurs if you right click on an opening or closing brace.
If you right click on a function definition, Wedit will prompt you to show the local
variables of the function. This allows you to see slices of the function’s code by variable.
If you click on the name of the function with the right mouse button, a menu appears in
which you can to see some information about that function. If you double-click on a
function name, the cursor will be positioned at the beginning of that function's definition.
The ‘Options’ menu allows you to open the file from the definition and puts the cursor at
the beginning of the definition. You can also print the contents of the structure.
The ‘Files’ combo box shows you which files use the symbol, the ‘Functions’ combo box
shows you which functions use it. You can change the context displayed by clicking in a
line from the main list box.
Searching for a Function
This option is complementary to the preceding one. It is useful when you are uncertain of
the function name you are searching. To search using regular expressions, select the
"Function" option from the "Search" menu.
The following dialog box appears:
The list of all functions defined in all loaded files appears at the left, sorted by name. If
you double-click on a function name, the dialog box will close and the cursor will be
placed where the function is defined. The prototype of the selected function is shown at
the lower right.
If you double-click on the list of files in the center-right, Wedit will open a new list with
all of the functions defined in that file.
You can indicate a filter in the entry field at the center. This filter can be a regular
expression. After the filter is applied, if any functions are found, they will be shown
within the list of selected functions. For instance, to find all functions that begin with a
capital 'C', the regular expression will be "^C.+"
The ‘Include *.c’ button at the upper right instructs the search engine to look for all files
in the current directory (that end with .c) and not only in the loaded files.
This dialog box does not use the information in the file. If you have just written a new
function and you have not yet saved the file, this dialog box will also accurately show
you the new function.
To go to the function definition, select the desired line from the list.
The small entry field at the right allows you to enter the function name if you know it.
You can sort the functions by occurrence in the input file or by name.
Since the #ifdef / #endif are not taken into account, the same function can appear several
times. In addition to this problem, the assumption here is that there are no fatal syntax
errors in the text of the file being scanned. Most syntax errors will not affect this option,
except unbalanced brackets, unfinished commentaries, or similar syntax errors.
23What a symbol is depends on the programming language. To avoid overloading the language definition
with heavy syntax, only letters, digits, and the underscore are used as symbols. This will fit most languages
except Common Lisp, where you can define symbols containing almost any combination of characters.
The user interface is simple: Type in the text and the replacement text, then press the
Replace button. The search expression can be a regular expression. If this is the case, do
not forget to select the corresponding option in the Match group box.
Possible options are:
• Use of a confirmation dialog box or if Wedit should replace all matches globally
without confirmation of each occurrence.
Goto
The Goto option from the search menu leads to the following dialog box:
This option allows you to move the cursor within the current file. Top and End place the
cursor at the beginning or at the end of the file, respectively. Line is used to move the
cursor to a specific line. You can skip the subsequent dialog box if you enter a line
number in the corresponding entry field at the lower right corner of the ‘Goto’ dialog
box.
You can reach this dialog box by selecting the
‘Goto’ option in the ‘Search’ menu bar. A dialog
box will show you several options, you choose
‘Goto line’. Or you can press the keys Ctrl+F12
and you arrive directly.
Ctrl+F12
You can add or delete keywords. To add a keyword, type it in the entry field and press
the 'Add' button. To erase a keyword, select it from the list first, and then press the
'Delete' button.
The debugger allows you to follow the program execution and to examine values at
runtime. There are two ways to start it.
•Press the F5 function key. If you have built a project, the executable will be started
automatically, or
•Use the File->Open menu option, and enter the name of an executable that you want to
debug. From the command line, you can specify to Wedit the name of the program to
debug. If the file given has a .exe extension, Wedit will assume you want to debug it and
will start.
If it is not a .exe file, the following dialog box appears:
You reach this dialog box when you open an executable using the ‘File’ and then ‘Open’ menu option.
You can enter optional command line parameters here or cancel the whole operation.
The executable started should contain the debug information. If it does not, you should
recompile it with the debug information turned on. This is specified in two place: The
compiler tab of the configuration property sheet and in the linker tab. The first one
specifies that the object files should be generated with debug information; the second
specifies to the linker that the debug information should be included in the executable.
If functioning properly, the program to be debugged is started and execution stops at the
‘main’ or WinMain function.
Please note that you must write the extension: foo.exe. Writing only « foo » will not
work.
Configuring the Debugger
You can configure the debugger with the following tab in the ‘Configuration’ wizard.
When building a DLL project, enter the name of the executable that will call up the DLL.
This executable should have debug information and be linked with the DLL to debug
statically. If the executable runs a LoadLibrary, instead of being linked with the DLL
statically, Wedit’s debugger will not be able to restore the breakpoints you set, since the
debugger cannot know in advance which DLLs are going to be loaded at which address.
There are several options for controlling the program execution of the program you
would like to debug:
• Same level (F4). This means that the debugger will run the program until it reaches
the next source line. If the current line contains a function call, it will be skipped. You
remain on the same level. If you reach the end of the function, the line where the function
call was implemented will be displayed. This is not possible in all cases — specifically if
your function is a Windows callback, it was called up by the operating system. You
cannot step through system code, so the debugger will stop when control reaches one of
the source lines of your program again.
• Step in (F8). This means that the debugger will run the program until it reaches the
next source line. If there is a function call in the current line, the debugger will try to see
if it has debug information for the function in question. If yes, execution will stop at the
first line of that function. If that function does not have any debug information, the
debugger will arrange to skip that call. In cases where the function calls one of the
procedures of your program indirectly, the debugger will stop when control reaches the
next source line of your program. A SendMessage call is one example of this. This
function will call the callback procedure for the window that can be in your program. In
this case, the debugger will stop at the beginning of the callback procedure.
• Step out (F9). This means that the debugger will run the program until it exits the
current function and place a stop at the calling function. The same rules apply as in the
return from a procedure explained in Same level above.
• Run to cursor (F7). The debugger will put a temporary stop at the indicated line and
pass control to the program being debugged. If control reaches the indicated line, the
debugger will stop. If not, the program will continue normal execution. Be careful to
ensure that control MUST reach the line you indicate with F7.
• Set a breakpoint (F2). This will set a breakpoint at the indicated line.
• Unset a breakpoint (F2). If the line that is under the cursor contained a breakpoint,
that breakpoint will be deleted.
• Break. This makes the debugger stops the program under debug, no matter where it is.
• Stop debugging. This stops the execution of the program under debug, and closes the
debugger.
• Set next statement. This can be reached through the right mouse button menu. Using
this feature, you can skip several lines of code in the current function, or return
backwards to retrace the execution. Note that you can make the program fail if you set
the next statement where it would use variables that were initialized in a piece of code
that you just skipped. The debugger cannot undo what the program has done, when you
reset the current line to some line before the current one. If the program opened, closed,
or deleted files, for instance, the debugger does not undo those actions.
• Set next instruction. When the ‘Machine instructions’ window is open, you can move
the program counter explicitly to a new location by pressing the right mouse button
anywhere on that window. A contextual menu will appear, prompting you to change the
program counter to the selected line in the ‘Machine instructions’ window. To do this,
choose this menu item and the program counter will be set to that location.
Setting/Unsetting Breakpoints
To set/unset a breakpoint, press F2. This will toggle a breakpoint at the line where the
cursor is located. If you are in the debugger, a breakpoint symbol is shown at the left
side of the affected line.
You can also edit the current breakpoint list using the ‘Edit breakpoints’ dialog box,
which can be called up from the debugger menu.
In this dialog box, there is a list of all functions defined in the running program at the left
side. To set a breakpoint in any of these functions, double-click on the large list box at
the left side of the dialog box. Note that this enables you to set a breakpoint at any
function, even those library functions where there is no source file associated with them.
For instance, to set a breakpoint in the library function ‘printf’, double-click on its name.
This is the only way to specify a breakpoint in these functions. F2 will not work here
because there is no source file associated with that function.
You can specify a source file and a line in the “New breakpoint” edit field. This is
enabled only when the debugger is active.
To specify a breakpoint that will be skipped <n> times before it stops the program under
debug, double-click on the breakpoint you want to modify. Then enter the number of
times to skip in the dialog box that pops up. This feature is active only when the
debugger is running, and the settings will not be saved between debugging sessions.
The second set of machine registers are the FPU registers and their associated flags.
The third set of registers is the mmx registers. Use this set only if you use the MMX
intrinsics and your machine is an MMX machine.
This menu option opens or closes the ‘Code’ display. This will display the assembly codes for
the function currently being executed.
If you click in this window with the right mouse button, a contextual menu will appear that
allows you to mix C code with assembly instructions (the ‘Source annotation’ menu option) or
display the code bytes, i.e., the exact instructions without decoding by the disassembler. When
this window is open, you can reset the program counter to any desired location within this
window. Choose the ‘Set next instruction’ menu item from the contextual menu. This menu
appears when you click anywhere in this window with the right mouse button.
If you are interested in the exact code bytes that are stored and not just their mnemonics, you
can view the hexadecimal numbers shown at the left of the assembler mnemonics.
When the ‘Code’ window is open, the debugger will single step through each assembler
instruction instead of single stepping through each line of the source program.
Note that ‘MainWndProc’ is a callback procedure. You can determine this because
USER32.dll and ntdll.dl appear as active in the stack. Note that the user function
‘InitializeApp’ is also active. This is the normal case for processing a WM_CREATE
message. When you call up CreateWindow, this function sends a WM_CREATE message to
the window procedure before returning to the caller.
You can view the code of any active stack procedure by clicking on the corresponding line.
Note that you should click on a function name and not in the parameters. When you click on a
function name, the debugger will bring that part of the source code into view.
The Locals Display
This window will show you the local variables of the function currently being executed.
The symbols marked with a ‘+’ are structures, unions or tables, i.e., aggregates.
The ‘Events’ window shows you the threads that the program has started, the DLLs that
were loaded/unloaded on the program’s behalf, etc.
The debugger will show the output of the ‘OutputDebugString’ Win32 function in this
window.
If your message uses the Win32 API function ‘OutputDebugString’, all debug strings will
be displayed in this window. Note that this does not trigger a breakpoint.
Here, the exact sequence of actions when a trap occurs will be displayed, if there is a
problem with the debugger.
A DLL is loaded. The
debugger displays its name,
the file handle for the
executable, the base of the
DLL code, the offset to the
debug information (if any),
the pointer to the DLL
name, and whether or not it
is a Unicode DLL.
The OutputDebugString
event is received. The
debugger is currently unable
to understand the
undocumented formats that
are used by Microsoft’s
DLLs. Further investigation
of this may produce a more
interesting display here.
Normally a character string
should be at the address
pointed to by
lpDebugStringData, but this
is not the case for system
DLLs.
The memory window allows you to explore the contents of memory at a specified address
or variable name.
This window allows you to open a secondary watch window where the contents of a
variable can be displayed permanently. The debugger will evaluate the contents of the
field at each stop.
A box opens asking you which variable you want to watch. Enter the name of a watch
and press return.
To erase a variable from the watch list, press the ‘delete’ key. To add a variable, press the
‘insert’ key. Remember to first click in the watch window so that it receives the focus. As
of this release, only simple types are supported, i.e., if you have a structure with an
integer field, type struct->field into the watch window input.
The watch window looks like many other windows in the debugger:
This window tries to display the values that may be of interest from each line of the
source code that is currently being executed.
For instance, for the following source lines:
At this stop in execution, the variable window will display the following:
The preceding line and the current lines are scanned for identifiers, and the values of all
such identifiers are displayed. In addition, the return values of all functions called are
shown. This is very simple: Wedit’s debugger scans the current line and the preceding
line, eliminates comments and character strings from them, and scans all identifiers that it
can find. The debugger and the results shown evaluate this list. In addition, each time a
function call is found, its results will be stored and displayed in the ‘Auto’ window.
The profiler is a utility that allows you to see where your program is spending its time. It
operates by starting a special debugging session in which the debugger interrupts the
running program approx. 1,000 times per second. When the debugger stops the program,
it checks what the program is currently executing and records each source line/function
that corresponds to the current program counter (EIP).
When the program finishes running, the debugger assembles the information it has
gathered into a report in which each function that was interrupted is shown with the
number of hits it had.
The logic behind this method is that the longer a function executes the higher the
probability that the debugger will interrupt its execution. Since this is a statistical
approach, the longer the program runs, the more accurate the information of the profiler
will be. Short runs can introduce errors because the chance factor is higher. Longer runs
provide a more reliable report.
When measuring a program’s execution, you should run several profile sessions before
using the data.
To start a profiler session, you should compile the program with the debug information
ON of course. Use only the lowest debug level (g2). Other debug levels will introduce a
skew in the data, since they affect the program’s runtime behavior. For instance, if you
set the debug level to g3, at each procedure call, the program will record the name of the
procedure in the stack, making procedure calls more costly, skewing the data seen by the
profiler.
The profiler report will be loaded automatically into the editor. You can save it or rename
it as you would do with any other text file.
During the profiler session, the debugger’s main window will appear. Do not use it
because the profiler session could be stopped or slowed down, rendering the data useless.
In the first line, under ‘Preprocessor’, enter the symbols you want to define for all
compilation units. Wedit will append a –D to each definition that should be separated by
commas or spaces and pass these options on to the compiler.
For code generation, you can:
• Generate the assembler listing of each source.
• Turn optimizations on or off.
• Generate the browsing information always when compiling. This is not very
productive, since Wedit will generate this information on an ‘as needed’ basis. Setting
this option will slow your compilation, but may speed up later searches.
• Use Pentium Pro instructions or not. Note that if you check this button, the compiler
will generate a program that will not run in a machine that does not have these
instructions, for example, an old 486.
You can change the name of the output file, for instance, to place your binaries in
different directory, instead of the default directory.
In the additional libraries tab, enter any libraries that are not included by the linker as a
default.
You can instruct lcclnk to generate a map file with the addresses of all symbols used by
your program by checking the corresponding box. If you are building the executable to
For simplicity’s sake, not all the linker options are displayed in this tab. You can read the
lcclnk command options for the command line at the beginning of this document and add
any option you consider useful in the corresponding edit field at the bottom of this tab.
This sub-system allows you to visualize a file in binary mode. The bytes in the file are
displayed without taking into account any line records.
You reach this utility from the File -> open binary menu option.
• A column at the left indicating the offset of each field relative to the beginning of
the structure.
• A 'Type' column that indicates the length and the representation used for this
field.
• The data for this field. Note that only the first few characters are shown.
• You can display the data either in decimal or hexadecimal form.
To add a field to the structure proceed as follows:
1. Choose the 'Add' menu option. This will open the following dialog box.
A line whose length is proportional to its length or volume, depending on the settings of
the ‘Data’ menu selection represents each function in the file. To see to which function
This option allows you to visualize only the lines of the function that contain the given
identifier. It is designed to show more clearly the evolution of the contents of a variable
and to easily identify if there is a problem. If the first line does not contain an assignment
An external symbol in this context means all the identifiers that are not defined as locals
or arguments. This includes the #define statements that the function uses and the names
of all typedefs used. This does not correspond to a strict C external definition, but rather
to the importation of names and to the dependencies created by this importation.
It is simple to use: click on the symbol that you want to investigate and all affected lines
will be shown at the top of the three lists.
At the lower left you will find the function's prototype.
The Macros
The key combinations Ctrl+Shift+A to Ctrl+Shift+Z are reserved for 26 different macros.
Macros are simply long phrases that you can define to be inserted at the cursor's position
when you press the specified key combination. For instance, you can define a macro
Ctrl+Shift+I for the 'if' construct of the C language:
if ( ) {
}
else {
}
To enter/modify a macro, use the 'Macros' option from the 'Edit' menu. This option will
display the following dialog box:
In the left column, the key that corresponds to the macro name is visible. The
replacement text is shown at the center. The 'Add' button adds a new definition, the
'Erase’ button deletes a definition.
Identifying an Executable or an Object File
This option allows you to insert a static character string within the C source file of type:
''$keyword:value$''. Since the static character strings are included in the executable, this will
allow the 'Identify file' utility of the 'Find' menu to search for all of these types of character
strings within the executable to identify the name and the date of each module that was used
to build the final product. The editor recognizes the static character string and updates the
date automatically each time a module is saved.
You reach this dialog box by choosing the ‘ID’
option in the ‘Search’ menu bar.
An executable can contain many of these character strings, each one from a different module
of the system. This allows you to see each of the sources that were used to build the final
product. This can provide significant assistance in rebuilding the state of the sources to find a
problem at a client's site.
Generating a Table of Character Strings
Wedit allows you to automatically generate string tables, either in the .rc format, or in a
plain table format. All of your current C source files will be scanned for character strings.
This
1. Simplifies the translation of your software into another language
2. Separates programming from the writing of error messages
You can reach this dialog box by choosing the ‘Strings’ item in the ‘Utils’ menu bar.
This dialog box allows you to view and control the generation process.
'Renum' option
This option allows you to renumber the integers used for identifying each string. If you
want to include the strings in another table, this option is essential.
The following dialog box is displayed:
Here you can change either the starting number or the increment to be added to each
string. If you want to have one numeric identifier for a string altering the sequence, go to
the 'Edit' option below.
'Edit' option
Exclude:
If you do not want to include a character string and leave it this way in the source, select
the string and press the exclude button.
You have two options for generating the string table. The first is to generate it in the
STRINGTABLE rc format; the second is to generate it in a normal character string table.
The generation of a string table in the .rc format leads to the following dialog box:
You reach this dialog box when you click the
‘rc’ button in the ‘Strings’ dialog box. You
reach the ‘Strings’ dialog box by selecting the
‘Strings’ menu item in the ‘Utils’ menu bar.
You enter:
1.The name of the output file. If this file exists already and it is a table string file that was
previously generated by Wedit, the new definitions will be appended to the end of the
file. Automatic renumeration will occur to avoid destroying the definitions of previously
existing strings.
2.The ‘Name of the table’ entry field is the variable name that will be used in your
program text to access this table. You should use names that avoid conflicts with any
other identifier in your program.
Alternatively, you can name a function that will return the character string given an
index. This option is active if you choose the ‘Function’ radio button at the left. If not a
straight index will be used.
The "DIFF" Utility
This utility will find the differences between two text files or between all files of two different
directories.
You can reach this
dialog box by
using the ‘Diff’
option from the
‘Utils’ menu
Alt+u, then
d.
If the option 'C syntax' is selected, Wedit will show the differences in this dialog box:
Adding a Utility
A utility is a program launched by the editor using a menu item from the 'Utilities' tab in
the configuration of Wedit. It should be a program that you use frequently. The
'nickname' you choose for it will be added to the 'Options' menu.
You reach this dialog box either by using the ‘Description’ sub-menu in the ‘Edit’ menu bar, choosing the ‘’File’
option, or using the contextual menu that opens when you click with the right mouse button somewhere within an
open source file.
One of the main points is showing you which functions in your code aren’t used
anywhere. This can be viewed easily with the “Unreferenced publics” list, described
below.
The first step when using this utility is to choose the object files that you want to include
in the cross-reference.
You can change the directory using its corresponding button at the bottom, eliminate
object files with the “Ignore” button in the middle. When you are finished, press the ‘OK’
button. The following dialog box will appear. This may take some time, because all of
the actions are implemented after you press ‘OK’.
The
‘Analysis’ list
box can be
reached
from the
main menu
by selecting
‘Utils’ then
‘Analysis’.
All information shown is based on the currently selected function, which is highlighted in
the function listbox at the upper left. Each time the selection of that listbox changes, the
information in the other parts of the dialog box will be updated accordingly.
For each function, the following will be displayed:
• Its prototype at the bottom and any commentary that immediately precedes the
function definition
• All functions that call up the selected function in the list box at the right
• The name of the file and line number where the function is defined
• All functions that are called up by the selected function in the list box at the
middle of the dialog box
Double-clicking in one of the list boxes will call up a dialog box showing the exact place
where the call is done and its context.
Writing the Prototype of all Functions Defined in the Current File
The 'Prototypes’ option is used to produce a file of prototypes that will describe all
functions defined in the current file. It is better if this is handled automatically so that a
function prototype is not forgotten and older software is converted to the ANSI form.
Output file You should enter the name of the output file here. If that file name is in
name use already, you will be prompted before the editor replaces it.
Options The button 'Load into the editor' will display the result after build. For
more information see the browsegen documentation
The information displayed depends on the selection in the list box to the left.
The 'Print' button will generate a memory file in the editor with the definitions of all the
structures in alphabetic order. You can print it using the normal printing procedure of
Wedit. The name of the buffer is '_struct_.c'.
24This is not always true. It is normal for some include files to begin with the following instruction:
extern "C" {
This means that all definitions later wouldn't be used at all if we followed strictly the 'brackets level
zero' directive.
The 'Title' entry field should contain the title that will appear in the help file being
generated.
The 'Help file name' field should contain a file name with the .HLP extension. The result
from compiling an intermediate RTF file (for Windows) or IPF file (for OS2) generated
by Wedit will be stored here.
To add a file to the list, click on the 'Add' button; to delete a file from the list, use the
'Remove' button.
The Output File
The generated file has two main levels:
• A file level, where the index will show all the C sources included during the
compilation. If the file, as is often the case, begins with a commentary, this comment will
be included here. At this level, you will find all of this file’s global variables, as well as
You can print a given function by choosing the corresponding push button.
You can send the printed file to the printer or you can generate an RTF file that can be
used later in a text-processing program.
The ‘Configure’ button allows you to set the printer options.
The first time you use this feature, it is worthwhile to spend some time choosing the right
font for your printouts, according to your printer and the fonts available.
This two operations can be separated. You can use the resource editor for just drawing
your resources, and you will take care of the programming sied, writing of the callback
functions, etc. This is a possibility for instance, when you have already a mass of code
that uses this approach, and you do not feel like modifying it to fit into the resource editor
schema of things.
The different steps involved in the construction of a dialog box.
To use a dialog box you have to:
• Draw it. Weditres helps you by giving you a drag and drop interface. You just place
the objects in their respective positions.
• Generate the different files that containg information about it (Save it)
• Compile and link the generated sources with your program.
• Test it.
This manual will explain you this operations in detail. To give you an overview of the
process, here we summarize all those steps.
• Step 1. Drawing the dialog box. You drop the controls from the toolbar in the place they
will occupy in the dialog box. This operation is explained in detail in the first chapter.
• Step 2. Saving it. Weditres saves the information in a special type of files with the
extension .wed. This file contains the information Weditres needs that is not contained in
a normal windows ressource file. The windows information is saved in two files : the
.dlg, and the .res. Those files contain information that allows Windows to display your
dialog box at runtime. In addition to those, Weditres generates a .c and a .h source files.
Those are linked with your program, and implement all the user interface characteristics
at runtime, that you defined when drawing the dialog box.
• Step 3. You compile and link the generated sources with the callback procedures for your
dialog box.
• Step 4. You test...
Example :
You make the dialog called IDD_MYDLG, in the project called ‘myprj’. If you do not
change the default file names, you will obtain the following files :
1. myprj.dlg. This file contains the ascii description of the resources used, to be
compiled using lcc-win32 resource compiler ‘lrc’.
2. myprj.res This file contains the binary description of the resources. This file can be
directly used by the linker to add your resources into the executable. This saves you
the compilation step.
The first line is mandatory. All the ASCII descriptions of resources use the symbolic
names defined in windows.h, instead of the raw numerical values.
The second one instructs the resource compiler to include the definitions you made when
designing the dialog box. You gave a symbolic name to each element you want to access
in your dialog box, so this file, that contains all of them, should be included too.
The third line, instructs the resource compiler to read the dialog definitions from the
indicated file.
You can separate all your dialogs, and store each one of them in a spearate dialog box file
and header if you wish. In that fashion, each editing project remains of reasonable size.
Or you can throw all your dialogs into one big file, so you avoid cluttering your directory
with too many files. This is a matter of taste left to you.
Structure of the generated code.
Weditres generates a dialog box procedure in a c file. this procedure contains the actions
to take when each of the windows messages that you have decided to handle arrives at
your dialog.
The structure of this procedure is verey simple : it is just a big ‘switch’ statement,
containing a case for each of the messages that interested you.
BOOL DialogDlgProc(HWND hwnd,UINT msg,UINT wParam,UINT lParam)
{
switch (msg) {
case WM_INITDIALOG :
In the parameters dialog boxes you determine in general the following things :
1. The identity of the control, as shown above.You can change the symbolic name given
by default, or its numeric value. To use an already existing identifier you open the
identity combo box, and select an item from the list of available identifiers. Do not type
an old name directly, because of a small bug I haven’t foudnd the time to correct. Only
type a name in there when its a new name, not used before.
2. The static style of the control, i.e. the different options that windows gives for
modifying the appearence of the control, or some other properties.
3. The dynamic style. This is implemented by C code generated by weditres, that allows
you to change some characteristics of the dynamic behaviour or appearence that waren’t
provided by the windows system.
4. The messages and actions you want to be aware of. Weditres will intercept the
messages you indicate, and generate code that will code the function you specify. That
function is usually indicated in a ‘Callbacks’ edit field, in each dialog box. You can type
any name you want, but it is better to prefix it with the name of the dialog box, so that
there isn’t any name conflict between the functions that make similar actions in different
dialog boxes.
A simple example
You go into the ‘File’ option of the menu, choose new, enter ‘example’ as the name of
the project, and then OK.
Weditres will startup a dialog box, and give you a complicated dialog box with several
dozens of parameters. You ignore all of them except the ‘Callbacks’ field, and enter there
the prefix for all the functions in this new dialog box : DlgExample.
Then, press the ‘ok’ button and the dialog box will disappear, leaving you an empty
dialog box. Drag one button from the toolbar to the dialog box.
The ‘Button’ icon is labelled ‘ok’, so it is fairly easy to recognize it. If you leave the
mouse a small time over each button, an explicative text appears, telling you what control
is described by the icon.
The dialog box that appears allows you to individually select/deselect which files will be
generated, and to change the paths where they will be generated. It is not a bad idea to
look at this place if you have any problems with paths, or similar.
The grid is the minimung spacing between each movement. The spacing is the amount of
space left by the editor by default between controls. The margins, are just that : margins
that delimit the controls from the borders of the window.
‘Sticky group boxes’ means that the controls that are enclosed by a group box are moved
with the group box when you move it. If you deselect this feature, to move all items in a
group box you have to select all of them.
You can include additional text in the header file that the resource editor generates. This
text can be entered here.
Managing the selection
There is always a selected item. It is highlited with eight small red squares. You can
change its hsape by taking one of the squares with the mouse, or, if you prefer using the
Ctrl+Arrow keys : Ctrl+left arrow is equivalent to taking the square in the left border of
the control and moving it leftwards.
To start the control, just press the ‘test’ button, or press Ctrl+T. This will make weditres
create a copy of the control, and load that copy as windows would do. You can see the
appearence of the control in action, press buttons, select list box items, etc. Pressing the
OK button, or the Cancel button will stop the test. If the dialog box has a close menu,
pressing that button will stop the test too.
If you have painted yourself in a corner, by drawing a dialog box without all those
buttons, you can always get out by pressing Ctrl+T again, what will stop the test.
Using the directory listing
When you press the ‘dir’ button, you will see a list of all the dialog boxes that are
contained in the current project in a separate window. Using the right mouse button, you
can sort the items in several ways : by ID, or by title or others.
Setting the tab order.
The tab key can be used to switch the focus from one element of the list box to the
following one in the Group order that you choose at design time. Normally, this order is
the sequence that you used when dropping the controls in the dialog surface one after the
other. You can change this order by using the ‘Group’ item in the ‘Options’ menu bar.
This order is important for the ergonomy of your dialog box, specially for people that do
not like to leave the hands from the keyboard, and prefer just using the tab key to go to
the next entry field for instance, instead of using lengthy mouse move operations.
The ‘Group’ dialog box will show you the list of controls that you have already dropped
in your dialog box. You select one item, and then you can easily move it around to put it
first or after another control. Here you can set/unset whether the control will be a tab stop
or not. If you unset the tabs, the tab key will never go into that control. This is
recommended for controls that do not accept any user input, like static text fields or
group boxes.
And this is all there is to it Of course, there are hundreds of details that will be explained
later,if I arrive at bringing myself to writing all the documentation... But the essential of
weditres is this.
The group and the tab order are essential for a good user interface. The tab order is the
sequence that the focus of the controls in the dialog will follow when the user presses the
TAB key. Normally, the TAB key should go from one control to its immediate neighbor,
without jumping around.
The dialog editor will establish this sequence as just the order that you used to drop the
controls in the dialog. It often happens, however, that you drop a control, and then you
realize that you forgot one, and drop another control in a wholly unrelated place. This
doesn’t affect your dialog box visually, but it does affect the user interface. Pressing the
TAB key will make the focus jump around within the controls of your dialog box.
Besides, it is important, that static controls like group boxes or text fields aren’t available
with the TAB key. If they acquire the focus, they do not show it, so the user doesn’t
know where the focus is.
You can change the tab order by moving the controls around within this dialog box. To
move a control you select it first, by clicking in the middle of a row.
When a control is selected, you will see that the form of the mouse changes to an
horizontal bar when moving within the list of controls. This means that you can drop the
control in that position, and change its order.
The controls that are reachable with the TAB key have a small tab symbol at the left of
them.
You should remove that tab stop from Group boxes, static text fields, and other static
controls. You should add it to all controls that receive user input like buttons, edit fields,
list boxes, etc.
This represents an edit control, both single line (default) or a multiline edit control.
This represents a list view control. If you use this, please do not forget to call
InitCommonControls in your code. This applies to all other controls after this one.
This represents an AVI displaying control. This is not operational in this version of
weditres.
The two comboboxes allow you to edit the symbolic name of the currently selected
control at the left, and to edit the control’s text at the right, if applicable.
The selection
The selected control will be shown with full red handles around it. By holding the Shift
key down and clicking in other controls, you can select several of them :
and then press the align left button in the fixed toolbar of the editor, the controls will
be aligned using the left side of the dominant control. If you choose the ‘same width’
button in the fixed toolbar, the dominant control’s width will be used to resize all
other controls in the selection.
The multiple selection doesn’t apply to the dialog box itself of course, since there is no
meaningful alignment that can be used with the dialog box itself.
The selection is important when copying controls from one dialog box to the other, since
the normal operations like cut, paste, and copy apply to the selected controls. This allows
you to easily transport controls from one dialog to another.
The arrow keys apply to the selection too : you can move the group of selected controls
using the arrows, what is more precise than using the mouse.
When there is only one control selected, you can resize the selected control using the
Ctrl+arrow keys. The combination Ctrl+left arrow, for instance, will maintain fixed the
right side of the control, and resize it towards the left. The right arrow with the control
key does the same but to the right, the up arrow resizes it towards the top of the screen,
and the down arrow towards the bottom of the screen.
Fixing a control in the screen
Using the tool, you can fix a control, or one side of a control to the screen. This
allows you to move it horizontally or vertically without fear of disturbing the overall
position, or to fix it in one place within the dialog box, so that you do not move
accidentally later.
When you click in the tool, the mouse changes its shape, signifying that you can fix the
selected control. This will not work when you have the entire dialog box selected, since
fixing a dialog box is not very sinful.
You should click in one of the red handles of the selected control. The color of the handle
will change, telling you that side of the control is now fixed. For instance :
The status bar is divided into five fields. They show in dialog coordinates :
1. The upper left corner of the selected control(s).
You can use the status bar to fine tune the position. By double clicking in the
corresponding field of the status bar you can enter the positions numerically. When you
double click in the ‘dx’ field of the status bar, you can change the width of the selected
control and enter a numerical value directly.
Managing the symbols
The purpose of this dialog is to allow you to add a new symbol, to erase a definition you
no longuer need, or to change either the name or the value of a symbol.
To add a new symbol type its name in the first entry field, then the value it should have in
the second, and press the Add button.
To erase a symbol select one in the list and press the Erase button.
To change a symbol change either its name or value, and then press the Change button.
The changes you do will be effective only after you press the validate button.
Easy isn’t it ? No big science here.
The zoom utility
This allows you to see in more detail your dialog box. Just choose ‘zoom’ in the
resources menu of Wedit, then click in the surface of the small window that appears.
Then, without releasing the mouse button , move the mouse pointer around. You will see
the magnified contents of the rectangle that the mouse draws in the zoom window
Modal dialog boxes are simpler to manage than modeless dialog boxes because they are
created, perform their task, and are destroyed by calling a single function.
Note that if you are editing a .res file, and you haven’t defined a project for weditres,
only a portion of this dialog will be visible.
Messages
Message Effect
Init Calls the specified callback function when the message WM_INITDLG is
received.
The name of the callback is
DlgXXXInit(HWND hwnd, WPARAM wParam, LPARAM lParam)
Normally, you should handle this message, since it allows you to initialize
things in the dialog box before is displayed.
Cancel Calls the specified callback function when the user presses the ‘Cancel’ button.
The name of the callback is :
DlgXXXCancel
Close Calls the specified callback when the dialog receives the WM_CLOSE
message. Its name is : DlgXXXClose.
All Instead of calling the default message handling function, it calls a callback :
DlgXXXDefault(HWND hwnd,UINT msg,WPARAM wParam,LPARAM
lParam) ;
This is an escape hatch so that you can always treat a message the framework
doesn’t consider.
Validation Calls DlgXXXValidate(HWND hwnd) when the user presses theOK button.
Note that if you are editing a .res file, and you haven’t defined a project for weditres,
only a portion of this dialog will be visible.
You should establish here the general appearance of the edit field, and the prefix that will
be used by weditres when generating the callbacks you want for this control. You can
change the font, if you wish, the number of accepted characters, and set the initial
contents of the edit field, if any.
Identity
The #define under which this edit field will be used in your application. This is the define
you use when you call the GetDlgItem function for instance. The numerical value is
shown too, below.
Text alignment
Text can be aligned from the left, centered, and from the right. Normally, use left
alignment, other styles will provoke strange things when typing.
Messages
Message Effect
Set focus When the dialog box receives the EN_SETFOCUS message, the callback :
DlgBoxXXXSetFocus(HWND hwnd, WPARAM wParam,LPARAM
lParam) ;
will be called.
Kill focus When the dialog box receives the EN_KILLFOCUS message the callback :
DlgBoxXXXEditFieldYYYKillFocus(HWND hwnd, WPARAM
wParam,LPARAM lParam) ;
will be called. Normally at this point you would check the contents of the
dialog box for validity. It is sometimes better to do it immediately, without
waiting for the user closing the dialog box.
Text has When the dialog box receives the EN_CHANGE message from the control,
changed the callback :
DlgBoxXXXEditFieldYYYChanged(HWND hwnd, WPARAM
wParam,LPARAM lParam) ;
will be called. This allows you to follow the input character by character if
you want it to.
Space If the user has typed so much text that the edit field has no space for holding it,
Overflow the message EN_ERRSPACE will be received. At this point, if you want it,
the callback :
DlgBoxXXXEditFieldYYYErrSpace(HWND hwnd, WPARAM
wParam,LPARAM lParam) ;
will be called. This allows you to react to that situation. It must be noted that
this was very frequent under windows 3.1, but it is virtually impossible that
this happens now.
Horz Scroll If the user has clicked in the horizontal scroll, the dialog box will receive the
EN_HSCROLL notification message from the control. You can react to this
event. In this case the callback :
DlgBoxXXXEditFieldYYYHorzScroll(HWND hwnd, WPARAM
wParam,LPARAM lParam) ;
Validate You can establish a callback specific for this control when the user presses the
OK button. Normally this is not used, and you process all controls in the
Validate message for the whole dialog box.
DlgBoxXXXEditFieldYYYValidate(HWND hwnd, WPARAM
wParam,LPARAM lParam) ;
Note that the HWND parameter there is the hwnd of the edit field.
A text static control displays text in a rectangle in one of five styles: left-aligned without
word-wrap, left aligned with word-wrap, centered, right-aligned, or « simple. »
When you press the color button, at the bottom right of the text styles dialog box, the
standard dialog box for choosing a color will appear.
Weditres will generate code to handle the WM_CTLCOLORSTATIC message that will
be received by the dialog box procedure. This code will set the color of the static text to
the color you choose in the colors dialog box.
Properties of a ComboBox
A combo box consists of a list and a selection field. The list presents the options a user
can select and the selection field displays the current selection. Except in drop-down list
boxes, the selection field is an edit control and can be used to enter text not in the list.
Messages
Button Windows Description
message
Init WM_INITDLG You can get called at the initialization of the dialog box, to
initialize things for this specific control. Normally this is
not used. The callback has the form :
DlgXXXComboYYYInit(HWND hwnd, WPARAM
wParam,LPARAM lParam) ;
Hiding list CBN_CLOSEUP This message is sent when the list box of a combo box has
been closed.If you want to be notified when this message
arrives, weditres will generate a callback of the form :
DlgXXXComboYYYHideList(HWND hwnd,WPARAM
wParam,LPARAM lParam) ;
Double CBN_DBLCLK This message is sent when the user double-clicks a string in
click the list box of a combo box. If you want to take a special
action here, weditres will generate a callback of the form :
DlgXXXComboYYYDoubleClick(HWND
hwnd,WPARAM wParam,LPARAM lParam) ;
Show list CBN_DROPDOWN This message is sent when the list box of a combo box is
about to be made visible.If you want to take a special
action, weditres will generate a callback of the form :
Note that if you are editing a .res file, and you haven’t defined a project for weditres,
only a portion of this dialog will be visible.
Note that if you are editing a .res file, and you haven’t defined a project for weditres,
only a portion of this dialog will be visible.
You should specify the prefix to be used for this control, and the font to be used.
Text
This text will be shown in the check box. You can enter any text here up to 255 chars.
Identity
The #define under which this check box will be used in your application. This is the
define you use when you call the IsDlgButtonChecked function for instance. The
numerical value is shown too, below.
Font
Name and size of the font used for this check box.
The styles of a group box are described in detail in the documentation of any of the other
controls.
There are no callbacks, since the group box sends no messages, and receives no input.
You will notice that group boxes carry the elements that they contain in the editor, when
you move them. Modifying the ‘sticky group boxes’ check box in the configuration of the
editor can change this behavior.
This control, like the group box above, is just for grouping purposes. It receives
no input and sends no messages.
Black rectangle styles
This control, like the group box above, is just for grouping purposes. It receives no input
and sends no messages.
These controls are seldom used by themselves in dialog boxes. They can send
only one message: WM_HSCROLL or WM_VSCROLL.
Since there is only one message, no suffix will be added to the name of the
control procedure as specified in the ‘Callbacks’ edit field. The procedure would
be then :
void DlgXXXScrollYYY(HWND hwnd,UINT message,WPARAM
wParam,LPARAM lParam) ;
The message argumet can be either WM_VSCROLL or WM_HSCROLL. This
way you can use a single callback procedure for both messages.
Spin control styles
To the user, a spin control and its buddy window often look like a single control. You can
specify that an up-down control automatically position itself next to its buddy window
and that it automatically set the caption of the buddy window to its current position. For
example, you can use a spin control with an edit control to prompt the user for numeric
input.
The spin control is at the left of the entry field. Pressing the arrows you can
increment/decrement the edit field contents.
The Identity and Value fields have the same meaning than in the other controls.
Styles
Static styles
Input field Window style Purpose
Visible WS_VISIBLE Makes the control visible at startup
Disabled WS_DISABLED Disables the control at startup
Group WS_GROUP Marks the start of a group of controls
Tab stop WS_TABSTOP Makes this control reachable with the TAB key.
Static edge WS_EX_STATICEDGE Has a static edge around it
Client edge WS_EX_CLIENTEDGE Has an edge around the client area
Help ID Not implemented in this version
Messages
Input field Window Purpose
message
Value will change UDN_DELTAPOS The operating system sends the UDN_DELTAPOS
notification message to the parent window of an spin
control when the position of the control is about to
change. This happens when the user requests a
change in the value by pressing the control’s up or
down arrow. The UDN_DELTAPOS message is sent before
the WM_VSCROLL or WM_HSCROLL message that actually
changes the control’s position. This lets you examine,
allow, modify, or disallow the change. return TRUE
in your callback in response to this message to
prevent the change in the control’s position. Return
FALSE to allow the change
The callback will be of the form :
Here we have a dialog with a big tree control in it. This is a very complex control, that can
do a lot of things but needs a lot of effort to get it right. Weditres can help you a bit by
generating some of the code that needs to be written.
The properties box of the tree control matches this element’s complexity. Here it is:
Messages :
Description Message Purpose
Begin drag TVN_BEGINDRAG Notifies the program that the user has begun a drag
operation with the left mouse. The callback function will
be of the form :
xxxBeginDrag(HWND,NM_TREEVIEW *) ;
Begin right TVN_BEINRDRAG The user has begun a drag operation with the right mouse
button drag button. The callback will be of the form :
xxxBeginRDrag(HWND,NM_TREEVIEW *) ;
Begin label TVN_BEGINLABELEDIT The user has begun to edit a tree label. The callback will
editing be of the form :
xxxBeginLabelEdit(HWND,TV_DISPINFO *) ;
End label TVN_ENDLABELEDIT The user has ended the editing of a label in an item. The
editing callback will be of the form :
xxxEndLabelEdit(HWND,TV_DISPINFO *) ;
Needs TVN_GETDISPINFO Requests information that the tree view control requires
display to display an item. The callback has the form :
information xxxGetDispInfo(HWND,TV_DISPINFO *) ;
Set display TVN_SETDISPINFO Informs the parent window that it should set the display
information information it has about an item. The callback has the
form :
xxxSetDispInfo(HWND,TV_DISPINFO *) ;
Selection has TVN_SELCHANGED Informs the parent window that the selection has changed
changed from one item to another. The callback has the form :
xxxSelChanged(HWND,NM_TREEVIEW *) ;
Selection is TVN_SELCHANGING Informs the parent window that the selection is about to
changing change. The callback as the form :
xxxSelChanging(HWND,NM_TREEVIEW *) ;
Item is TVN_ITEMEXPANDING Informs the parent window that an item is going to
expanding expand or collapse. The callback has the form :
xxxItemExpanding(HWND,NM_TREEVIEW *) ;
Item has TVN_ITEMEXPANDED Informs the parent window that an item has been
been expanded. The callback has the form :
expanded xxxItemExpanded(HWND,NM_TREEVIEW *) ;
Key has TVN_KEYDOWN A keyboard event. The callback has the form :
been pressed xxxKeyDown(HWND,TV_KEYDOWN *) ;
The parameter ‘hwnd’ in all messages above is the handle of the dialog window. You can get
the handle of the tree control by using the GetDlgItem primitive.
The structures used are the following:
1) NM_TREEVIEW
UINT action
Specifies a notification-specific action flag.
TV_ITEM itemOld
Specifies a TV_ITEM structure that contains information about the old item state. This
member is zero for notification messages that do not use it.
TV_ITEM itemNew
Specifies a TV_ITEM structure that contains information about the new item state.
This member is zero for notification messages that do not use it.
POINT ptDrag
Specifies a POINT structure that contains the client coordinates of the mouse at the
time the event occurred that caused the notification message to be sent.
2) TV_ITEM
The TV_ITEM structure specifies or receives attributes of a tree-view item.
typedef struct _NM_TREEVIEW {
NMHDR hdr ;
UINT action ;
TV_ITEM itemOld ;
TV_ITEM itemNew ;
POINT ptDrag ;
} NM_TREEVIEW ;
UINT action
Specifies a notification-specific action flag.
TV_ITEM itemOld
Specifies a TV_ITEM structure that contains information about the old item state. This
member is zero for notification messages that do not use it.
itemNew
Specifies a TV_ITEM structure that contains information about the new item state.
This member is zero for notification messages that do not use it.
ptDrag
Specifies a POINT structure that contains the client coordinates of the mouse at the
time the event occurred that caused the notification message to be sent.
3) NMHDR
typedef struct tagNMHDR {
HWND hwndFrom ;
UINT idFrom ;
UINT code ;
} NMHDR ;
Members description :
hwndFrom
Handle to control sending message. In the above examples is the handle of the tree
control.
idFrom
Identifier of control sending message. In the case above, this would be the id of the
tree control.
code
Specifies the notification code.
4) TV_DISPINFO :
typedef struct _TV_DISPINFO { tvdi
NMHDR hdr ;
TV_ITEM item ;
} TV_DISPINFO ;
Handling the Begin/End drag.
Here is an example of a callback function that handles the begin drag message, adapted
from the documentation of MSDN.
// MyTreeViewBeginDrag - begins dragging an item in a tree view control.
// hwndTV - handle to the image list.
// lpnmtv - address of information about the item being dragged.
// Tell the tree view control to create an image to use for dragging.
himl = TreeView_CreateDragImage(hwndTV, lpnmtv-
>itemNew.hItem) ;
// Get the bounding rectangle of the item being dragged.
TreeView_GetItemRect(hwndTV, lpnmtv->itemNew.hItem,
&rcItem, TRUE) ;
// Get the heading level and the amount that the child items are indented.
dwLevel = lpnmtv->itemNew.lParam ;
dwIndent = (DWORD) SendMessage(hwndTV, TVM_GETINDENT,
0, 0) ;
// Start the drag operation. This is not a function call, it is just a macro,
defined in win.h
ImageList_BeginDrag(himl, 0, 0, 0) ;
// Hide the mouse cursor, and direct mouse input to the parent window.
ShowCursor(FALSE) ;
// Now capture the mouse to follow the drag operation.
SetCapture(GetParent(hwndTV)) ;
// Sets a global variable to notify the functions that are going to be called
later when dragging is active.
g_fDragging = TRUE ;
return ;
}
To control the different options you use the following properties dialog box :
The slider interfaces with the dialog box that contains it only with the WM_HSCROLL
or the WM_VSCROLL message. Weditres will add code to handle those messages and
call your callback procedure when the slider wants to say to you something.
You can add a range of values, and Weditres will generate code to set that range of
values at run time during the initialization of the dialog box.
The other styles shown are the usual ones already explained in all the other controls
(visible, tab stop, etc). They will not be repeated here.
The date calendar control
This control allows the user to choose a date. Here is an example.
MONTHDAYSTATE mds[MAX_MONTHS];
INT i, iMax;
LPNMHDR hdr = (LPNMHDR)lParam;
switch(hdr->code){
case MCN_GETDAYSTATE:
iMax=lpnmDS->cDayState;
for(i=0;i<iMax;i++){
mds[i] = (MONTHDAYSTATE)0;
BOLDDAY(mds[i],15);
}
lpnmDS->prgDayState = mds;
break;
}
return FALSE;
}
To add a menu item just type insert (the ‘ins’ key), selecting before the menu item above
the one you will introduce.
You can test your menu to see it in ‘action’ by choosing ‘test’ in the ‘File’ option of the
main menu of the menu editor.
Besides the tree with the items, you will se the following dialog box floating around.
Here you enter the name of the menu, its associated symbol (#define), and its value.
In the ‘Options’ group you can change the appearance of the menu item, either for a
normal menu item, or for a popup menu. Do not forget to press ‘Apply’ when you are
done with changes.
Fo instance, when you want that Ctrl+Shift+N do something special in your application,
you define an accelerator key like
switch(message) {
...
case WM_COMMAND:
switch(LOWORD(wParam)) {
case MENU_STOPCALCULATING:
if (CalculationsStarted()) {
StopCals();
}
break;
}
}
You can have a menu item somewhere, with an item 'Stop calculations" but this is not
mandatory. You receive from windows this message when you do not forget to add the
TranslateMessage step in that famous MainLoop of your window procedure.
You can edit this table graphically from Weditres. To call the corresponding editor you
should either use the menu item in the 'Objects' bar, or use the directory tree. There, (if
there is already a resource table defined in the application), you will find your table. Just
double click in its name and the accelerator editor will be called automatically.
The editor for this resource type is very simple. It will show you at startup a list of all
defined items. You can perform the usual actions (Add, Modify, and Delete), with three
buttons at the lower right.
If there is no accelerator table defined, the editor will automatically start the 'Add' action,
supposing you are not very interested in contemplating an empty list. The Add/Change
dialog box edits a single line of the accelerator table.
Instead of showing here yet another screen shot, I think it is better to spend more time
explaining the concepts behind this.
You can define either plain Ascii keys combinations, or you can set the 'Virtual Key' flag,
that indicates to Windows that the value is to be interpreted as a value for a virtual key,
i.e. a key like VK_F1, VK_BACK, etc. All those values are defined in <windows.h>, and
It is important to be clear that the ASCII/VIRTUAL KEY flags are alternatives (hence
the radio buttons in the editor). You can only use one of those.
These flags are not alternatives, they can all be set for the same key combination. They
can be set/unset using the checkboxes in the dialog box that edits each line of the table.
The accelerator resource is named following the same conventions as the naming of all
other resource types: either with a character string or an identifier. You load the resource
using the LoadAccelerators window function that searches for the specified
accelerator table.
Using the ‘Versions’ tab from the ‘Options’ menu (‘Configuration’), you can change
these parameters.
The options for 'get' and 'put' are very similar. You should specify if you always want
CMS to lock the file after a get or a put operation, if you want to see the progress display,
and if you want CMS to erase the original version of a file after it is stored under CMS.
The other options concern setting the CMS files with a read only attribute
(recommended) and if the user's name is case sensitive (not recommended).
Get: Retrieving a Version from a CMS File
This operation consists of reading a version in the corresponding CMS file. This can
produce access conflicts in a multi-user environment because the file can be locked. CMS
forbids two people from working with the same source at the same time.
After asking for a CMS file, the 'Get' option displays the following dialog box:
You can change the destination directory by editing the corresponding entry field.
This operation takes an existing file as input and stores it under the same name in the CMS
file in the CMS directory. If the file does not belong to the project file list, it will be added.
You reach this
dialog box by
using the ‘Put’
option in the
‘Versions’
menu bar.
The files shown are the files that have been changed.
Displayed are the default version, the symbolic name of the revisions (if any) and the
lock status. If you select the 'Details' button, the following display appears:
To visualize the different entries, select a line of the list box at the left.
Building a Release
A release is understood in this context as a coherent set of files and versions at a given
moment in the development of a software system. A client receives a version of the
executable, for instance, and a release captures all versions and all files that have been used
to build that executable.
You can modify the version used by CMS or exclude a given file from the release.
To see the contents of each distribution, click under its name in the list box to the left.
The contents of the other controls will be updated accordingly.
Retrieving a Release
Use the 'Get release' option from the 'CMS' menu. First you are prompted to choose a
revision with a list box very similar to the 'See distribution' described above. When you
have selected a release, the following dialog box appears:
The purpose of this utility is to generate a skeleton of your Windows application. The
problem with Windows programming is that, a large amount of code must be written just
to display a window. This frustrates novice Windows programmers and skilled
professionals alike. Normally, a ‘generic’ skeleton is used, which is modified with a text
editor. This is cumbersome and error prone. It is better to generate a customized skeleton
using a set of templates with a utility that is designed precisely for this operation.
Triggering the application wizard is very simple: Type its name or answer ‘yes’ when
Wedit asks you, when creating a new project.
In the first page of the wizard, you should fill in the following fields:
Name Purpose
Name of the project Wedit fills this in when the wizard is called from Wedit. This
will be used to derive the name of the window classes and the
file names.
Single window This is an application that displays only one main window.
Multiple window This is an application that uses the MDI standard. A standard
MDI menu will be generated and the code for resizing the
main window will be slightly modified when a status bar is
active.
Dialog based This is not implemented in this version.
Dll This is a DLL application. The wizard will generate a LibMain
only. No window will be created or other visual controls.
Status bar at the The application (either MDI or SDI) will have a status bar
bottom where you can display messages or other information to the
user. The wizard will generate code to show in the status bar
an explicative text of each menu option as the user moves the
mouse among different menu items.
Toolbar The application has a toolbar, which can be floating or fixed to
the main application window
TCPIP The wizard will generate code at the entry of the program
(after the main window is created) to call the WSAStartup API
to setup the network, and will generate a call to WSACleanup
before the program exists. If you use this option, it is
imperative to add ws2_32.lib to the libraries used by your
project, since lcclnk does not include that library by default.
About dialog box The wizard will generate code for a callback for a standard
‘About’ dialog box, will modify the OnCommand function to
accept the IDM_ABOUT command, and before generating the
code, the wizard will call the resource editor to allow you to
Class Definition
To be able to open a window, a window of a specific class has to be registered with the
system. The purpose of the first page of the wizard is to let you define exactly the
window class. If this looks too complicated to you, press the continue button and leave
the default values. In most cases, the default values are appropriate to your needs.
Toolbar Definition
You should click on the button you want to have in your toolbar. If you do not choose at
least a single button, the toolbar will not be generated.
Styles
Creating a Window
The wizard generates a procedure for creating the main application window. If this looks
too complicated, do not alter these parameters; simply press the Continue button. In most
cases, these default parameters will be what you want.
The documentation for each of the fields is included below.
The window class should be defined in the preceding panel. It is displayed here for
information purposes only.
Action What to do
Adding a new • Modify the .rc file and add the menu item you want. The item
menu item should have a line of text and a numeric identifier. See the other
menu items for ideas on how this is done.
• This new numeric identifier should be #defined in the global
application header file, that is #included in the .rc file.
• Modify the MainWndProc_OnCommand function, adding a
new case in its switch statement. This new case should be the
same numerical identifier you entered in the header file for this
menu item.
Adding a dialog • Design the dialog box with Weditres. Normally, you will have
box several dialog boxes in your application. Therefore, it is best to
do is to start a new project and modify the .rc file with an
#include statement of the .dlg files generated by Weditres.
Assume that you name your dialog box set mydialogs. Weditres
will generate a mydialogs.dlg file. You should then add the line
#include « mydialogs.dlg » to the .rc file. This will allow you to
add several dialogs later always using the same names.
• After the design of the dialog box is finished, you have to call it
up using the DialogBox windows primitive.
• The DialogBox primitive needs a callback function that will be
called up to handle the events in the dialog box. You have the
choice of having Weditres generate that procedure for you, or
writing your own. If you let Weditres do it; it will generate a file
This instructs the compiler to add a special instruction for the linker to add this name (in
this case MyFunction ) to the export table of the DLL.
The second method is to build a definition file (.def) where you write the list of exported
functions from the DLL. This is just an ASCII text file whose extension must be .def,
with the list of the exported functions of the DLL. An example of such a file is:
EXPORTS
MyFunction
The first line must be the keyword EXPORTS, followed by the names of the exported
functions, one in each line.
The formal syntax is:
IDENTIFIER [DATA]
IDENTIFIER is a placeholder for the name of the exported symbol. It can be followed by
the keyword DATA, which means that the exported symbol is not a function, but a data
item. This is important to specify, since the entries generated in the import library are not
the same.
3) You should build an import library.
This is done automatically by lcclnk. If you want to do it manually, you should
issue the following command:
To debug your DLL with Wedit’s debugger, change the name of the executable to start in
the project configuration tab ‘Debugger’ and write the name of the executable that uses
your DLL. Then, follow the executable until a DLL function call appears. Next, press F8
to enter the function in the DLL. Remember that both the executable and the DLL should
have been compiled with debug information turned on!
DLLs should have a DllMain or LibMain entry point function, that is called up by the
system when the DLL is loaded or unloaded, and allows you to initialize/cleanup
elements. This function MUST be declared as follows:
#include <windows.h>
/*----------------------------------------------------------
------------
Procedure: LibMain
Purpose: DLL entry point called up when a DLL is loaded or
unloaded by a process, and when new threads are
created or destroyed.
Input: hDllInst: Instance handle of the DLL
fdwReason: event: attach/detach
lpvReserved: not used
Output: The return value is used only when the fdwReason is
The first line should contain the name of the DLL you are using, i.e., Mydll.dll or whatever. Since it is a
file name, case is NOT significant. No path information should be included. Just the name of the DLL.
The following lines should contain three columns, separated by tabs or spaces.
The first one is the name of the symbol as published by the compiler, i.e., if your symbol is MyFunction,
the column should contain _MyFunction. In the case of a _stdcall function it would be
_MyFunction@12 .
The second one should contain the name of the symbol as exported from the DLL. Normally this should
be the same as the column 1, but sometimes you want to export the functions without the leading
underscore, for instance for using them with another language processor like Visual Basic.
The third column is optional. If present it should contain the column DATA, meaning that this is an
exported DATA symbol.
The .exp file is generated automatically by lcclnk.
Library Mydll
EXPORTS
Myfunction
_MyOtherFunction=Other
SECTION
DATA SHARED
The first line must contain the name of the DLL or file that you are building, but this is
not required. The Exports section contains two exports: A function called “MyFunction”,
and a function called “Other”, which is associated to the “MyOtherFunction” procedure,
and which will not be visible with that name, since its exported name will be “Other”.
The SECTION part defines the data sections (.data and .bss sections) as shared, i.e.,
accessible by other programs.
This function should then be inlined by the compiler. The C interface would be:
_strlen(str);
The compiler recognizes intrinsic macros because they have an underscore as the first
character of their names, they are declared _stdcall, and they appear in the intrinsics
table. Functions that begin with an underscore are few, thereby avoiding the need to look
up the intrinsics table for each function call, which would slow down compilation speed.
Take the file intrin.c in the sources of lcc-win32 and modify the intrinsics table. Its
declaration is in the middle of the file and looks like this:
Note that all intrinsics should start with an underscore to avoid conflicting with user
space names.
When a call to this function is detected by the compiler, you will first be called when
“pushing” the arguments. Here is the function strlenArgs() then:
This function tests that in the given node, the left child is not already assigned to a
register. It will assign the register only if this is not the case.
You then go to the center of the routine: Generating code for the strlen utility.
Compile the compiler and obtain a new compiler that will recognize the macro just
created.
In general, you can use ECX, EDX, and EAX as desired. The contents of EBX, ESI, EBP
and EDI should always be saved. If you destroy them “unpredictable results” will surely
occur.
#include <stdio.h>
#ifdef MACRO
int _stdcall _strlen(char *);
In the C source, we use the conditional MACRO to signify if we should use our macro, or
just generate a call to the normal strlen procedure. We compile this with our new
compiler, and add the –S parameter to see what is being generated.
_main:
pushl %ebp
movl %esp,%ebp
pushl %edi
.line 9
.line 10
cmpl $1,8(%ebp)
jle _$2
.line 11
movl 12(%ebp),%edi
; Your argument gets assigned to ECX, as your strlenArgs
function
; defined
movl 4(%edi),%ecx
; This is the beginning of your macro body
orl $-1,%eax
; This is your generated label
_$strlen0:
inc %eax
cmpb $0,(%ecx,%eax)
jnz _$strlen0
; Your macro ends here, leaving its results in EAX
pushl %eax
movl 12(%ebp),%edi
pushl 4(%edi)
pushl $_$4
call _printf
addl $12,%esp
_$2:
.line 12
xor %eax,%eax
.line 13
Scan the characters looking for either zero (end of the string) or the given char. The
pointer to the string will be in EAX, and the character to be searched for will be in
ECX. Use EDX as a scratch register. Next, write the strchr function for assigning the
arguments. It is:
static Symbol strchrArgs(Node p)
{
1. LoadObjectFile
The interface is very similar to that of LoadLibrary, since the functionality is quite
similar.
The dynamic loader operates by opening the given object, allocating space in RAM for
the data and the code stored in there, copying the contents of the data and code sections,
then fixing up everything.
To resolve external references, the loader relies first on the symbol table of the running
executable. If that symbol table exists, it will be used to resolve external references from
the object file.
If the symbol table is absent in the running executable, or a symbol is found that does not
match any executable symbols, the dynamic loader will rely on the imports table
generated by the bind utility. This table contains the DLLs used by the object file, and all
the imported functions that are needed.
The bind utility will construct this table from the “apilist.txt” file, which is present in the
lcc-win32 distribution in the “lib” directory. This file contains a list of all known DLLs
and their exported functions. Using this list, the bind utility appends a list of needed
DLLs to the object file, that will be used by the dynloader.dll library.
Note that if you wish to add a DLL of your own to the list, you can do so by modifying
apilist.txt.
A Complete Example
#include <dynloader.h>
int main(void)
{
OBJECT_FILE *obj = LoadObjectFile("hello.obj");
void (*fn)(void);
fn = GetProcedureAddress(obj,"_hello");
(*fn)();
UnloadObjectFile(obj);
return 0;
}
Eiffel support is still in a very early stage within the lcc-win32 system. Still, there are
many things that are working.
To build an Eiffel project, you should add to your new project files with a .e extension.
This will tell Wedit that the compiler is ‘compile’, the name of the SmallEiffel compiler.
You should enter the name of the root class, and the name of the creation procedure for
that root class on which defaults to ‘make’. The name of each compiler option is the same
as the one used by the Eiffel compiler. Please look at the documentation that comes with
the compiler for more information.
The debugger works with the generated executable, and the commands are the same as
for the C language: F2 to set a breakpoint, F4 to skip calls and advance to the next line,
and F8 to follow calls.
MYDLL.dll
_foo@12 foo
_linelength linelength data
_alternatefoo@12 foo
This file should contain the name of the DLL in the first line, then a series of exports.
In the first column you should write the name of the function, as decorated by the
compiler: A leading underscore, and a '@nn' for all _stdcall functions. The number
following the @ means the number of arguments * 4. In the second column, you should
write the name as it was exported from the DLL. This is optional. If absent, the buildlib
utility will use the name of the function minus the decorations. The third column
(optional) is only necessary if you want to export a data item and not a function.
15) How can I use the debugger of lcc with Microsoft’s compiler?
You should compile with the debug information set to the standard NB09 and avoid the
program database. This can be accomplished with the following command line to the
Microsoft compiler ‘cl’:
cl /Z7 foo.c /link /pdb:none
16) When I start my program, a ‘DOS box’ (console) appears. How can I get rid of
it?
You have not defined your program as a Windows (GUI) program. To do this, go to the
‘Linker configuration’ tab, and check the ‘Windows program’ radio button. This will add
the option ‘Subsystem Windows’ to the linker command line.
When Windows starts a program, it looks at its header for the ‘Windows’ bit. If the
program is not marked as a GUI program, it will open a console window before starting
it. The linker defaults to a ‘console’ application, and not to a Windows application.
17) The linker indicates that _LibMain@12 is not defined when I try to link my
DLL. What does this mean and how do I get rid of it?
This means you did not define the entry point of your DLL. Generate a DLL skeleton
with the wizard. Or write the following function:
BOOL WINAPI __declspec(dllexport) LibMain(HINSTANCE hDLLInst,DWORD fdwReason,LPVOID
lpvReserved)
{
return 1;
}
For instance:
• When I use 'make' on the \lcc\src\lccsrc the lcclnk.exe fails. It says, 'Fatal: Command
arguments too long' — What have I forgotten to do?
Answer:
There are many make utilities. That prompt does not appear in the make from the lcc CD,
and the user has forgotten that another Make utility with a smaller command line limit
apparently is being used. Maybe a DOS Make utility.
These type of bugs are difficult to prevent, and in general, I cannot prevent a problem
from surfacing somewhere. To be sure that the lcc Make utility is being used, type:
\lcc\bin\make
make
There are other problems that can arise, the possibilities are infinite. Obviously, if a file is
missing, contact me immediately and it will be shipped to you.
The following example creates a surface associated with a DirectDraw object by calling
the IDirectDraw2::CreateSurface method with the C programming language:
The lpDD parameter references the DirectDraw object associated with the new surface.
Incidentally, this method fills a surface-description structure (&ddsd) and returns a
pointer to the new surface (&lpDDS).
To call the IDirectDraw2::CreateSurface method, first dereference the
DirectDraw object's vtable, and then dereference the method from the vtable. The first
parameter supplied in the method is a reference to the DirectDraw object that has been
created and which invokes the method.
To illustrate the difference between calling a COM object method in C and C++, the
same method in C++ is shown below (C++ implicitly dereferences the lpVtbl parameter
and passes the ‘this’ pointer):
The lpDD parameter is a pointer to the DirectDraw structure that represents the
DirectDraw object.
Name Purpose
Aclapi Security API functions.
bzip2 Compression library.
Roids Arcade game.
Hello Hello world under Windows.
Htmldlg Calling a Java application that displays a dialog box from C.
Dll Simple DLL.
Intrinsic The intrinsics functions of lcc-win32.
Mandel Mandelbrot drawing.
Exetype Utility showing the type of executable of the given file: Windows or
console.
Service A sample service (Windows NT only).
Tasklist Shows the list of running processes.
Stdlib Many examples illustrating different functions of the standard library
of the C language.
Guidgen Utility to generate a Globally Unique Identifier (GUID). Located in
\lcc\src\utilities\guidgen.
Halftone The Halftone sample allows you to load and display bitmaps while
allowing you to dynamically changing the color filters that are
applied.
Errdecode Utility to show a clear text error description from the HRESULT or
WIN32 error codes. Located in \lcc\src\utilities\errdecode.
Uudecode Utility to transform binary files into a transportable ASCII
representation and back.
Gdidemo GDI window functions.
htmldlg A dialog that displays an html text.
Iconpro Icon management.
Wincapture Mouse capture.
Cpuid Displays information about the type of CPU that is running in your
machine.
Console Console (text mode) functions for managing the cursor, reading from
the screen buffer, setting the video modes, etc.
Perfmon Performance monitoring.
keyword: one of
A.1.3 Identifiers
identifier-nondigit:
nondigit
universal-character-name
nondigit: one of
_a b c d e f g h i j k l m n o p q r s t u v w x y z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
All characters from 127 to 25430
digit: one of
0 1 2 3 4 5 6 7 8 9
A.1.4 Universal character names
universal-character-name:
\u hex-quad
\U hex-quad hex-quad
hex-quad:
hexadecimal-digit hexadecimal-digit
hexadecimal-digit hexadecimal-digit
A.1.5 Constants
constant:
integer-constant
floating-constant
enumeration-constant
character-constant
Constants are either integers, floats, enums or character constants.
integer-constant:
decimal-constant integer-suffix opt
octal-constant integer-suffix opt
hexadecimal-constant integer-suffix (optional)
decimal-constant:
nonzero-digit
decimal-constant digit
octal-constant:
0 octal-constant octal-digit
hexadecimal-constant:
hexadecimal-prefix hexadecimal-digit
hexadecimal-constant hexadecimal-digit
30 Note that this is not strictly specified by the standard of the language and the programs accepted
by lcc-win32 may not compile in other processors.
A.1.7 Punctuators
punctuator: one of
[](){}.-> ++ -- & * + - ˜ ! /%<<>><><=>===!=ˆ|&&||
?:;... = *= /= %= += -= <<= >>= &= ˆ= |= ,###
<: :> <% %> %: %:%:
A.2.1 Expressions
primary-expression:
identifier
constant
33 The implementation of these two features has started, but will not be ready until July/August 2000.
A.2.2 Declarations
The purpose of declarations is to define the type of an object to the compiler.
declaration:
declaration-specifiers init-declarator-list opt ;
declaration-specifiers:
storage-class-specifier declaration-specifiers opt
type-specifier declaration-specifiers opt
type-qualifier declaration-specifiers opt
function-specifier declaration-specifiers opt
init-declarator-list:
init-declarator
init-declarator-list , init-declarator
init-declarator:
declarator
declarator = initializer
storage-class-specifier:
typedef No storage, just a compile time definition.
extern Storage is defined in another module.
static Storage is allocated in this module, but
not visible outside.
auto Stack storage in current frame.
register Integer variable may be stored in a machine
register.
type-specifier:
void
char
short
int
long
float
double
signed
unsigned
_Bool
_Complex
_Imaginary
struct-or-union-specifier
enum-specifier
typedef-name
_ _declspec(dllexport)
overloaded35
declarator:
34This specifiers are specific to the Windows system, and are not supported by other compilers in other
systems. Within the Windows system they are fairly common.
35 See the documentation for the overloaded keyword .
36 References, even if widely used in the C++ language are not strictly part of the C grammar.
37 Note that this is specific to lcc-win32, even if this type of operator redefinition is widely used in C++,
it is not a part of the C language.
38 Note that here is one of the few places where white space is significant in the language.
ftp.compapp.dcu.ie/pub/crypto/miracl.zip
I had worked a lot in the 1989 version, rewriting the essential parts of it in pure
assembly. It runs quite fast now, and I am convinced it is a very useful package.
Practical considerations:
Note that the bignum library is designed to work with the garbage collector. Most
operators that need to, for instance “+”, “-“ etc., return a new bignum, that will be
garbage collected automatically if it is no longer needed. This can be costly, and
if you prefer trading speed for notational convenience, you can use the normal C
interface and instead of writing:
you write:
In this latter case, you create only a single temporary that can later be reused. In
the former case, you create two. This is absolutely unnoticeable in MOST cases.
The convenience of the infix notation largely compensates the occasional stops
to collect unneeded structures. Of course, you can trade execution speed for
development speed.
Note that the public interface of the bignum library is an opaque data structure:
typedef struct _mp {
void *mp;
} pBignum;
The library is presented as a DLL. When loaded, the DLL will automatically initialize the
bignum system to a precision of 300 bits. You can change this using the BignumPrecision()
API.
Example:
This example prints the powers of two from 127 to zero.
#include <bignums.h>
int main(void)
{
pBignum a,b,c;
char buffer[4096];
c = newBignum(2);
for (int i = 127;i> 0;i--) {
b = newBignum(i);
a = quadpow(c,b);
quadformat(a,buffer);
printf("[%3d] %s\n",i,buffer);
}
return 0;
}
Output:
[127] 170141183460469231731687303715884105728
[126] 85070591730234615865843651857942052864
[125] 42535295865117307932921825928971026432
[124] 21267647932558653966460912964485513216
[123] 10633823966279326983230456482242756608
[122] 5316911983139663491615228241121378304
[121] 2658455991569831745807614120560689152
[120] 1329227995784915872903807060280344576
[119] 664613997892457936451903530140172288
…
Bignum implementation
Interface overview
Function Description
Initialization
int BignumPrecision(int); Sets the precision to a given value. Each
big number is represented as a vector of
integers. For each integer, the precision
increases of 30 bits. The argument is the
number of integers to reserve for each big
number. For instance, if you request a
precision of 30, 30 integers of 30 bits
precision will be used, i.e. 900 bits per big
number.
Creation
pBignum newBignum(void) Returns a new big number initialized to
zero
pBignum newBignum(int); Returns a new bignum initialized to the
given integer.
pBignum newBignum(double); Returns a new big number initialized to the
given double precision number.
pBignum newBignum(long long); Returns a new big number initialized to the
given long long integer.
pBignum newBignum(char *); Returns a new big number initialized to the
converted value of the given string.
Conversions
pBignum atoquad(char *); Converts the given string to a newly allocated
big number.
pBignum longToquad(long); Converts the given 32 bit integer,double
pBignum doubleToquad(double);
precision, or long long number to a newly
pBignum longlongToquad(long
long); allocated big number.
void long2quad(long,pBignum); Converts the given 32 bit integer or double
void
double2quad(double,pBignum);
precision number into a big number. Sotrage
is not allocated, the result is stored in the given
bignum, that must have been previously
allocated.
double quad2double(pBignum); Returns a double precision or a long long
long long quadToll(pBignum);
number from a big number.
Formatting
void quadexpformat(pBignum x, Formats a given big number “x” as text in the
unsigned char *outbuf, int
width, int decimals); buffer pointed to by “outbuf”, with the given
Limit Effect
More than 4095 characters in a string literal Warning message
More than 127 levels of nested statements Warning message
More than 1023 cases in a switch statement Warning message
More than 511 identifiers declared in a block Warning message
More than 65535 bytes in an object Warning message
More than 2147483647 bytes in an array Error
More than 1023 fields in a struct/union Warning message
More than 1023 enumeration members Warning message
More than 127 arguments to a function Warning message
More than 4095 external identifiers Warning message
More than 64 #if nesting levels Error
More than 128 evaluation levels in #if directive Error
More than 15 #include nesting levels Error
More than 256 arguments to a macro Error
The following books may be of interest for learning how to program under
Windows:
Programming Windows, Petzold (and Yao), MS Press
Charles Petzold wrote the original Windows programming 'bible' - "Programming
Windows" back in the mid eighties. Everyone who started Windows programming in
those days had (or needed) a copy of this book. Now updated for Win32, Petzold
starts the basic paradigms of Windows programming, Windows and message queues.
He goes on to cover many advanced topics. The book uses C and assumes a prior
knowledge of this language. I have tried to get all of the examples of this book to
work. If you find any problems please report them to me!
Windows 95 System Programming Secrets by Matt Pietrek
A good book to investigate. All low level details of the Win32 API. It complements
the explanations in the lcc-win32 technical reference very well.
These magazines are good references and can be useful for your work: