Link to home
Start Free TrialLog in
Avatar of kodiak1
kodiak1

asked on

Basics for setting up a C++ DLL for VB

I've been trying to call a C function from a VB project, but keep getting a run-time error '453': Can't find DLL entry point for <function> in <path>.

I've set up the VB side and called the Windows API MessageBeep() and it works great.  I think I'm just missing something in my function declaration or something else. I just need to know what are the essential tasks in making a function visible to a VB project. (i.e. declarations, return types, includes, etc.)
Avatar of kodiak1
kodiak1

ASKER

Edited text of question
ASKER CERTIFIED SOLUTION
Avatar of nietod
nietod

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Here is a sample VC C++ dll that exports a single function.  To export a finction you need to declare it with __declspec(dllexport), since that is ugly, I #define DllExp.  Since you will be exporting to an non C++ application you need to use the extern "C" directive to tell it not mangle the function name.  (You could use a #define to put the extern "c" in as well, I don't.)

#define DllExp __declspec(dllexport)

DllExp extern "C" int FunctionToExport(int i)
{
   return i + 1;
}

bool
WINAPI DllMain(HINSTANCE DLLHnd, // >> DLL module.                              ULONG     Rsn,    // Reason for calling fuction.                 LPVOID    Rsv)    // Reserved.                    {
   return true;
}

Wow that came out really badly formatted!

here is the DllMain again.

bool
WINAPI DllMain(HINSTANCE DLLHnd,ULONG Rsn,LPVOID Rsv)
{
   return true;
}
Avatar of kodiak1

ASKER

Now I seen the declaration part before, however, I have no idea what the dllMain function is for.  I'm assuming that it is the entry part of the file I was missing before.  Is this needed in every DLL file? Could you give me some reasoning behind the DLLMAIN function?
Every dll, just like every EXE, must have a an entry point.  The entry point is specified to the linker which records its location in the dll file, so the entry point could be called anything you want.  However, for convenience, Visual C treats any procedure with the name "DllMain" and the appropriate arguments as the entry point.  (Strictkly speaking it is not the entry point.  The VC run-tim libraries contain the entry point which then calls this procedure.)

This procedure is required for all Dll's.  Windows will call the procedure under 4 circumstances.  When the library is attached to a process, detached from a process, attached to a thread, detached from a thread.  The Rsn parameter indicates why the procedure is being called.  The bool return value is used only when attachiong to a process.  If the procedure returns false, it indicates the Dll could not initialize for some reason and windows will not continue to start up the EXE or DLL that uses the Dll.  

If you do not have to do any start-up/shut-down processing, you can leave the procedure blank, as I did in the example.
Avatar of kodiak1

ASKER

I'm sure I'm doing something really stupid, but I think I'm missing an include file or library.  It doesn't like the DllMain declaration The error I keep getting is:

error C2239: unexpected token 'identifier' following declaration of 'WINAPI'
 
  and also

error C2061: syntax error : identifier 'DllMain'

Do I use another name, is DllMain something you came up with?  Here's exactly what I have in .cpp the file.:

#define DllExp __declspec(dllexport)

DllExp extern "C" int Myfunc(int i)
{
        return i + 1;
}

bool WINAPI DllMain(HINSTANCE DLLHnd,ULONG Rsn,LPVOID Rsv)
{
return true;
}

Do I need a include to declare WINAPI as a keyword?  Thanks for al the extra effort.
you need to include the windows include files "windows.h".  I have to go.  hopefully this helps you.  I'll check in tomorrow morning.
Avatar of kodiak1

ASKER

I'm still having trouble seeing these functions in VB.  I have recently added the name to the .Def file and it finally worked, but it died once it was passed through the function.  Now I can't get it to work again.  Did it not unload the DLL correctly?  do I need to do something specific to keep it from doing that?  I think this is bigger than I thought to begin with.
I suspect the problem now is calling syntax, that is parameter format and/or order.  

The default C++ calling convention (__cdecl) is to place parameters on the stack in reverse order and the caller is responsible for removing the parameters after the function returns.  Return values are returned in EAX.  Does this match the VB calling convention and/or can you specify that this convention be used for a function.  

Vissual C also supports the pascal (__stdcall) calling convention.  In this case the function is responsible for cleaning up the stack.  

If this doesn't help, post some sample code.


Avatar of kodiak1

ASKER

BOOL WINAPI DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason,
                 LPVOID lpReserved )
                 {
                     switch( fdwReason )
                     {
                     case DLL_PROCESS_ATTACH:
                     break;

                     case DLL_THREAD_ATTACH:
                     break;

                     case DLL_THREAD_DETACH:
                     break;

                     case DLL_PROCESS_DETACH:
                     break;
                     }
                     return FALSE;
                 }

__declspec( dllexport ) int WINAPI DateAndTime( int i )
{
      
      return i + 2;

}

The above is my C++ exported function.  I had it returning i + 1 and no matter what I passed in I got -3513 and now I get -3512.  On the VB side this is how I declared it:

Option Explicit

Declare Function DateAndTime Lib "Framer" (i As Integer) As Integer

the function name doesn't mean anything, I'm just trying to get stuff to work.  Its not crashing, but I'm not sure why its working? Or why its giving screwy numbers.  You'll have to tell me if you think its a VB problem.  I'm not sure now.  I had no trouble calling pre-compiled WINAPI functions before.  thanks
Avatar of kodiak1

ASKER

Finally got this to work thanks for your efforts.  I just changed the (i As Integer) As Integer to (ByVal i As Integer) As Integer and changed the declaration of the C to short instead of integer.  thanks for you help
A short is only 16 bits.  Is that the right size?
Avatar of kodiak1

ASKER

I can change that as the data deems it necessary.  I just needed something to work.  I'm in a kind of demonstration phase and needed a working system.  I'll switch to longs if I need bigger numbers.  

I may have to implement array or string passing and I'm not too sure how I'll do that, but I'll worry about that bridge when I come, unless its a no brainer.
I understand that.  My question was does a VB integer correspond to a C++ short?  i.e. is a VB integer only 16 bits.  (I'm not looking for an answer, I just want to make sure that's a question you've asked yourself.)  
Avatar of kodiak1

ASKER

Sorry, I misunderstood.  I'm not sure, but from other materials I've read it seemed to suggest just that.  

   short = integer
   long = long
   double = double