Professional Documents
Culture Documents
© by
Heinz Rongen
Forschungszentrum Jülich
Zentrallabor für Elektronik
52425 Jülich, Germany
email: H.Rongen@fz-juelich.de
Programmers use DLLs to provide code that they can reuse and to
parcel out distinct jobs.
Unlike an executable (EXE) file, a DLL cannot be directly run.
DLLs must be called from other code that is already executing.
In more understandable words, a DLL is a file which does a particular job, and allows
other programs to use its efforts in assisting the program's job. Some programs use a
DLL so that they won't need to spend time figuring out how to do that job. For
example, Microsoft has a DLL comctl32.dll which does all the user interface jobs
(toolbars, text boxes, scroll bars, etc). So, other programs use that DLL so they won't
have to create their own edit boxes, etc.
When a program requires a DLL to run, and can't find it, it won't be able to run
because its suddenly missing the DLL to perform some of its critical work. We've all
used DLLs before and we're using them now. They're required to run all Windows
programs, including Windows but you never actually see them at work. There are
different versions of the same file name. Just because the file appears to be the
same doesn't mean it is. To check what version the file is, open Windows Explorer,
locate the file and right click on it. Select Properties and click on the Version tab. If
there is no version tab then the file does not have a version number. Generally, if you
have a newer version of a file, don't replace it with an older version. Due to popular
request, we are slowly adding version numbers to each individual file. This will take
quite a while. Please bear with us.
Note: Many times, DLLs are placed in files with different extensions such as .EXE,
.DRV or .DLL.
Applications and DLLs can link to other DLLs automatically if the DLL linkage is
specified in the IMPORTS section of the module definition file as part of the compile
or you can explicitly load them using the Windows LoadLibrary function.
#include <windows.h>
switch (fdwReason)
{
case DLL_PROCESS_ATTACH: break;
}
return (TRUE);
}
Note: the Dll-Entry-Point function name is different for different Compiler systems:
in Borland C/C++: DllEntryPoint
in Microsoft Visual C/C++: DllMain
In this example, we will create a VI that calls only one of these functions. As a further
exercise on your own, create VIs that use the Call Library Function to use the other
functions in the DLL.
After the listing of the source code for the DLL, you will also find listing for the custom
header file, ourdll.h.
switch (fdwReason)
{
case DLL_PROCESS_ATTACH: break;
}
return (TRUE);
}
in Microsoft C++:
_declspec (dllexport) DWORD Func1 (DWORD a, DWORD b);
_declspec (dllexport) long avg_num (float *a, long size, float *avg);
LIBRARY ourDLL
EXPORTS Func1
avg_num
As specified in the previous diagram, first specify the location of the DLL by typing in
the path name. Also specify the name of the function you want to call in the DLL. In
this case it is avg_num. The calling convention for this function in the DLL is C.
The return type is Signed 32-bit Integer. The parameters to the function are an Array
Data Pointer to 4-byte Single precision floating point numbers, a 32-bit Signed
Integer which contains the size of the array, and a pointer to a 4-byte Single precision
floating point value, which will return the average of the elements in the array. Create
the front panel shown in the Figure.
Then, connect the appropriate controls and indicators to the Call Library Function
icon.
The Pascal string format is nearly identical to the LabVIEW string format, but instead
of storing the length of the string as a signed 32-bit integer, it is stored as an
unsigned 8-bit integer. This limits the length of a Pascal style string to 255
Note: To use the LabVIEW CIN function calls you must add labview.lib to your
project if you are using the Visual C++ compiler, or add labview.sym.lib to your
project if you are using the Symantec compiler.
extern „C”
{
/* your function prototypes here */
}
After properly configuring the Call Library Function, run the VI. If it does not run
successfully, you might get errors or a General Protection Fault. If you get a General
Protection Fault, there are several possible causes. First, make sure that you are
passing exactly the parameters that the function in the DLL expects. For example,
make sure that you are passing an int16 and not an int32 when the function expects
int16. Also confirm that you are using the correct calling convention _stdcall or C.
Calling the DLL from another C program is also an excellent way to debug your DLL.
By doing this, you have a means of testing your DLL independent of LabVIEW, thus
helping you identify possible problems sooner.
PC add on boards are either I/O or Memory mapped into the System address space.
The PC uses 32 bit addresses for memory and 16 bit addresses for I/O. For I/O this
means we have maximum 65536 I/O addresses (0..FFFF). The ISA Bus only
decodes the lower 10 address lines, resulting in a I/O address range from 0..3FF
(1024 I/O addresses) . PCI devices can use the full I/O address range up to FFFF.
Access to the hardware is done with a normal memory access instructions for
memory mapped add on board, or with port I/O instructions for I/O mapped devices.
16 bit OS
32 bit OS
With 16 bit Windows-OS you have full access to all I/O and memory mapped devices
from the Application layer. (DLL running at application level)
In 32 bit Windows-OS hardware access is only possible with a “Kernel Mode Device
Driver”.
Abstract
ISA add-in cards use IO address aliasing to get around the limited IO space available
in standard PC-compatibles. This aliasing (and the dependence upon it) means that
PCI devices must never require more than 256 bytes of contiguous IO space.
Introduction
This paper describes what ISA aliasing is and how it came into existence. Once ISA
aliasing is understood, the obvious requirements on PCI devices are discussed.
This paper is motivated by encounters with PCI devices that have required more than
256 bytes of IO space. These devices will cause problems in systems also having an
ISA bus. How the problem shows up depends on the particular system, but
symptoms include:
♦ the BIOS is unable to initialize the PCI device
(because the BIOS will not allocate an IO space larger than 256 bytes)
♦ ISA devices (that use IO aliasing) quit working,
♦ or won't work when the PCI device is in the system.
ISA Aliasing
Many years ago, when IBM first introduced its' "PC", the architecture for that system
was such that motherboard devices only decoded the lower ten address lines for IO
space addresses This effectively limited the IO space of these early PCs to 1K bytes
(210). The system design further mandated that of these 1K bytes of IO ports, the
first 256 (addresses 0 thru 255) were reserved for motherboard devices, and the rest
(addresses 256 thru 1023) were available for add-in devices.
The Figure below shows how 16-bit IO addresses were decoded in these early
systems.
15 10 9 8 7 0
xxxxxx
Some years later, the motherboard standard changed such that the upper six bits of
the IO address were no longer don't-cares. Motherboard devices then did a full 16-
bit decode and still tended to exist in the first 256 bytes of the IO space. This should
have allowed the full IO space (64K) to be used. However, by this time there were
many add-in cards that only did a 10-bit decode, so while motherboards were doing
a full 16-bit decode, add-in cards still only looked at the bottom ten bits. This
effectively fragmented the IO address space such that for each 1K (210) chunk of IO
space the bottom 256 bytes are available for full 16-bit decode while the upper 768
bytes are unusable because ISA cards are doing only a 10-bit decode.
Writing DLLs and LabView: (16)
10-bit decode
0xX900 0xD000
0xX800 16-bit decode
10-bit decode
0xX500
0xX400 16-bit decode 0x2000
10-bit decode
0xX100 0x1000
0xX000 16-bit decode
0x0000
This fragmentation essentially left ISA add-in cards a total of 768 IO locations to
perform whatever functions they wanted to perform. The sheer numbers of add-in
cards led to compatibility problems because two ISA cards would end up claiming the
same IO addresses leading to one (or both) cards not working. Some defacto
standards arose where certain classes of devices got certain IO locations, but these
have not been sufficient for some functions.
Many ISA add-in cards have gotten around this limitation by claiming a small number
of locations in the 10-bit range, and then using 16-bit aliases of those location to map
other device registers. For instance, if an ISA device uses the 10-bit address 0x300,
it can also use the 16-bit aliases of that address (0x1300, 0x2300, ..., 0x0700,
0x1700, 0x2700, ..., 0x0B00, 0x1B00, 0x2B00, ..., 0x0F00, 0x1F00, 0x2F00, ...). For
every IO location in the 10-bit decode area, there are 63 16-bit aliases of that
location.