I'm trying to use ProductName() in a dll, JBBECore.dll (written in VC++), which is called by my bot, JBBE (written in VB6).
VC++ Code:
char productName(char shortname) {
char ret;
if(shortname == (char[5])"CHAT") { ret = (char)"a chat bot"; }
if(shortname == (char[5])"DSHR") { ret = (char)"Diablo Shareware"; }
if(shortname == (char[5])"DRTL") { ret = (char)"Diablo"; }
if(shortname == (char[5])"JSTR") { ret = (char)"Japanese Starcraft"; }
if(shortname == (char[5])"SSHR") { ret = (char)"StarCraft Shareware"; }
if(shortname == (char[5])"STAR") { ret = (char)"StarCraft"; }
if(shortname == (char[5])"SEXP") { ret = (char)"StarCraft: BW"; }
if(shortname == (char[5])"W2BN") { ret = (char)"WarCraft III: BNE"; }
if(shortname == (char[5])"D2DV") { ret = (char)"Diablo II"; }
if(shortname == (char[5])"D2XP") { ret = (char)"Diablo II: LOD"; }
if(shortname == (char[5])"WAR3") { ret = (char)"WarCraft III"; }
if(shortname == (char[5])"W3XP") { ret = (char)"WarCraft III: TFT"; }
if (ret == NULL) {
return (char)shortname;
} else {
return ret;
}
}
VC++ Export:
; JBBECore.def : Declares the module parameters for the DLL
LIBRARY "JBBECore"
DESCRIPTION "Visual C++ backend of JBBE."
EXPORTS
getDLLVersion
productName
MsgBox
VB Declaration:
Public Declare Function ProductName Lib "JBBECore.dll" Alias "productName" (ByVal Product As String) As String
VB Usage:
Private Sub BNCS_UserJoins(sUsername As String, sStatstring As String, lPing As Long, Product As String)
Call AddChat(Me.rtbChat, vbYellow, sUsername & " has joined the channel using " & ProductName(Product) & ".")
End Sub
I'm pretty much stuck. Anyone know what to do?
EDIT -
For comparison, JBBECore and JBBE are like SphtBotCore and SphtBot, the core being a VC++ DLL, and the bot itself written in VB.
If you are calling from VB you need to add
extern "C"
to the fuction.
Or, you could do a
extern "C" {
on the entire file with a } at the end of the file.
And when using Mircosoft VC++ *.*, you can use
__declspec(dllexport)
instead of making a DEF file.
So the method would look like:
extern "C" __declspec(dllexport) char productName(char shortname)
Then if you were using C/C++ to call the project, you would probably use a macro as such:
#ifdef EXPORTS
#define WHATEVER extern "C" __declspec(dllexport)
#else
#define WHATEVER extern "C" __declspec(dllimport)
#endif
I've added extern "C" to all my procedures, but it worked before anyhow, so eh?
Quote from: Joe on November 25, 2005, 07:22 PMI'm pretty much stuck. Anyone know what to do?
Fixing your C code would be a good start. I suppose you've managed to beat it into submission with all those typecasts, but I'm really surprised your compiler even built the code you posted.
Does...
extern "C" char PASCAL productName(LPCSTR product) {
LPCSTR ret = "";
if(product == "CHAT") { ret = "a chat bot"; }
if(product == "DSHR") { ret = "Diablo Shareware"; }
if(product == "DRTL") { ret = "Diablo"; }
if(product == "JSTR") { ret = "Japanese Starcraft"; }
if(product == "SSHR") { ret = "StarCraft Shareware"; }
if(product == "STAR") { ret = "StarCraft"; }
if(product == "SEXP") { ret = "StarCraft: BW"; }
if(product == "W2BN") { ret = "WarCraft III: BNE"; }
if(product == "D2DV") { ret = "Diablo II"; }
if(product == "D2XP") { ret = "Diablo II: LOD"; }
if(product == "WAR3") { ret = "WarCraft III"; }
if(product == "W3XP") { ret = "WarCraft III: TFT"; }
if (ret == "") {
return (char)product;
} else {
return (char)ret;
}
}
look any better?
Quote from: Joe on November 25, 2005, 10:49 PMDoes...look any better?
Yes, but it's still wrong. You're returning useless results, and comparing addresses instead of contents.
Well, you can see I have no clue what I'm doing. Could you enlighten me on how to do this correctly? I'm not asking you to spoon feed me, but to give me some instructions or examples that would help me.
I realized I was comparing the pointer to the value itself. I can't get the actual value pointed to, no matter what I do. Could you show me an example of that being done?
First rule: don't use a typecast unless you're certain you know better than the compiler. Too many people just start throwing typecasts in to make warnings/errors go away, but often you're just suppressing the problem.
Make productName return a const char *, and fix the return statements accordingly. Use strcmp(3) instead of == to test for string equality.
Thank you.
extern "C" const char * PASCAL productName(const char * product) {
const char * ret = "";
if(strcmp(product, "CHAT") == 0) { ret = "a chat bot"; }
if(strcmp(product, "DSHR") == 0) { ret = "Diablo Shareware"; }
if(strcmp(product, "DRTL") == 0) { ret = "Diablo"; }
if(strcmp(product, "JSTR") == 0) { ret = "Japanese Starcraft"; }
if(strcmp(product, "SSHR") == 0) { ret = "StarCraft Shareware"; }
if(strcmp(product, "STAR") == 0) { ret = "StarCraft"; }
if(strcmp(product, "SEXP") == 0) { ret = "StarCraft: BW"; }
if(strcmp(product, "W2BN") == 0) { ret = "WarCraft III: BNE"; }
if(strcmp(product, "D2DV") == 0) { ret = "Diablo II"; }
if(strcmp(product, "D2XP") == 0) { ret = "Diablo II: LOD"; }
if(strcmp(product, "WAR3") == 0) { ret = "WarCraft III"; }
if(strcmp(product, "W3XP") == 0) { ret = "WarCraft III: TFT"; }
if (ret == "") {
return product;
} else {
return ret;
}
}
Now, if I'm not mistaken, its returning a pointer to a string, not a string itself. If I just define this as As String will VB handle it correctly?
Quote from: Joe on November 26, 2005, 02:52 PMNow, if I'm not mistaken, its returning a pointer to a string, not a string itself. If I just define this as As String will VB handle it correctly?
You are not mistaken. I try to avoid VB, so I don't know whether VB will handle it correctly. As a minor performance optimization, you could use
else if instead of
if, since product can equal at most one of those strings.
Quote from: Kp on November 26, 2005, 03:26 PM
Quote from: Joe on November 26, 2005, 02:52 PMNow, if I'm not mistaken, its returning a pointer to a string, not a string itself. If I just define this as As String will VB handle it correctly?
You are not mistaken. I try to avoid VB, so I don't know whether VB will handle it correctly. As a minor performance optimization, you could use else if instead of if, since product can equal at most one of those strings.
Ahh, good idea on the else if. I'll do that. :)
A little problem though, VB didn't handle it correctly. I'm trying to copy the pointer to a string now, with very little success. =(
Shouldn't it be __stdcall?
Quote from: Banana fanna fo fanna on November 26, 2005, 06:18 PM
Shouldn't it be __stdcall?
That's what I already told him, unless you're trying to pick on my use of only one underscore. I don't recall encountering a compiler that recognized __stdcall and failed to recognize _stdcall.
Quote from: Banana fanna fo fanna on November 26, 2005, 06:18 PM
Shouldn't it be __stdcall?
Yeah, why are you using PASCAL?
Couple thoughts:
LPCSTR instead of const char*.
#define EXP extern "C" __stdcall __declspec(dllexport)
Visual C++ often creates macros for you based on the project name when you create a DLL project. For example, if your project name was "JBBECore" (which build JBBECore.dll), it'd create a file JBBECore.h. Among the declarations would be something like:
#if EXPORT
#define JBBECORE_API extern "C" __stdcall __declspec(dllexport)
#else
#define JBBECORE_API extern "C" __stdcall __declspec(dllimport)
#endif
Actually, it will only give you the __declspec parts (not extern "C" __stdcall). The idea behind this is that you can use the header file for including in other C/++ projects and not define the EXPORT symbol, and the program would know to expect any function marked JBBECORE_API as imported.
You might also consider passing a ByRef String variable as an OUT variable and simply returning the product name that way (instead of through the return statement).
One last note:
A core DLL should not return location-specific strings. That's the job for localized interface programs. Your core DLL should always deal with culture-neutral data. I know you may not care about this right now, but if you decide you want to do something practical with software development one day, it might be a good idea to get into habits of doing this. Any string the user will see is an interface string, and should be as far out as possible. This particular usage of a DLL seems a bit superfluous and unnecessary. Doing this in C won't be any better at all than doing it in VB.
Visual Basic uses BSTR for strings. That is what you should use as well.
Quote from: TheMinistered on November 26, 2005, 07:05 PM
Visual Basic uses BSTR for strings. That is what you should use as well.
N and O put together spell NO
Quote from: TheMinistered on November 26, 2005, 07:05 PM
Visual Basic uses BSTR for strings. That is what you should use as well.
BSTR is a COM type, not a C type.
Blerf.cpp:
void __stdcall Bleh(int blah, char *boo)
{
if(blah > 0)
strcpy(boo, "bleh");
}
Blerf.def:
Bleh=Bleh
APIDeclares.bas:
Declare Sub Bleh Lib "Blerf.dll" (ByVal Blah As Long, ByVal Boo As Long)
CoolModule.bas:
Sub Meh()
Dim Eh As String
Eh = Space(256)
Call Bleh(1, Eh)
End Sub
Bleh, you get the point
Quote from: Joe on November 26, 2005, 02:52 PM
<snip>
if (ret == "") {
return product;
} else {
return ret;
}
You're still trying to use == to compare strings.
Quote from: TehUser on November 27, 2005, 11:52 AM
Quote from: Joe on November 26, 2005, 02:52 PM
<snip>
if (ret == "") {
return product;
} else {
return ret;
}
You're still trying to use == to compare strings.
Yes, but unless his compiler is totally braindead, it's ok in this case. ret was initialized to point at an empty string, and now he's comparing to see whether it points at an empty string. If the compiler is pooling strings (and it
really should!), then the two will have the same address and it'll be OK.
Quote from: TehUser on November 27, 2005, 11:52 AM
Quote from: Joe on November 26, 2005, 02:52 PM
<snip>
if (ret == "") {
return product;
} else {
return ret;
}
You're still trying to use == to compare strings.
Oops..
Quote from: Kp on November 27, 2005, 12:10 PM
Quote from: TehUser on November 27, 2005, 11:52 AM
Quote from: Joe on November 26, 2005, 02:52 PM
[...]
You're still trying to use == to compare strings.
[...]unless his compiler is totally braindead [...]
Lets asume VC++ is braindead. =p
I was assuming he was using an MFC DLL considering he is just now figuring out how to do it... thus...
Quote
If we want to pass strings to a DLL as input or to get strings from a DLL as output and we want to do this in the most general way, we are told from Microsoft to use the BSTR type.
The only reason char* works in this case is because it's being passed as ANSI. However, if microsoft encourages the use of BSTR in this case then why not?
Quote
Again from the MSDN documentation (in a remote part of it, to be honest !), we read what follows:
1. Visual Basic always creates a new BSTR containing ANSI characters (not UNICODE ones!) when passing a string to a DLL
2. Visual Basic always gets a BSTR containing UNICODE characters when getting a string from a DLL
http://www.codeproject.com/dll/BSTR_CString_conversion.asp
I'm not using MFC.