Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
Discussion GroupsVB SyntaxEnterprise DevelopmentDatabase AccessControlsCOMWin APICrystal ReportDeploymentGeneralGeneral 2
Related Topics
VB.NET / ASP.NETMS SQL ServerMS AccessOther Database ProductsMore Topics ...

VB Forum / COM / February 2005



Tip: Looking for answers? Try searching our database.

Calling C++ DLL from VB

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Peter Aitken - 14 Feb 2005 13:36 GMT
I am trying to call functions in a DLL that is supplied by a hardware
manufacturer. In a C++ program everything works just fine. In VB however
there is a problem - the program cannot find the entry point in the DLL. I
declare the function as usual:

Public Declare Function fdOpen lib "fglove.dll" (port As String) As Long

But when I call the function I get this error:

Run Time Error 453 - cannot find entry point fdOpen in fglove.dll

I have double-checked the spelling and capitalization of the function name.
Any ideas how I can fix this?

Thanks

Signature

Peter Aitken

Remove the crap from my email address before using.

Ralph - 14 Feb 2005 13:56 GMT
> I am trying to call functions in a DLL that is supplied by a hardware
> manufacturer. In a C++ program everything works just fine. In VB however
[quoted text clipped - 11 lines]
>
> Thanks

You say it works fine in C++?

Post the declaration in the header file you use to compile your C++
application.
It is possible the function is not _stdcall. Also I suspect it would be
interesting to see how that "String" was declared.

-ralph
Ralph - 14 Feb 2005 14:04 GMT
> > Public Declare Function fdOpen lib "fglove.dll" (port As String) As Long

Also, where is the dll located? The default is to look for the dll in the
current dir or Windows special folders.
You may need to provide a path for the "fglove.dll".

-ralph
Peter Aitken - 14 Feb 2005 14:14 GMT
>> > Public Declare Function fdOpen lib "fglove.dll" (port As String) As
>> > Long
[quoted text clipped - 4 lines]
>
> -ralph

The declaration is

fdGlove *fdOpen(char *pPort)

I am pretty sure the problem is not with the arguments or return type or
with finding the DLL - the error message I get is specifically when the
program can find the DLL but cannot find the entry point.

I am wondering if the problem is connected with the fglove.lib file that is
part of the C++ project. Does the lib file provide the C++ program with
information about the DLL that is not available to the VB program?

Thanks,

Peter Aitken
George Ionescu - 14 Feb 2005 14:59 GMT
Hello Peter,

>> Public Declare Function fdOpen lib "fglove.dll" (port As String) As Long

> The declaration is
> fdGlove *fdOpen(char *pPort)

> I am pretty sure the problem is not with the arguments or return type or
> with finding the DLL - the error message I get is specifically when the
> program can find the DLL but cannot find the entry point.

Actually, the argument *is* the problem.
VB cannot handle c-style strings (char*). You can either:

1. Change your vb declaration to
Public Declare Function fdOpen lib "fglove.dll" (ByVal port As Long) As
Long
and, when you call it from VB use ANSI strings and StrPtr, something like:

Dim lRez As Long
lRez = fdOpen( StrPtr(StrConv("MyPort", vbFromUnicode)) )

or, if you have access to C sources of the DLL
2. Change your C DLL to accept w_char*
since VB natively works with unicode strings.

Signature

Best Regards,
George Ionescu

SQLiteDb - fast, powerful and lightweight database engine
http://www.terrainformatica.com/sqlitedb

Terra Informatica Software inc.
http://www.terrainformatica.com

Jim Mack - 14 Feb 2005 15:31 GMT
>>>> Public Declare Function fdOpen lib "fglove.dll" (port As String) As
>>>> Long
[quoted text clipped - 21 lines]
>
> Peter Aitken

Contrary to George's advice, VB easily handles passing 'char *' -- use
"ByVal port As String" and the C++ DLL should get what it expects.  You
can't change the allocation for the passed-in string, though.

The problem may be name decoration.  Absent a DEF file, the export of a
_stdcall function will be something like fdOpen@4, where the '4'
represents the number of bytes of arguments.

Peeking into the LIB file may help here, but you could always just try:

Public Declare Function fdOpen alias "fdOpen@4" lib "fglove.dll" (ByVal
port As String) As Long

Signature

   Jim Mack
   MicroDexterity Inc
   www.microdexterity.com

Peter Aitken - 14 Feb 2005 16:07 GMT
>>>>> Public Declare Function fdOpen lib "fglove.dll" (port As String) As
>>>>> Long
[quoted text clipped - 34 lines]
> Public Declare Function fdOpen alias "fdOpen@4" lib "fglove.dll" (ByVal
> port As String) As Long

