Hi!
It should probably be
- Exp -= (1 - EXCESS);
in EFtoF() and
- Exp += (1 - EXCESS);
in FtoEF(). The other way round.
No, this would break compatibility. The way to verify this. Write a driver, install it and send a packet to it, so to activate the test. Have the driver dump to WinDbg.
Suggestion to make it a little clearer: #define BIAS 127 Exp -+= (BIAS - 2);
I know about the IEEE bias. I'm just using my old 68k code that I'm comfortable with. I'll change this later with the Dc handle stuff I'm still testing.
Thanks, James
jimtabor schrieb:
No, this would break compatibility. The way to verify this. Write a driver, install it and send a packet to it, so to activate the test. Have the driver dump to WinDbg.
Ok, I take my time to go into this, because I *am* interested in compatibility.
Let's analyze how the conversion between FLOAT and EFLOAT works on XP. We could simply use some documentation floating around, but let's do it on our own, just for the fun. We don't need no itchy-bitchy-kmtest-driver-callback-winpooch-hooky-thingy, because Windows has already all we need to do this completely in user mode. DC_ATTR has some EFLOATs and what we need is a function that takes a FLOAT and stores it as EFLOAT. SetWorldTransform() seems suitable (In fact the values will be stored in the DC_ATTR structure only after a following call to GetWorldTransform()). And we need a windows compatible structure definition for DC_ATTR, wich we can get from a well known book. For the code see attachment.
Now let's see what we get with different parameters for the float:
f: 1.000000 (0x3f800000) -> lMant: 0x40000000, lExp: 0x000002 f: -1.000000 (0xbf800000) -> lMant: 0xc0000000, lExp: 0x000002 f: 2.000000 (0x40000000) -> lMant: 0x40000000, lExp: 0x000003 f: -2.000000 (0xc0000000) -> lMant: 0xc0000000, lExp: 0x000003 f: 1.500000 (0x3fc00000) -> lMant: 0x60000000, lExp: 0x000002 f: -1.500000 (0xbfc00000) -> lMant: 0xa0000000, lExp: 0x000002 f: 1235.000000 (0x449a6000) -> lMant: 0x4d300000, lExp: 0x00000c f: -1235.000000 (0xc49a6000) -> lMant: 0xb2d00000, lExp: 0x00000c
Looks like Feng Yuan was right. Now let's see what your code would do with f=1.
FtoEF( EFLOAT_S * efp, FLOATL f) {
... Exp = EXP(worker.l); // Exp = (((0x3f800000) >> 23L) & 0xFF) = 0x7F Mant = MANT(worker.l); // Mant = ((0x3f800000) & 0x7FFFFFL) = 0x00000
Mant = ((Mant << 7) | 0x40000000 | SIGN(worker.l)); // Mant = (0 << 7) | 0x40000000 | (0x3f800000 & 0x80000000 )= 0 | 0x40000000 | 0 = 0x40000000 Exp -= (1 - EXCESS); // Exp = 0x7F - (1-126) = 0x7F + 0x7D = 0xFC
efp->lMant = Mant; efp->lExp = Exp; ... }
Replace the - by a + and you get
Exp += (1 - EXCESS); // Exp = 0x7F + (1-126L) = 0x7F - 0x7D = 0x2
Wich is what we have discovered windows does.
And it looks like there's another thing, you didn't take into account. Ok, I give you a hint: It has something todo with the sign bit. You don't get it? Well, it's all there!
Thanks, Timo
typedef struct _GDI_TABLE_ENTRY { PVOID KernelData; /* Points to the kernel mode structure */ HANDLE ProcessId; /* process id that created the object, 0 for stock objects */ LONG Type; /* the first 16 bit is the object type including the stock obj flag, the last 16 bits is just the object type */ PVOID UserData; /* Points to the user mode structure, usually NULL though */ } GDI_TABLE_ENTRY, *PGDI_TABLE_ENTRY;
typedef PGDI_TABLE_ENTRY (CALLBACK * GDIQUERYPROC) (void);
#define GDI_HANDLE_COUNT 0x10000
#define GDI_HANDLE_INDEX_MASK (GDI_HANDLE_COUNT - 1)
#define GDI_HANDLE_GET_INDEX(h) \ (((ULONG_PTR)(h)) & GDI_HANDLE_INDEX_MASK)
typedef union { FLOAT f; ULONG l; } gxf_long;
typedef LONG FIX;
typedef struct _EFLOAT_S { LONG lMant; LONG lExp; } EFLOAT_S;
/* XFORM Structures */ typedef struct _MATRIX_S { EFLOAT_S efM11; EFLOAT_S efM12; EFLOAT_S efM21; EFLOAT_S efM22; EFLOAT_S efDx; EFLOAT_S efDy; FIX fxDx; FIX fxDy; FLONG flAccel; } MATRIX_S;
/* Structure definition taken from Feng Yuan's book "Windows Graphics Programming Win32 GDI and DirectDraw" */ typedef struct { void *pvLDC; DWORD SomeStuff1[7]; #if _WIN32_WINNT >= 0x0500 DWORD SomeStuff2[4]; // 0x20 #endif DWORD SomeStuff3[10]; // 0x030 #if _WIN32_WINNT >= 0x0500 DWORD SomeStuff4[8]; // 0x58 #endif DWORD SomeStuff5[7]; // 0x78 MATRIX_S mxWorldToDevice; // 0x94 MATRIX_S mxDeviceToWorld; // 0xD0 MATRIX_S mxWorldToPage; // 0x10C // More stuff we don't need } DC_ATTR, *PDC_ATTR;
Hi! Yes! I will fix it. Thanks, James