views:

122

answers:

3

Help! I am receiving this error when viewing the contents of an inbound function parameters in my Delphi 4 application.

The code calls a function in a dll with 3 parameters (app.handle, pchar, boolean)

The declaring function is in externs.pas and declared as:

function AdjustVoucherDifference(hOwner :HWnd; Receipt_ID :PChar; 
  bCommit: Boolean): boolean; stdcall; 
  external 'FBCoupon.dll' name 'AdjustVoucherDifference';

in another source file, the code calls it as:

AdjustVoucherDifference(Application.Handle, PChar(Receipt_ID), true);

When stepping through the code in debug mode, I can see valid values in the source file, but when it breaks on the line in externs.pas, the tooltip for the values (or CTRL+F7) shows that the symbols have been eliminated from the linker and I receive exceptions when the execution is in the dll.

The DLL is developed in CBuilder4 and the particular function is declared as:

BOOL __stdcall __DLLTYPE__ AdjustVoucherDifference(HWND hOwner, 
  char *receipt_id, bool commit);

Compiler optimization is turned off.

Thanks!!!

+1  A: 

The linker isn't affected by compiler optimizations. The linker will "smartlink out" any routine that it can prove is will never be called in your program. Unfortunately, this means it's not available for the debugger to call into.

My solution to this, when it's happened to me in the past, is generally to put a meaningless call to the routine in question in an initialization section. The smartlinker won't mess with those. Can you do this without causing any errors?

initialization
  AdjustVoucherDifference(0, '', true); //DO NOT SMARTLINK THIS OUT!
end;
Mason Wheeler
Mason, thanks for your reply, I tried it in the initialization section and received a runtime error. The linker sees the function, but does not recognize the parameters.... very strange.
Dennis
I remember Danny Thorpe's magical touch method: `procedure Touch(var arg); begin end;` which outsmarts both the compiler and linker.
Jeroen Pluimers
Jeroen, worked perfectly!!! Thanks so much, the new build is on its way to QA :)
Dennis
@Dennis: Hmm. If "touching" the external proc changes the behavior, take a closer look at the context in which you're calling the external proc. The linker thinks that your call isn't being used by the program, which means the body of code that contains the call isn't being used by the program. This could be a linker bug. Needs to be checked out and reported, because stuff that goes away magically has a bad habit of coming back.
dthorpe
thanks for the heads up dthorpe. These lines of code have not been modified for a long time. I really don't understand how it could just pop up like that. This function is an external call into a dll, so the body of code is extant to the program. Never ran across this one before. Unresolved Symbols are easier to understand than the linker just dropping parameters.
Dennis
+1  A: 

Note that BOOL and Boolean are different. BOOL is defined in Windows.pas as

type
  BOOL = LongBool;

so SizeOf(BOOL) = 4 while SizeOf(Boolean) = 1

Even if it would not help you with your problem, replace Boolean by BOOL (or LongBool) in Delphi declaration to make the declaration correct.

Serg
+4  A: 
  1. Set a breakpoint before the call to the external function (not a breakpoint on the external declaration).
  2. Open the debugger disassembly window. (I forget the exact menu path to get there)
  3. Step through the machine instructions one at a time. You don't need to understand all of them (though it doesn't hurt), but keep a sharp eye out for jump and call instructions.
  4. There will be a bit of chatter as the code sets up the parameters for the call, then a call instruction.
  5. Follow (step into) the call instruction. Since this is an external call, expect to see a jump indirect instruction.
  6. Follow that jump to its destination. You should now be inside the C++ DLL. If you built the DLL in CBuilder with debug info, you should have symbol info and source line info as well.

If your parameter declarations on the Delphi side don't match the expectations on the C++ side, then you should start to see things going awry on the C++ side of the call, which could lead to an access violation exception or a runtime error generated by the C++ dll.

dthorpe
+1 for the recipe on how to diagnose where things are going wrong
Marjan Venema