Thanks Jim. I tried your suggestion but still get the same error. How would
I peek into the LIB file and what would I look for?

Signature

Peter Aitken

Remove the crap from my email address before using.

Jim Mack - 14 Feb 2005 16:57 GMT
>> The problem may be name decoration.  Absent a DEF file, the export
>> of a _stdcall function will be something like fdOpen@4, where the '4'
[quoted text clipped - 8 lines]
> Thanks Jim. I tried your suggestion but still get the same error. How
> would I peek into the LIB file and what would I look for?

I would use a hex editor and look for instances of the proc name to see
if it's decorated or mangled.

Also, try aliasing to _fdOpen@4 (leading underscore).

Signature

       Jim

Karl E. Peterson - 14 Feb 2005 18:10 GMT
>>> The problem may be name decoration.  Absent a DEF file, the export
>>> of a _stdcall function will be something like fdOpen@4, where the
[quoted text clipped - 11 lines]
> I would use a hex editor and look for instances of the proc name to
> see if it's decorated or mangled.

Would Depends.exe also show the decorated name?
Signature

[Microsoft Basic: 1976-2001, RIP]

Jim Mack - 14 Feb 2005 19:19 GMT
>>>> The problem may be name decoration.  Absent a DEF file, the export
>>>> of a _stdcall function will be something like fdOpen@4, where the
[quoted text clipped - 13 lines]
>
> Would Depends.exe also show the decorated name?

I think Depends will optionally unmangle C++ names that it understands,
but I don't know about simple decoration.  Certainly worth a look.

Signature

       Jim

Jim Carlock - 22 Feb 2005 02:31 GMT
dumpbin should show the exports...

At a DOS prompt...

dumpbin.exe /exports fglove.dll

I think dumpbin.exe comes both with C++ and with the Platform
SDK.

The following link indicates that dumpbin can be used to obtain
the ordinal number of the function call as well in which case, the
Alias clause would be something like Alias "#439"...
http://msdn.microsoft.com/library/en-us/vbcon98/html/vbcondeclaringdllprocedure.asp

That link there indicates that there could be a problem if the
name is similarly defined inside of another referenced module...
ie, you can press F2 and do a search, type in the fdOpen name
into the search textbox.

I'm not sure though on whether all C++ defined dll's are all
COFFs. I think dumpbin.exe might only work with COFF files.
Perhaps someone else can comment on that.

HTH

--
Jim Carlock
Post replies to newsgroup.

Karl E. Peterson wrote:
> Jim Mack wrote:
>> Peter Aitken wrote:
[quoted text clipped - 16 lines]
>
> Would Depends.exe also show the decorated name?

I think Depends will optionally unmangle C++ names that it understands,
but I don't know about simple decoration.  Certainly worth a look.

Signature

       Jim

Ralph - 23 Feb 2005 13:09 GMT
> dumpbin should show the exports...
>
[quoted text clipped - 8 lines]
> the ordinal number of the function call as well in which case, the
> Alias clause would be something like Alias "#439"...

http://msdn.microsoft.com/library/en-us/vbcon98/html/vbcondeclaringdllprocedure.asp

> That link there indicates that there could be a problem if the
> name is similarly defined inside of another referenced module...
[quoted text clipped - 6 lines]
>
> HTH

They are "COFF". COFF is used by a wide range of OSs including Unix and
Windows. Windows uses "PE-COFF" ... http://support.microsoft.com/?id=121460

Additional info from the 'master' -
http://msdn.microsoft.com/msdnmag/issues/02/02/PE/default.aspx
Duane Bozarth - 14 Feb 2005 19:28 GMT
...
> Thanks Jim. I tried your suggestion but still get the same error. How would
> I peek into the LIB file and what would I look for?

I just use grep (or a workalike) on the library file looking for the
case-insensitive symbol name--this will show up all entries and then one
can <usually> see the name decoration.
Floppie < - 18 Feb 2005 22:36 GMT
I am having a similar problem and was wondering if anyone could help.  I
was looking to have my webserver output to a timestamped log file
instead of its log window, and instead of looking around for info on how
to write to a while in VB (reading I had to learn obviously, has to read
the file and send it), I simply created a function in C++ to add a log
line for me.

Anyway, I'm getting the same run-time error.  "Can't find DLL entry
point outfile in filestreamdll.dll".  I have tried aliasing the function
any way I found possible, utilizing any decoration in the .DLL/.LIB
files ("?outfile@@YAHABVString@@0ABH@Z" being the total decoration I was
able to find), but with any combination of decoration in there I still
recieved the error message.

