Lynn McGuire said:
I have created a test app at
www.winsim.com/testdll.zip
When I open testdll.xls and look at CommandButton1_Click, the relevant code
that I see is a call to InitTestDLL.
When I look at InitTestDLL in testdll.c, the relevant code that I see is:
1. The chptst calculation, which is displayed using MessageBox.
2. A call to capsmn().
3. A call to checkMathCoprocessorStatus [sic].
When I look at checkMathCoprocessorStatus, the relevant code that I see is:
1. old87Control = _control87 (0, 0).
2. Commented-out code that might change the FP control word (FPCW).
3. new87result = _control87 (0, 0)
4. A call to MessageBox to display old87Control and new87Result.
Lynn McGuire said:
Just load testdll.xls into Excel (I am using Excel
2003 but any should work OK). Then press the RUN
button on the spreadsheet. The first time, all is
OK. The second time, the chptst calc in the C DLL
code exhibits the calc failure
By "OK", I presume you mean chptst is exactly zero. And by "failure", I
presume you mean that chptst is non-zero, namely about 2.851266E-10.
And that is indeed what I observe, as well, when I execute
CommandButton1_Click in testdll.xls.
But that behavior makes no sense based on my summary of the InitTestDLL and
checkMathCoprocessorStatus functions above.
(See the speculative explanation at the end below.)
The first time InitTestDLL is called, the FPCW should be set according to
VBA. We know that _PC_64 + _RC_NEAR. So chptst should be the non-zero
value ("failure").
The second time InitTestDLL is called, __if__ the FPCW were set to _RC_53,
chptst should be zero ("OK").
I believe my summaries above are correct.
So I conclude that the testdll.c file in the testdll.zip archive is __not__
the same(!) as the one used to create testdll.dll.
That is readily apparent since, at a minimum, the checkMathCoprocessorStatus
function in that testdll.c file has every line commented out that might
alter the state of the FPCW. So it would not modify the FPCW at all(!).
If you want to discuss this further with me, you will have to use the files
that I put into lynntest.zip, which you can download from
http://www.box.com/s/cedabb54b1026fce5f46.
There you will find a "clean" (distilled) implementation of InitTestDLL and
setMathCoprocessorStatus (now correctly named for its function), along with
a much-simplified VBA file.
Use testdll.c, testdll.h and testdll.def to create lynntest.dll with your
compiler. (I used VC++.)
Import lynntest.bas into VBA to test the behavior of InitTestDLL.
Note that you must the correct Lib path "C:\yourPathTo". And you need to
execute doit() manually (press F5), since I did not bother to set up a
"button" in Excel.
When I execute doit()....
1. The first time, chptst is non-zero, the old FPCW is 0xc001f, and the new
FPCW is 0xd001f, all as expected.
2. The subsequent times, chptst is zero, and the old and new FPCW are
0xd001f, again all as expected.
If you get different results(!) from those files, unmodified except for
"C:\yourPathTo", I would be surprised. Please let us know in either case.
Assuming you get the same results, use those files to correct your
implementation.
PS: It you do not want to call setMathCoprocessorStatus within your DLL
code, as you said before, I have declared setMathCoprocessorStatus to you
can all it (once?) from VBA.
But as I believe I explained previously, you must call it once for each
"execution" of VBA -- that is, from each function that you might call form
an Excel formula, and from each of the first "sub" procedures that you
invoke either manually or using Excel "buttons".
-----
Speculative explanation of the behavior of your testdll.xls and testdll.dll
.....
When I execute CommandButton1_Click in testdll.xls:
1. The first time, the old FPCW is 0x127f and the new FPCW is 0x137f.
2. Subsequent times, the old and new FPCW are 0x137f.
Note that _control87 returns an __abstraction__ of the machine FP control
word. I suspect you are expecting the _control87 values to be the same as
the machine FP control word. They are not.
Note that for _control87, 0xN2NN represents _RC_UP and 0xN3NN represents
_RC_CHOP. That might explain why chptst is zero the first time, but
non-zero subsequent times.
I suspect that when you built testdll.dll, you uncommented the following
line to set the FPCW:
new87result = _control87 (0x27f, 0xffff);
There we see 0x2NN, which would set _RC_UP(!). Look at the definitions of
the _control87 parameters in <float.h> and in
http://msdn.microsoft.com/en-us/library/e9b52ceh(v=vs.80).aspx.
I suspect you chose 0x27f, in part, because 0x2NN does indeed represent
53-bit precision in the machine FP control word. But as I noted above, that
is not the same format of the "FPCW" used as input for and output from
_control87.
We do not see where you set _control87(0x37f,0xffff). But I suspect you did
just that in the version of testdll.c that you used to create testdll.dll.
As I noted before, it is readily apparent the testdll.c included in
testdll.zip is not the version of testdll.c that you used to create
testdll.dll.
It would surprise me if _control87 itself changed _RC_UP to _RC_CHOP. But
since we do not know how _control87 is implemented, and since it is
obviously returning some undocumented bits, it is possible that a faulty
implementation within _control87 is responding incorrectly to the
undocumented bits that you set.