Microsoft Excel is polymorphic. Cells can hold many different types of values: strings, numbers, arrays, error values, or logical values. Internally, this is accomplished by using a special, 10-byte data type called an XLOPER. Every XLOPER has 2 bytes that indicate the type of data and 8 bytes that indicate the actual data. The 8 bytes are used differently, depending on the data type — sometimes they contain a pointer to data that is stored elsewhere.
Note
Although the actual size of an XLOPER is 10 bytes, the effective size may vary depending upon the operating system. C compilers and/or CPUs are frequently more efficient when structures are aligned on fixed byte boundaries. Under Win16 the preferred alignment is 2 bytes, and the effective size remains 10 bytes. Under Win32 the preferred alignment is 8 bytes. The best way to handle this is to set the Struct Member Alignment to 8 bytes. This is the default value in Microsoft Visual C++. This increases the effective size of an XLOPER to 16 bytes under Win32.
There are 12 different types of XLOPERs. You specify a type by entering a type constant in the xltype field of the XLOPER. The type constants are defined for you in XLCALL.H and are listed in the following table.
Type constant |
xltype |
Type of value | ||
xltypeNum |
0x0001 |
Numeric (IEEE floating-point) | ||
xltypeStr |
0x0002 |
String (byte-counted) | ||
xltypeBool |
0x0004 |
Logical (TRUE or FALSE) | ||
xltypeRef |
0x0008 |
General reference (external and/or disjoint) | ||
xltypeErr |
0x0010 |
Error | ||
xltypeFlow |
0x0020 |
Flow control in a macro | ||
xltypeMulti |
0x0040 |
Array | ||
xltypeMissing |
0x0080 |
Missing argument in a function call | ||
xltypeNil |
0x0100 |
None (for example, an empty cell) | ||
xltypeSRef |
0x0400 |
Single rectangular reference to current sheet | ||
xltypeInt |
0x0800 |
Integer (rarely used; use xltypeNum) | ||
xltypeBigData |
0x0802 |
Persistent data storage |
The file XLCALL.H contains the definition of the XLOPER structure. In Windows, the definition appears as follows:
typedef struct xloper
{
union
{
double num; /* xltypeNum */
LPSTR str; /* xltypeStr */
WORD bool; /* xltypeBool */
WORD err; /* xltypeErr */
short int w; /* xltypeInt */
struct
{
WORD count; /* always = 1 */
XLREF ref;
} sref; /* xltypeSRef */
struct
{
XLMREF *lpmref;
DWORD idSheet;
} mref; /* xltypeRef */
struct
{
struct xloper *lparray;
WORD rows;
WORD columns;
} array; /* xltypeMulti */
struct
{
union
{
short int level; /* xlflowRestart */
short int tbctrl; /* xlflowPause */
DWORD idSheet; /* xlflowGoto */
} valflow;
WORD rw; /* xlflowGoto */
BYTE col; /* xlflowGoto */
BYTE xlflow;
} flow; /* xltypeFlow */
struct
{
union
{
BYTE *lpbData; /* data passed in */
HANDLE hdata; /* data returned */
} h;
long cbData;
} bigdata; /* xltypeBigData */
} val;
WORD xltype;
} XLOPER, *LPXLOPER;
typedef struct xlref
{
WORD rwFirst;
WORD rwLast;
BYTE colFirst;
BYTE colLast;
} XLREF, *LPXLREF;
typedef struct xlmref
{
WORD count;
XLREF reftbl[1]; /* actually reftbl[count] */
} XLMREF, *LPXLMREF;
Following are diagrams of the various types of XLOPERs.
Caution
When you get string XLOPERs from Microsoft Excel, they are not always null-terminated! Do not attempt to pass them directly to C string-handling functions, such as strcpy(), that expect null-terminated strings.
Note
Be sure to use an unsigned char or (BYTE) for the byte count. This is important, because otherwise it is possible to create negative string lengths. For example:
LPSTR s;
WORD w;
w = s[0]; /* Bad */
w = (BYTE) s[0]; /* Good */
For more information, see "Advanced Flow Control in Macro Sheets" on page 191.
The following are some examples showing how to construct various types of XLOPERs in C. As a convention, XLOPER variable names start with a lowercase "x."
XLOPER xInt;
xInt.xltype = xltypeInt;
xInt.val.w = 27;
XLOPER xPi;
xPi.xltype = xltypeNum;
xPi.val.num = 3.141592654;
XLOPER xStr;
xStr.xltype = xltypeStr;
xStr.val.str = (LPSTR)"\014Excel String";
/* Notice the octal byte count in front of the string. */
XLOPER xBool;
xBool.xltype = xltypeBool;
xBool.val.bool = 1;
XLOPER xZeroDivide;
xZeroDivide.xltype = xltypeErr;
xZeroDivide.val.err = xlerrDiv0;
XLOPER rgx[2];
XLOPER xArray;
rgx[0].xltype = rgx[1].xltype = xltypeInt;
rgx[0].val.w = 1;
rgx[1].val.w = 2;
xArray.xltype = xltypeMulti;
xArray.val.array.lparray = (LPXLOPER) &(rgx[0]);
xArray.val.array.rows = 1;
xArray.val.array.columns = 2;
XLOPER xData;
xData.xltype = xltypeBigData;
xData.val.bigdata.h.lpbData = lpbData; // pointer to the data
xData.val.bigdata.cbData = cbData; // data length in bytes
For more information about using bigdata XLOPERs, see "Persistent Storage" on page 175.