For reference, I'll include any vital info here.  This is my complete
DllMain() function, as I didn't feel as though I needed any real
initialization/deinitialization for it:

BOOL APIENTRY DllMain(HANDLE hModule, DWORD  ul_reason_for_call, LPVOID
lpReserved) {
   switch (ul_reason_for_call)
    {
        case DLL_PROCESS_ATTACH:
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
   }
   return TRUE;
}

The only function's prototype (I enumerated app and trunc to 0 and 1,
respectively):
__declspec(dllexport) int outfile(const String &strOutString, const
String &strFile, const int &filemode = app);

String being a standard class I used to make dynamic char arrays easier.
The prototype to its relevant constructor is:
String::String(const char * s);

My attempt at calling the function from VB:
Public Declare Function outfile Lib "filestreamdll.dll" _
   (ByRef strOutString As String, ByRef strFile As _
String, ByRef filemode As Integer) As Integer

My attempt at actually utilizing the function from VB:
   outfile_return = outfile("Start Session @" & _
GetFormattedTime() & Chr$(10), "httplog.log", 0)
Ralph - 20 Feb 2005 16:29 GMT
> I am having a similar problem and was wondering if anyone could help.  I
> was looking to have my webserver output to a timestamped log file
[quoted text clipped - 44 lines]
>     outfile_return = outfile("Start Session @" & _
> GetFormattedTime() & Chr$(10), "httplog.log", 0)

Floppie,

First off, IMHO, when using components from VB and Web services, if your
service-level requirements will allow it - create an ATL ActiveX component
and register it with COM+/IIS/etc. You will save yourself a ton of
aggravation in terms of permissions and declarations/signature/type nuances.
The service will show up with intellisense and be universally consistent and
reliable.

VB will be happy, the OS will be happy, and a C/C++ will be happy.

      HRESULT = outfile( [in] BSTR* strOutString, [in] BSTR* strFile, [in]
int filemode,
                            [out, retval] long outfile_return);

But if you must use an API...

One thing wrong with your Declare statement: A VB 'Integer' is a C/C++
'short'. A C/C++ integer is a VB 'Long'.
Second, when used with VB or any cross-language calls, always use a .def
file to export your procedures. A def file gives you the advantage of being
able to create very clear (legal everywhere) names for the procedure and
reduces most opportunities to shoot yourself in the foot.
Third create a typelib for any exported API. They are easier to test against
the original call in C, provide intellisense, and difficult to screw up once
you get the signature correct.
Fourth, on a quick glance your cute little String:String() might work - but
again IMHO - avoid any such C-redirection crap in a call to be used
elsewhere - use a simple construct.
If you want a char* then say "char*". There is enough opportunties to
screw-up without adding to the list. <g>

hth
-ralph
Ralph - 20 Feb 2005 16:39 GMT
> I am having a similar problem and was wondering if anyone could help.  I
> was looking to have my webserver output to a timestamped log file
[quoted text clipped - 44 lines]
>     outfile_return = outfile("Start Session @" & _
> GetFormattedTime() & Chr$(10), "httplog.log", 0)

Floppie,

First off, IMHO, when using components from VB and Web services, if your
service-level requirements will allow it - create an ATL ActiveX component
and register it with COM+/IIS/etc. You will save yourself a ton of
aggravation in terms of permissions and declarations/signature/type nuances.
The service will show up with intellisense and be universally consistent and
reliable.

VB will be happy, the OS will be happy, and a C/C++ will be happy.

      HRESULT = outfile( [in] BSTR* strOutString, [in] BSTR* strFile, [in]
int filemode, [out, retval] long outfile_return);

But if you must use an API...

One, A VB 'Integer' is a C/C++ 'short'. A C/C++ int is a VB 'Long'.

Second, when creating an API to be used with VB or any cross-language calls,
always use a .def file to export your procedures. A def file gives you the
advantage of being able to create a very clear name for the procedure and
reduces opportunities to shoot yourself in the foot.

Third create a typelib for any exported API. They are easier to test against
the original call in C, provide Intellisense, and difficult to screw up once
you get the signature correct.

Fourth, on a quick glance your cute little String:String() might work - but
again IMHO - avoid any such C-redirection stuff in a call to be used
elsewhere - use a simple construct. Lose the 'references'. If you want a
char* then say "char*". Again, there are enough opportunties to mess-up
without adding to the list. <g>

hth
-ralph
Ralph - 20 Feb 2005 20:27 GMT
Floppie,

Made a slight error in my IDL example...

>        HRESULT = outfile( [in] BSTR* strOutString, [in] BSTR* strFile, [in]
> int filemode, [out, retval] long outfile_return);

