Home All Groups Group Topic Archive Search About

Functional IDE DLL call compiles to non-functional DLL call

Author
5 Jul 2005 1:40 PM
Joel Whitehouse
Hello All,

I wrote a DLL in VC++, and in my VB program I've declared each of the
functions with absolute paths to the compile directory of the .DLL.
When I click "Start with Full Compile," the program runs in the IDE and
executes each .DLL call perfectly.

However, when I compile the program to an .EXE, the program doesn't call
the .DLL's functions any longer.  Furthermore, the .EXE exits with the
attached error message.

I'm running on Win2k.  Any ideas?

Thanks!

Author
5 Jul 2005 2:34 PM
Jim Mack
Joel Whitehouse wrote:
> Hello All,
>
> I wrote a DLL in VC++, and in my VB program I've declared each of the
> functions with absolute paths to the compile directory of the .DLL.
> When I click "Start with Full Compile," the program runs in the IDE
> and executes each .DLL call perfectly.
>
> However, when I compile the program to an .EXE, the program doesn't
> call the .DLL's functions any longer.  Furthermore, the .EXE exits
> with the attached error message.
>
> I'm running on Win2k.  Any ideas?

If this is a standard DLL, show us the C++ prototypes and the VB Declares, and a representative call to each.  What you posted isn't enough to diagnose this.

--

    Jim Mack
    MicroDexterity Inc
    www.microdexterity.com
Author
5 Jul 2005 2:39 PM
Joel Whitehouse
Jim Mack wrote:
Show quoteHide quote
> Joel Whitehouse wrote:
>
>>Hello All,
>>
>>I wrote a DLL in VC++, and in my VB program I've declared each of the
>>functions with absolute paths to the compile directory of the .DLL.
>>When I click "Start with Full Compile," the program runs in the IDE
>>and executes each .DLL call perfectly.
>>
>>However, when I compile the program to an .EXE, the program doesn't
>>call the .DLL's functions any longer.  Furthermore, the .EXE exits
>>with the attached error message.
>>
>>I'm running on Win2k.  Any ideas?
>
>
> If this is a standard DLL, show us the C++ prototypes and the VB Declares, and a representative call to each.  What you posted isn't enough to diagnose this.
>
Coming right up.
Author
5 Jul 2005 2:48 PM
Joel Whitehouse
Mr. Mack,

Thanks for your help - here is the code you requested.  Like I say, it
works in the VB IDE, but not when compiled...

Here are the VB Declares:
----------------------------------------------------------------------------
Public Declare Function Calibrate Lib
"C:\MyProjects\MastControllerLibrary\MastController\Debug\MastController.dll"
(ByVal hWnd As Long, ByVal Msg As Long) As Integer
     Public Declare Function Initialize Lib
"C:\MyProjects\MastControllerLibrary\MastController\Debug\MastController.dll"
(ByVal lpszFileName As String, ByVal hWnd As Long) As Integer
     Public Declare Function MoveAz Lib
"C:\MyProjects\MastControllerLibrary\MastController\Debug\MastController.dll"
(ByVal hWnd As Long, ByVal Msg As Long, ByVal nAzimuth As Long) As Integer
     Public Declare Function MoveEl Lib
"C:\MyProjects\MastControllerLibrary\MastController\Debug\MastController.dll"
(ByVal hWnd As Long, ByVal Msg As Long, ByVal nElevation As Long) As Integer
     Public Declare Function StopMast Lib
"C:\MyProjects\MastControllerLibrary\MastController\Debug\MastController.dll"
Alias "Stop" () As Integer
     Public Declare Function IsMastAlive Lib
"C:\MyProjects\MastControllerLibrary\MastController\Debug\MastController.dll"
Alias "IsAlive" (ByRef answer As Boolean) As Integer
     Public Declare Function IsMastMoving Lib
"C:\MyProjects\MastControllerLibrary\MastController\Debug\MastController.dll"
Alias "IsMoving" (ByRef directons As Long) As Integer
     Public Declare Function NotifyOnComplete Lib
"C:\MyProjects\MastControllerLibrary\MastController\Debug\MastController.dll"
(ByVal hWnd As Long, ByVal Msg As Long) As Integer


