In the old days, when you wrote a program, you had full control over the CPU. The Instruction Pointer would always point to code that you wrote, and never anywhere else. That means if you wanted to do any kind of input/output, you had to write it yourself. Need a key from the keyboard? Get it yourself. Need to write a character to the output device? Display it yourself. (Relaxen und watchen das blinkenlights. What lights?) You had to write your own code to support both Monochrome and Color Graphics Adapters, dot matrix and laser printers, etc. When a new graphics card/printer came out, all application developers had to scramble to write/test/deploy a new driver. I remember writing my own keyboard input and teletype output routines. BASIC (Beginners All Purpose Symbolic Instruction Code), Focal (my first programming language in 1971) and other languages evolved and helped to insulate the user from the nitty gritty details.
Eventually, people wrote libraries of routines that could be reused. Some of these were shared with others. After a while, these were bundled together in something called an Operating System.
Along came the idea of an Operating System, which had reusable code that could handle things like input/output. Not only did this make things easier for the programmer, but the I/O became standardized. No longer did you have to write a zillion printer or display drivers to ship with your application. Getting user input and displaying information on the screen became more uniform, both to the programmer and the user. Standardizing was a GOOD idea!
Imagine if electrical outlets had different sizes/shapes depending on which room of a building you’re in (actually, this is true if one room is in Europe and one is in the
In order for the Operating System to work, there had to be some mechanism for the user code to call the OS functions. On a PDP-11, there was the EMT (Emulator Trap) instruction, which was a synchronous interrupt. Interrupts are used because they can cause the CPU to switch modes, as from the highly protected User mode to the less restricted Kernel mode.
Windows XP API calls will execute some initial code and then, if a kernel mode switch is required, uses the SYSENTER ASM instruction. (see Great post about "How system calls work").
A program module like an EXE, DLL, OCX, etc. is a PE file (Portable Executable: see c:\Program Files\Microsoft Visual Studio 8\Vc\PlatformSDK\Include\winnt.h) file. These files usually contain executable code, which often has calls to other functions in other modules. These “dependencies” can be on Windows components, such as kernel32.dll, user32.dll, on user written code (like FLLs or COM DLLs), or even on 3rd party components.
When a module is loaded, the Operating System program loader ensures any dependent modules are loaded into memory. Modules can have a preferred load addresses. There are possible collisions at a particular address, so the loader will choose a different address for a module. Any inter module calls are patched to the correct addresses.
These are called statically linked function calls. Another way to call functions is to load and call them dynamically using the LoadLibrary and GetProcAddress APIs. These will cause modules to be loaded in the process address space after the initial module of a process starts executing. That’s how DECLARE DLL works in VFP.
The code below shows that VFP9 is statically linked to 872 functions in 18 DLLs. However, Inspect your memory image and see fragmentation shows about 83 modules actually loaded when VFP is up and running.
- The 18 dependent static DLLs may each have their own dependencies
- Perhaps some modules were loaded via LoadLibrary.
Challenge: Modify the code below to search through dependent modules found to find out the total number of statically linked DLLs
CREATE CURSOR imports (Module c(40),address c(10),FuncName c(40))
cVars=LOCFILE("c:\Program Files\Microsoft Visual Studio 8\Vc\bin\vcvars32.bat") && VS2005
* cVars=LOCFILE("c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\bin\vcvars32.bat") && VS2003
TEXT TO mybat TEXTMERGE NOSHOW
dumpbin /imports "<<_vfp.fullname>>" > c:\t.txt
!cmd /c t.bat
FOR i = 1 TO nLines
IF cLine=" Summary"
IF !EMPTY(cLine) AND LEFT(cLine,4)=" "
IF SUBSTR(cLine,5)!=' '
IF LEFT(cline,8) = SPACE(8)
m.Address = GETWORDNUM(cline,1)
m.FuncName = GETWORDNUM(cline,2)
IF m.FuncName != "Import" AND "0" != m.address
INSERT INTO imports FROM MEMVAR