ID Number: Q69897
3.00
WINDOWS
Summary:
Using variable argument lists in functions in Windows dynamic-link
libraries (DLLs) immediately suggests problems because the current
data segment is not the same as the current stack segment (DS != SS).
However, it is possible to create functions declared with the C
calling convention (_cdecl) that can properly access variable argument
lists from Windows DLLs using the Windows Software Development Kit
(SDK) version 3.00.
More Information:
In the STDARG.H file included with the Windows SDK, macros are defined
to manipulate variable argument lists. Because DS != SS in DLLs
containing code and data segments, the standard macros will not
perform properly in small-model or medium-model DLLs. The standard
macros assume that the stack segment (SS) and data segment (DS) are
equal for far-data models and use NEAR pointers to access the
arguments. However, small-model and medium-model DLLs containing code
and data segments use the calling application's SS and the DLL's DS.
The standard macros fail to account for this case.
If the DLL is a code-only DLL where DS == SS (using the DATA NONE
declaration), or if the DLL is large-model, the standard macros will
work properly.
One way to overcome the problems with the standard macros is to define
a new set of macros for use with Windows' DLLs. For example:
/****************************************************************
*
* File: wstdarg.h
*
* Remarks: Macro definitions for variable argument lists
* used in DLLs
*
****************************************************************/
typedef char _far *wva_list ;
#define wva_start( ap, v ) (ap = (wva_list) &v + sizeof( v ))
#define wva_arg( ap, t ) (((t _far *)(ap += sizeof( t )))[-1])
#define wva_end( ap ) (ap = NULL)
/****************************************************************
* End of File: wstdarg.h
****************************************************************/
When these macros are compiled, the stack segment is properly selected
to access the arguments.
Please note the following caveats concerning the use of variable
argument lists in DLLs:
1. When passing arguments by reference, always use FAR pointer
declarations. The compiler will synthesize FAR pointers by pushing
the DS and the offset of the memory location on to the stack. This
will provide the DLL will the proper information to access the
application's data segment.
Also note:
If the application under development will be run under real mode,
avoid calling functions that will yield control from the DLL. If
yielding occurs, the data segment could be moved. Movement would
result in invalid pointers.
2. Because functions with variable arguments are defined using _cdecl,
all pointer arguments not declared in the parameter list must be
typecast in the function call. If this casting is not done,
unpredictable results will occur due to the lack of the function
parameter prototype. For example:
void FAR _cdecl DebugPrint( LPSTR lpStr, LPSTR lpFmt, ... )
...
DebugPrint( szValue, "%s, value passed: %d\r\n",
(LPSTR) "DebugPrint() called", (int) 10 ) ;
3. When the function is exported or imported, it must be declared with
an underscore (_) prefix in the .DEF file. It is also necessary to
preserve uppercase and lowercase letters in the function name.
Here is the declaration for the function above:
EXPORTS
WEP @1 RESIDENTNAME
_DebugPrint @2
4. Variable argument C run-time library functions such as vsprintf()
and vfprintf() do not take into account that DS != SS. These
functions are not available in DLLs.