And the c++ Prototypes
------------------------------------------------------------------------------
AFX_API_EXPORT HRESULT PASCAL Calibrate( HWND hWnd, UINT Msg );
AFX_API_EXPORT HRESULT PASCAL Initialize( LPCTSTR lpszFileName, HWND
hWnd  );
AFX_API_EXPORT HRESULT PASCAL MoveAz( HWND hWnd, UINT Msg, INT nAzimuth );
AFX_API_EXPORT HRESULT PASCAL MoveEl( HWND hWnd, UINT Msg, INT nElevation );
AFX_API_EXPORT HRESULT PASCAL Stop( void );
AFX_API_EXPORT HRESULT PASCAL IsAlive( BOOL & isAlive );
AFX_API_EXPORT HRESULT PASCAL IsMoving(INT & directions);
AFX_API_EXPORT HRESULT PASCAL NotifyOnComplete(HWND hWnd, UINT Msg);



And a representative call to each:
-------------------------------------------------------------------------------

Public Function IsAlive() As Boolean
On Error Resume Next
     IsMastAlive IsAlive
End Function

Public Function IsMoving() As Long
On Error Resume Next
     IsMastMoving IsMoving
End Function

Public Sub Az(ByVal azimuth As Integer)
     On Error Resume Next
     GoNotifyOnComplete
     MoveAz Form1.hWnd, UWM_MOVE_AZ_THREAD, CLng(azimuth)
End Sub

Public Sub El(ByVal elevation As Integer)
     On Error Resume Next
     GoNotifyOnComplete
     MoveEl Form1.hWnd, UWM_MOVE_EL_THREAD, CLng(elevation)
End Sub

Private Sub GoNotifyOnComplete()
On Error Resume Next
     'Do this just once
     Static x As Boolean
     If (x = False) Then
         NotifyOnComplete Form1.hWnd, UWM_MOVEMENT_COMPLETE
         x = True
     End If
End Sub

Public Sub InitializeMast(iniFilePath As String)
On Error Resume Next
      Initialize iniFilePath, Form1.hWnd
End Sub

Public Sub HaltMast()
On Error Resume Next
      StopMast
End Sub

Public Sub CalibrateMast()
     On Error Resume Next
      Calibrate Form1.hWnd, UWM_CALIBRATE_THREAD
End Sub
Author
5 Jul 2005 4:59 PM
Jim Mack
Joel Whitehouse wrote:
Show quoteHide quote
> Mr. Mack,
>
> Thanks for your help - here is the code you requested.  Like I say, it
> works in the VB IDE, but not when compiled...
>
> Here are the VB Declares:
> ----------------------------------------------------------------------------
> Public Declare Function Calibrate Lib
> (ByVal hWnd As Long, ByVal Msg As Long) As Integer
>      Public Declare Function Initialize Lib
> (ByVal lpszFileName As String, ByVal hWnd As Long) As Integer
>      Public Declare Function MoveAz Lib
> (ByVal hWnd As Long, ByVal Msg As Long, ByVal nAzimuth As Long) As
>      Integer Public Declare Function MoveEl Lib
> (ByVal hWnd As Long, ByVal Msg As Long, ByVal nElevation As Long) As
>      Integer Public Declare Function StopMast Lib
> Alias "Stop" () As Integer
>      Public Declare Function IsMastAlive Lib
> Alias "IsAlive" (ByRef answer As Boolean) As Integer
>      Public Declare Function IsMastMoving Lib
> Alias "IsMoving" (ByRef directons As Long) As Integer
>      Public Declare Function NotifyOnComplete Lib
> (ByVal hWnd As Long, ByVal Msg As Long) As Integer
>
>
> And the c++ Prototypes
> ------------------------------------------------------------------------------
> AFX_API_EXPORT HRESULT PASCAL Calibrate( HWND hWnd, UINT Msg );
> AFX_API_EXPORT HRESULT PASCAL Initialize( LPCTSTR lpszFileName, HWND
> hWnd  );
> AFX_API_EXPORT HRESULT PASCAL MoveAz( HWND hWnd, UINT Msg, INT
> nAzimuth ); AFX_API_EXPORT HRESULT PASCAL MoveEl( HWND hWnd, UINT
> Msg, INT nElevation ); AFX_API_EXPORT HRESULT PASCAL Stop( void );
> AFX_API_EXPORT HRESULT PASCAL IsAlive( BOOL & isAlive );
> AFX_API_EXPORT HRESULT PASCAL IsMoving(INT & directions);
> AFX_API_EXPORT HRESULT PASCAL NotifyOnComplete(HWND hWnd, UINT Msg);
>
>
>
> And a representative call to each:
> -------------------------------------------------------------------------------
>
> Public Function IsAlive() As Boolean
> On Error Resume Next
>      IsMastAlive IsAlive
> End Function
>
> Public Function IsMoving() As Long
> On Error Resume Next
>      IsMastMoving IsMoving
> End Function
>
> Public Sub Az(ByVal azimuth As Integer)
>      On Error Resume Next
>      GoNotifyOnComplete
>      MoveAz Form1.hWnd, UWM_MOVE_AZ_THREAD, CLng(azimuth)
> End Sub
>
> Public Sub El(ByVal elevation As Integer)
>      On Error Resume Next
>      GoNotifyOnComplete
>      MoveEl Form1.hWnd, UWM_MOVE_EL_THREAD, CLng(elevation)
> End Sub
>
> Private Sub GoNotifyOnComplete()
> On Error Resume Next
>      'Do this just once
>      Static x As Boolean
>      If (x = False) Then
>          NotifyOnComplete Form1.hWnd, UWM_MOVEMENT_COMPLETE
>          x = True
>      End If
> End Sub
>
> Public Sub InitializeMast(iniFilePath As String)
> On Error Resume Next
>       Initialize iniFilePath, Form1.hWnd
> End Sub
>
> Public Sub HaltMast()
> On Error Resume Next
>       StopMast
> End Sub
>
> Public Sub CalibrateMast()
>      On Error Resume Next
>       Calibrate Form1.hWnd, UWM_CALIBRATE_THREAD
> End Sub