Since you are not "returning" a value for the first two parameters, or
rather expecting constant, then you don't need to mark them as ByRef. The
example should be ...

   HRESULT = outfile( [in] BSTR strOutString, [in] BSTR strFile, [in] int
filemode, [out, retval] long outfile_return);

I would also like to rant a bit about one of my pet peeves. <g>

You declared your function as "outfile". This is rather pedestrian and can
lead easily to naming collisions.

In any project of any size the chance of having something else named
"outfile" is pretty good. Even you might forget using this name in the
future. When defining an API it is good to always provide very descriptive,
unique names when possible. Something like "OutputStringToLogFile".

If the use of an unabbreviated, non-cryptic, meaningful name bothers your
inherent sense of "C-ness". Then you can always use "outfile" in your code
and just rename the function in the .def file. <g>

It is a bit acceptable when used as a member of an exported class, since you
will have to uniquely qualify the name when calling it anyway and the
opportunity for collision isn't there.

In addition don't forget to include your enums for "filemode",  along with a
HelpString,  in your idl or typelib.

hth
-ralph
Floppie < - 20 Feb 2005 18:39 GMT
I did them by refrence to save 1) memory and 2) the CPU time required to
copy that memory.  When done by value, it needs to make a copy of the
variable, and for my purposes, those strings may or may not end up very
long.  When done by reference, it simply works with the original
variable.

I solved the problem I was having by use of the *.def file mentioned
above.  I did it last night and forgot to check this thread and/or post
here saying something to the effect of "never mind".

I also solved an issue I was running into with my enum by simply
exporting a pair of constants (app and trunc, all I needed).

Believe it or not, I had a reason for naming it outfile.  It can and
will be used as my all-purpose file output function in VB.  While the
reason that "sparked" my creation of this was my need for a logfile for
my webserver, I will be using it in the future.

I thank you for trying to help (which, if I hadn't already found my
solution, you would've), but your post was highly insulting.  I am a C++
programmer, I only use VB for the simpler parts to my programs.  I have
done similar things in the past, but found a problem with this
particular instance.  Maybe this should've gone to the C++ board on this
site, I found this thread and thought to put it here instead of creating
a new one.
Ralph - 21 Feb 2005 23:54 GMT
> I did them by refrence to save 1) memory and 2) the CPU time required to
> copy that memory.  When done by value, it needs to make a copy of the
[quoted text clipped - 21 lines]
> site, I found this thread and thought to put it here instead of creating
> a new one.

Floppie,

I am glad you found a solution.

I am a bit shocked that you found my "post was highly insulting". Now don't
get me wrong. I am not particularly thin-skinned, nor do I believe everyone
in the world should love me. In fact I can be quite abrasive at times - once
voted - most able to piss off a total stranger in twenty words or less. But
usually on those occasions it was my choice. I am surprised it happened when
there was no intention to do so. <g>

Not sure why, but I can make a few guesses... remember just some guesses and
not necessary correct.

1) I probably came across too pedantic. Please appreciate, as you apparently
do, that you did post in a "vb.com" newsgroup. Most people who visit here
are VBers venturing into C and are not as familar with COM as C/C++
programmers. It often takes a bit of background to make sure I am
communicating.

2) You might not have liked my suggestions concerning the simplicity of
arguments, the advisabilty of using COM instead of an API, and/or my
suggestions concerning names. All of these suggestions come from the point
of view (mine <smile>) of an ancient C programmer ('74 - four years before
K&R was published) that has been in the trenches, been there, done that,
since Win3.0, msC 5.1, and VB 1.1, and were only passed on in the same
spirit of all "good advice".

I can appreciate that when one does their own thing in the C world -
anything goes. And I understand the general mindset (when I started the use
of a vowel was considered a weakness <g>) But there are other worlds out
there. One of them is VB Classic. I assumed that your effort would be used
in that other world, more importantly would be used by the inhabitants of
that other world. I assumed your effort was part of a major cross-language
project. Had my assumptions been correct my advice would stand.

As it is, just treat my comments like all good advice, don't be insulted,
just ignore it. <g>

-ralph
Floppie < - 21 Feb 2005 01:55 GMT
Actually it was more the comment about "C-ness" that bugged me~

Yeah, no hard feelings.  I read your post and made mine when I first
woke up this morning, so I probably took things the wrong way.

It's not really a huge project, I was more after the knowledge of how to
call a C++ DLL from VB for future reference, which may include a
largescale project...my webserver's just my all-purpose test program,
I've learned as I went for that entire thing.

Either way, thank you for the help <3~
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2009 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.