Calling C++ DLL from VB
|
|
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~
|
|
|