If you hadn't said that these work perfectly in the IDE, I'd say that they could never have worked at all, since you're using the Pascal calling convention, whereas VB uses and expects _stdcall.

It isn't difficult to accommodate pascal convention, just reverse the order of arguments.  For example,

AFX_API_EXPORT HRESULT PASCAL MoveEl( HWND hWnd, UINT Msg, INT nElevation );

...becomes:

Declare Function MoveEl Lib "xxx" _
(ByVal nElevation As Long, _
  ByVal Msg As Long, _
  ByVal hWnd As Long) As Integer

But it might be better overall to switch to _stdcall in the DLL.

Further, 'int' or 'uint' in C is always Long in VB, and that applies to HRESULT as well.  None of your parameters or return types should be "As Integer" in VB.  And a 'bool' in C is different than a Boolean in VB.  C 'bool' is equivalent to VB Long, with the values 0 and 1, not the 0 and -1 that you'd expect from VB.

Last, I can't say that I've ever seen C parameters listed as "INT & directions". I suspect that you mean "INT *directions", which would square with your use of ByRef in the VB Declare.

--

    Jim Mack
    MicroDexterity Inc
    www.microdexterity.com
Author
5 Jul 2005 5:44 PM
Joel Whitehouse
> If you hadn't said that these work perfectly in the IDE, I'd say that they could never have worked at all, since you're using the Pascal calling convention, whereas VB uses and expects _stdcall.
>
> It isn't difficult to accommodate pascal convention, just reverse the order of arguments.  For example,
>
>  AFX_API_EXPORT HRESULT PASCAL MoveEl( HWND hWnd, UINT Msg, INT nElevation );
>
>  ...becomes:
>
>  Declare Function MoveEl Lib "xxx" _
>  (ByVal nElevation As Long, _
>   ByVal Msg As Long, _
>   ByVal hWnd As Long) As Integer

Wow -  that is completely not intuitive...  Why *is* that?

>
> But it might be better overall to switch to _stdcall in the DLL.
>
> Further, 'int' or 'uint' in C is always Long in VB, and that applies to HRESULT as well.  None of your parameters or return types should be "As Integer" in VB.  And a 'bool' in C is different than a Boolean in VB.  C 'bool' is equivalent to VB Long, with the values 0 and 1, not the 0 and -1 that you'd expect from VB.

Thanks so much for this info - I seached for it online but didn't have a
great deal of success.

> Last, I can't say that I've ever seen C parameters listed as "INT & directions". I suspect that you mean "INT *directions", which would square with your use of ByRef in the VB Declare.
>
So a VB Byref casts to a C pointer?

Thank you sir for all your time -  I think I have a lot to go on here!

