Menu

Exception on executing DLL function

2009-03-23
2012-09-26
  • Krzysztof Korpiela

    Hello,

    I have my DLL built with MSVC; everything is exported using "declspec(dllexport) stdcall" (aimed to be used with Delphi) and with use of def file.
    I load the DLL in DevCpp for testing:

    include <cstdlib>

    include <iostream>

    include "windows.h"

    include <conio.h>

    typedef void (*_Function)(int, int, int);

    int main(int argc, char *argv[])
    {
    _Function Function;

    LibH = LoadLibrary("library.dll");
    if (LibH)
    {
    Function = (_Function)GetProcAddress(LibH, "ChannelMessage");
    ...
    }

    if (Function) Function(0x90, 48, 100); getch();
    Function(0x80, 48, 0); getch(); // <--------------

    FreeLibrary(hInstLibrary);

    system("PAUSE");
    return EXIT_SUCCESS;
    }

    When any imported function is called once, everything's OK. But the application throws an exception anytime I call same function again (I marked the line in example code above with "<-----------"). What might be the cause?

    Thanks,
    Krzysiek

     
    • Krzysztof Korpiela

      works with no problem under Turbo Delphi - thanks again for pointing me it out.

       
    • Krzysztof Korpiela

      > FreeLibrary(hInstLibrary);

      sorry, of course I meant: FreeLibrary(LibH);

       
    • cpns

      cpns - 2009-03-23

      The code:


      if (Function) Function(0x90, 48, 100); getch();
      Function(0x80, 48, 0); getch(); // <--------------


      Is the same as:

      if (Function)
      {
      Function(0x90, 48, 100);
      }

      getch();
      Function(0x80, 48, 0); getch();


      It seems unlikely that is what you intended, since the second call would get called (and fail) even if Function were NULL. Is it possible that Function is in fact NULL and the call that is protected by the if() is never called?

      You are using C++, but C++ name mangling is not compatible between compilers, so to make this function callable it must be declared to have C linkage. http://en.wikipedia.org/wiki/Compatibility_of_C_and_C%2B%2B#Linking_C_and_C.2B.2B_code

      So in the DLL code the function must have a construct such as:


      ifdef __cplusplus

      extern "C" {

      endif

      void ChannelMessage( int, int, int ) ;

      ifdef __cplusplus / If this is a C++ compiler, end C linkage /

      }

      endif


      Of course if you did that already, or compiled the MSVC++ code as C rather than C++, then the problem is something else.

      If you are not in a position to recompile the DLL, then you will have to use a DLL browser to determine the 'mangled' name, and use that rather than the unadorned "ChannelMessage".

      Clifford

       
    • Krzysztof Korpiela

      Thanks a lot for detailed explanation.

      On the second call of "Function" I did not used the "if (Function)" condition becase the function address validity has been already checked in the previous call.

      > Is it possible that Function is in fact NULL and the call that is protected by the if() is never called?

      The first time "Function" is called, it is executed properly. For the second time it crashes (I tried "if (Function)" statement for each call before as well, but this does not affect anything - so the address isn't NULL but the second call fails for some reason). Note that the crashes are not Function-body related, i.e. the problem occurs to any function (not always though).

      > http://en.wikipedia.org/wiki/Compatibility_of_C_and_C%2B%2B#Linking_C_and_C.2B.2B_code

      thanks for the interesting link, will look at that closer, I have a feeling this must be some incompatibility issue.

      > #ifdef __cplusplus
      > extern "C" {
      > #endif

      yes, I have these applied already (as well as __stdcall which is required for Delphi - maybe here is the problem?). Another DLL compilation isn't a problem too. Also let me mention that all the functions in this DLL already work in Delphi, but since I do not own license for commercial use, I cannot use the PE version for testing.

      Best regards,
      Krzysiek

       
    • cpns

      cpns - 2009-03-24

      > On the second call of "Function" I did not used the "if (Function)" condition
      > becase the function address validity has been already checked in the
      > previous call.

      Huh!? If the test fails, the second call to Function will still be attempted and will fail, so the test is pointless. It has to apply to all such calls or non at all. Look again at my 'equivalent' code, only the first Function() call is conditional. Both getch() calls and the second Function() call get invoked regardless. That would be very unusual if that is what you intended. The code should be:


      if (Function)
      {
      Function(0x90, 48, 100);
      getch();
      Function(0x80, 48, 0);
      getch();
      }


      See that all the conditional statements are in the block delimited by {...}.

      > Note that the crashes are not Function-body related

      We'll have to take your word for that, but it cannot be taken as a given unless you also provide that code. Given your naive justification for your 'dangerous' code, I am assuming that you are not a good arbiter of what is and is not safe code, so I have to assume all bets are off regarding the code in the DLL. Whatever the flaw is, apart from the flaw I pointed out, there is nothing wrong in the code you posted, so you can see why I suspect the code we cannot see.

      My guess is that the function being called is corrupting the stack and invalidating the pointer. Use the debugger to check that the pointer value is not changing between the calls or shine some light on your code as follows (currently you are fumbling in the dark):

      include <cstdlib>

      include <iostream>

      include "windows.h"

      include <conio.h>

      typedef void (*_Function)(int, int, int);

      int main(int argc, char *argv[])
      {
      _Function Function;
      static _Function errorcheck ;

      LibH = LoadLibrary("library.dll");
      if (LibH)
      {
      Function = (_Function)GetProcAddress(LibH, "ChannelMessage");
      ...
      }

      if (Function)
      {
      errorcheck = Function ;
      printf( "Before call Function = 0x%p\n", Function ) ;
      Function(0x90, 48, 100);
      printf( "After call Function = 0x%p\n", Function ) ;
      getch();

      if( errorcheck != Function )
      {
          printf( &quot;Error: Function call corrupted stack\n&quot; ) ;
      }
      else
      {
          Function(0x80, 48, 0);  
      }
      

      }
      else
      {
      printf( "Error: Function not found in DLL\n" ) ;
      }
      getch();

      FreeLibrary(hInstLibrary);

      system("PAUSE");
      return EXIT_SUCCESS;
      }

      > but since I do not own license for commercial use

      Might this be useful?: http://www.turboexplorer.com/delphi

       
    • Krzysztof Korpiela

      thanks for your time.

      > If the test fails, the second call to Function will still be attempted and will fail

      Yes of course I will keep checking all the time, it is safer. The thing is that the first call never failed to me. The pointed address remains the same before and after calling the function (0x1001A4E0). But I unnecessarily removed the check in code causing the confussion here. By the way - normally the called function should not affect the pointer just like that, am I right (i.e. unless function by some invalid operation invalidates the pointer)?

      > We'll have to take your word for that, but it cannot be taken as a given unless you also provide that code.

      Yes, I can't tell for sure, because my part of code is mostly just wrapping the DLL functions wrote by someone else. But at the same time these functions executed in Delphi several times do not cause any errors. But I must check that code anyway.

      > Might this be useful?: http://www.turboexplorer.com/delphi

      great tip, thanks! Btw. this is weird that the download link leads to the trial downloads at downloads.embarcadero.com and it is said to function for 14 days, while everywhere else I can see it is free and both for commercial and noncommercial. I'll give it a try.

      Best regards,
      Krzysiek

       

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.