-Joel
Author
5 Jul 2005 6:12 PM
Jim Mack
Joel Whitehouse wrote:
Show quoteHide quote
>> If you hadn't said that these work perfectly in the IDE, I'd say
>> that they could never have worked at all, since you're using the
>> Pascal calling convention, whereas VB uses and expects _stdcall. 
>>
>> It isn't difficult to accommodate pascal convention, just reverse
>> the order of arguments.  For example,
>>
>>  AFX_API_EXPORT HRESULT PASCAL MoveEl( HWND hWnd, UINT Msg, INT
>> nElevation );
>>
>>  ...becomes:
>>
>>  Declare Function MoveEl Lib "xxx" _
>>  (ByVal nElevation As Long, _
>>   ByVal Msg As Long, _
>>   ByVal hWnd As Long) As Integer
>
> Wow -  that is completely not intuitive...  Why *is* that?

Intuition should play very little role in programming. :-)

It is that because that's what it is.  Pascal convention has always been to pass from left to right, as was the older Basic convention.  C convention, and now stdcall, has always been to pass from right to left.  There may be reasons from the deep history of the languages, but in practical terms it just is that way, so we deal with it.

Actually, since I never use Pascal convention, I don't know for certain that C++ doesn't perform some trickery to do the order reversal for you.  I doubt it, but anything is possible.

--

    Jim Mack
    MicroDexterity Inc
    www.microdexterity.com
Author
5 Jul 2005 8:43 PM
Joel Whitehouse
Mr. Mack,

I fixed all of the calls and declarations, and I still get the error.

If I put the c++ .dll in the C:\ root, and change all the declares paths
to C:\, then the program still works in the IDE.

However, I compiled the VB code and removed the "On Error Resume Next"
lines form the VB functions that call the my dll, to try to get at teh
answer.  Whenever I try to call one of teh Declared .dll functions, I
get "Run Time error 53: File not found: C:\mydll.dll", despite the dact
that mydll.dll is *obviously* in the root directory.  I have no idea why
the compiled VB code does this when the IDE code does not.

I guess I'm wondering if you have any firther ideas, and if you had any
tips for converting a pascal call to __stdcall.

Thanks!

-Joel
Author
5 Jul 2005 9:21 PM
Jim Mack
Joel Whitehouse wrote:
Show quoteHide quote
> Mr. Mack,
>
> I fixed all of the calls and declarations, and I still get the error.
>
> If I put the c++ .dll in the C:\ root, and change all the declares
> paths to C:\, then the program still works in the IDE.
>
> However, I compiled the VB code and removed the "On Error Resume Next"
> lines form the VB functions that call the my dll, to try to get at teh
> answer.  Whenever I try to call one of teh Declared .dll functions, I
> get "Run Time error 53: File not found: C:\mydll.dll", despite the
> dact that mydll.dll is *obviously* in the root directory.  I have no
> idea why the compiled VB code does this when the IDE code does not.
>
> I guess I'm wondering if you have any firther ideas, and if you had
> any tips for converting a pascal call to __stdcall.
>

"File not found" can mean the named file, or a dependency of that file.  Use Depends.exe to load and run your compiled program, and I'll bet a missing dependent DLL shows up.

It's always best to put your DLL in Win/Sys, and leave off any path information from the Declare.  Placing it in the application directory is the next best, again with no explicit path in the Lib clause.

Even if it doesn't contribute to this problem, I'd strongly encourage you to switch to stdcall, since the Windows API is built around that and VB is most comfortable with it.

Changing to stdcall could be as simple as either replacing the keyword pascal with __stdcall, or just dropping the pascal with no other change.  I don't know how the other bits on your prototypes are #defined, but something with 'API' in the name may have __stdcall as part of it already.

--

    Jim Mack
    MicroDexterity Inc
    www.microdexterity.com
Author
5 Jul 2005 10:14 PM
Joel Whitehouse
> Changing to stdcall could be as simple as either replacing the keyword pascal with __stdcall, or just dropping the pascal with no other change.  I don't know how the other bits on your prototypes are #defined, but something with 'API' in the name may have __stdcall as part of it already.

I found this in an attached header:

#define PASCAL  __stdcall

My dependancies appear to be intact...

Heh heh.  I'm gonna be sick.  I've got a god year and an half into this
project...  It's *almost* done, and then this.  Ugh.

-Joel
Author
5 Jul 2005 11:38 PM
Jim Mack
Joel Whitehouse wrote:
>> Changing to stdcall could be as simple as either replacing the
>> keyword pascal with __stdcall, or just dropping the pascal with no
>> other change.  I don't know how the other bits on your prototypes
>> are #defined, but something with 'API' in the name may have
>> __stdcall as part of it already.   
>
> I found this in an attached header:
>
> #define PASCAL  __stdcall

Oooh, that's just evil.  But it does explain why it worked in the IDE, when it shouldn't have if it were using pascal calling convention.

> My dependancies appear to be intact...

Without digging into the DLL source it's not possible to go much further. I would suggest that you compile the DLL with no optimizations and with all possible checks turned on, to see if there is some assumption being made that is biting you.

I would also take a look at the exported entry points, in stdcall format. There should be, for example, an entry named _Calibrate@8.  If it says anything else, for instance _Calibrate@12, then you know where the problem lies -- hidden parameters.  At a minimum, you could just open the DLL in a hex editor and look for the string _Calibrate.

"Floating point inexact result" is a pretty specific-seeming error, and I can see no way that it could be generated by the act of making the calls, so it well could be a side effect of stack misalignment.  The IDE will hide stack misalignments that a compiled app will reveal.  You might also compile the VB to pcode instead of native, which (I think) will also hide them.

> Heh heh.  I'm gonna be sick.  I've got a god year and an half into
> this
> project...  It's *almost* done, and then this.  Ugh.

If none of the above yields any joy, I can put you in touch with a true C++/VB expert who can (for a fee) look over your work and possibly see something that you can't, being too close to it.  Let me know by email if that interests you.

--
        Jim
Author
6 Jul 2005 1:22 AM
Ralph
"Joel Whitehouse" <joelwhiteho***@gmail.com> wrote in message
news:%231Vuc8agFHA.2472@TK2MSFTNGP15.phx.gbl...
>
> > Changing to stdcall could be as simple as either replacing the keyword
pascal with __stdcall, or just dropping the pascal with no other change.  I
don't know how the other bits on your prototypes are #defined, but something
with 'API' in the name may have __stdcall as part of it already.
>
> I found this in an attached header:
>
> #define PASCAL  __stdcall
>
> My dependancies appear to be intact...
>
> Heh heh.  I'm gonna be sick.  I've got a god year and an half into this
> project...  It's *almost* done, and then this.  Ugh.
>
> -Joel


You are trying to import a MFC DLL into VB using the Function Declare
directive, and using C++ compiler directives to create your 'export'
signatures (__declspec(dllexport)).

This can cause problems for three reasons:
1) Your signatures, depending on compiler options (even seemingly harmless
ones), may not come out quite the way you expect, or more importantly the
way VB expects, and
2) You are defining arguments (parameters) that VB hasn't a clue about (but
is ready and willing to give a good guess about <g>), and
3) The Function Declare directive works slightly differently in the IDE than
it does with compiled code. (As you have discovered.)
Any of these items can conspire to produce strange results.

The easiest fix is to use a .def file to create your export files. Gives
somewhat better control - what you type is what you get.

You can also use a typelib, a superior solution to using Function Declares -
the chief advantage of which is - calls to a typedef will fail the same in
the IDE as it would if compiled. <g>

Second, I would remove the 'References' in your parameters (the BOOL&, ...).
I know references are implemented in C++ as pointers, and that most of the
time there is little difference in marshelling between a pointer and a
reference. But call me superstitious.

Third, the same with the 'BOOL' - a C++ BOOL and a VB Boolean may work alike
most of the time, but, again, they ain't the same and you can get burned.
Shorts are usually safe and don't forget to check for -1.

Fourth, a C++ 'int' is a VB 'long' and a VB 'integer' is a C++ 'short'.

Hard to get more specific without having the project in front of me.

hth
-ralph
Author
6 Jul 2005 4:32 AM
Ralph
Slight correction...

s/calls to a typedef will fail the same in the IDE as it would if compiled./
calls using a typelib will fail the same in the IDE as it would if
compiled/g
Author
6 Jul 2005 7:57 PM
Stefan Berglund
On Tue, 5 Jul 2005 14:12:37 -0400, "Jim Mack" <jmack@mdxi.nospam.com>
wrote:
in <eMA7g0YgFHA.3***@TK2MSFTNGP14.phx.gbl>


>> Wow -  that is completely not intuitive...  Why *is* that?
>
>Intuition should play very little role in programming. :-)

That's absolutely unequivocally true except when debugging.


---
Stefan Berglund