Re: LoadLibrary giving system err 183 while loading Crypto dll
How did you create the crypto.dll? cryptopp version 5.6.1.0 is available from Wei Dai's home page as a set of source files to be compiled to produce a .dll. Using their standard build produces cryptopp.dll and cryptopp.lib files. If you have (or can make) the .lib file why are you bothering using LoadLibrary etc when you could just link with the .lib file and include the .h file with your program? This would be my preferred way of doing it when these files are available.
However, as the source of the dll is available then if you build a debug version then you can use the debugger to debug into the dll when dllmain(..) is called to find the problem.
Quote:
Code:
int code = (decryptAddress)((char *) pswd, (char *) out, (char*)key);
This is not the usual way that a C++ (or C) programmer calls a function. Why are there parentheses around the name of the function?
Because decryptAddress is variable containing a pointer to a function and not a function name. It could have been written
Code:
int code = (*decryptAddress)((char *) pswd, (char *) out, (char*)key);
but the '*' is now optional.
Re: LoadLibrary giving system err 183 while loading Crypto dll
Quote:
I tried your suggestion with the dwFlags DONT_RESOLVE_DLL_REFERENCES and even that didn’t work. It didn’t give me error 183 this time while loading the crypto.dll. As per my log file, it even got the address for the decrypt function as well,
This means that the problem is probably within dllmain() as DONT_RESOLVE_DLL_REFERENCES means that dllmain() isn't called for process and thread initialisation. However, it also means that the system does not load additional executable modules that are referenced by crypto.dll - so the problem could be with loading a module used by cryto.dll and not with crypto.dll itself. What modules does crypto.dll use? According to the dll.h file, it needs msvcrt.dll loaded BEFORE crypto.dll is loaded as dllmain() uses malloc and free. As an expt, try doing LoadLibrary("msvcrt") before LoadLibrary("crypto") and see what happens. This may explain why it works under eclipse and not under jar if eclipse already has mscvrt.dll loaded and jar hasn't????:confused:
Re: LoadLibrary giving system err 183 while loading Crypto dll
Quote:
Originally Posted by
2kaud
Because decryptAddress is variable containing a pointer to a function and not a function name. It could have been written
Code:
int code = (*decryptAddress)((char *) pswd, (char *) out, (char*)key);
I know this, and your method is the second way of doing this, but none of that is necessary, even if the variable is a function pointer. You can call the function as if it is a regular function.
Code:
decryptAddress((char *) pswd, (char *) out, (char*)key);
But it is the casting that is suspicious. Whenever I see that, it raises red flags as it was placed there either due to inexperience of the programmer (not really serious), or more seriously, the programmer is (unwittingly) trying to outsmart the compiler by masking a serious compiler error or warning concerning differing types.
Regards,
Paul McKenzie
Re: LoadLibrary giving system err 183 while loading Crypto dll
I tried out the sample program as per your suggestion in post #12. Below is the code:
Code:
void main(int argc, TCHAR * argv[])
{
HINSTANCE myCrypto = (HINSTANCE)NULL;
myCrypto = LoadLibrary("crypto");
if(myCrypto == NULL )
{
printf("bad ret: %i\n", GetLastError());
}
else
{
puts("ok");
};
}
On executing it, I got result as
bad ret: 183
I then added one more printf statement in the if block to get the value of HINSTANCE
Code:
if(myCrypto == NULL )
{
printf("myCrypto: %d\n",(int)myCrypto);
printf("bad ret: %i\n", GetLastError());
}
On executing it, I got the results
myCrypto: 0
bad ret: 183
================
I then tried out loading the msvcrt dll before loading crypto
Code:
void main(int argc, TCHAR * argv[])
{
HINSTANCE hi = (HINSTANCE)NULL;
HINSTANCE myCrypto = (HINSTANCE)NULL;
hi = LoadLibrary("msvcrt");
if(hi == NULL )
{
printf("hi: %d\n",(int)hi);
printf("bad ret: %i\n", GetLastError());
}
else
{
puts("ok");
printf("hi: %d\n",(int)hi);
}
myCrypto = LoadLibrary("crypto");
if(myCrypto == NULL )
{
printf("myCrypto: %d\n",(int)myCrypto);
printf("bad ret: %i\n", GetLastError());
}
else
{
puts("ok");
printf("myCrypto: %d\n",(int)myCrypto);
}
}
and got the result as
ok
hi: 2009137152
myCrypto: 0
bad ret: 183
So the msvcrt.dll is loaded successfully, where as it still failed to load crypto.dll.
================
This Cryptowrapper is a CPP program compiled with Visual Studio 2010 to generate the cryptowrapper.dll.
================
Yes you are right, after compiling the set of files from Wei dai the cryptopp.dll and cryptopp.lib files were created. Which are then referred into the crypto program. I am not really sure why this was done in this particular manner, but its how it has been over a period of time.
Cryptowrapper calling crypto which in turn uses cryptopp. This used to work fine till now with Java1 program. Now we have introduced Java2 program and with this we are getting the issue with Cryptowrapper failing to Load crypto dll. Pls not ethat Java1 program is still able to function successfully on the same machines where Java2 is failing.
================
In decryptAddress((char *) pswd, (char *) out, (char*)key);
The parameters pswd and key are passed from Java program, so the value initially comes as jstring and are then converted to char cons * type and then passed to the decryptAddress function. Similary the out var defined as char * is later converted to jstring and returned back to Java program.
================
For debugging – After the Java program is kicked off, I attach it to the CryptoWrapper program using ‘Attach to the Process’ and I am able to debug the program.
Thanks..
Re: LoadLibrary giving system err 183 while loading Crypto dll
Share Your very useful and intelligent individuals.
Ming Thank you much.
I'll read carefully easier to understand.
Chia se cua ban rat hay va huu ich voi ca nhan minh.
Minh cam on ban nhieu.
Minh se doc ky de hieu hon.
Tran trong
Re: LoadLibrary giving system err 183 while loading Crypto dll
Quote:
Originally Posted by
RituP
I tried out the sample program as per your suggestion in post #12. Below is the code:
Code:
void main(int argc, TCHAR * argv[])
{
HINSTANCE myCrypto = (HINSTANCE)NULL;
myCrypto = LoadLibrary("crypto");
if(myCrypto == NULL )
{
printf("bad ret: %i\n", GetLastError());
}
else
{
puts("ok");
};
}
On executing it, I got result as
bad ret: 183
I then added one more printf statement in the if block to get the value of HINSTANCE
Code:
if(myCrypto == NULL )
{
printf("myCrypto: %d\n",(int)myCrypto);
printf("bad ret: %i\n", GetLastError());
}
On executing it, I got the results
myCrypto: 0
bad ret: 183
Then you should concentrate on getting this to return a valid instance handle.
First, you didn't place the full path of the module to load. By not putting the full path, you are now at the mercy of the Windows OS search logic when finding modules. See here:
http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx
That's why I mentioned earlier about possibly other modules that are named the same but just happen to be loaded (or attempted to be loaded) by the Windows OS. If you have more than one crypto.dll or other dependent module floating around on your computer with the same name, by using a relative name in the LoadLibrary() call, the library that is loaded is no longer under your control.
Quote:
In decryptAddress((char *) pswd, (char *) out, (char*)key);
The parameters pswd and key are passed from Java program, so the value initially comes as jstring and are then converted to char cons * type and then passed to the decryptAddress function.
You didn't really answer the question as to what happens if you leave out those casts.
The compiler is not being stupid or annoying when it gives you the errors that you're now masking. If the function wants a char*, then it is possible that the function can attempt to change what that char* points to. Passing a const char* to a function that takes a char* is inviting disaster. There is a big difference between a function that wants a const char* and one that wants a char*. The former is guaranteeing that what the argument is pointing to can't be changed, while the latter makes no such guarantee.
Quote:
Similary the out var defined as char *
No, I asked where does it get initialized. A char* by itself means nothing. Where does it point to? Where does the buffer it must point to come from? You can't just declare a char* and pass it to the C++ function that expects it to point to a buffer.
Regards,
Paul McKenzie
Re: LoadLibrary giving system err 183 while loading Crypto dll
In my sample code, if I try to hardcode the full path (along with the dll name) for crypto. I have removed all the instances of the crypto, cryptowrapper and cryptopp dlls from this machine. Just one copy is maintained in C:\ drive and I am referring to that in my code.
Code:
void main(int argc, TCHAR * argv[])
{
HINSTANCE myCrypto = (HINSTANCE)NULL;
myCrypto = LoadLibrary("C:\\crypto.dll");
if(myCrypto == NULL )
{
printf("myCrypto: %d\n",(int)myCrypto);
printf("bad ret: %i\n", GetLastError());
}
else
{
puts("ok");
printf("myCrypto: %d\n",(int)myCrypto);
}
}
On executing this code, it prompted an error message box titled ‘Unable to Locate Component’ with text as – ‘This application has failed to start because cryptopp.dll was not found. Re-installing the application may fix this problem.’
On clicking OK button on that message box I got the result as
myCrypto: 0
bad ret: 183
But I do have the cryptopp.dll along with crypto dll in the C:\ drive, so why is it not able to find it. I tried to register the crytoppp.dll placed in C:\ drive using regsvr32 and got this message:
'C:\cryptopp.dll was loaded, but the DllUnregisterServer entry point was not found. The file can not be registered.'
I tried moving both the dlls (crypto and cryptopp) to its original location and then in the code provided the same path to Loadlibrary, but then also I got the same error message ‘Unable to Locate Component’ .
============
Here’s the original code that does the casting for pswd and key. The variables thePassword and theKey are jstrings. I am relatively new to this code, so it’s taking me some time to understand, sorry for the delay..
Code:
char const *pswd = env->GetStringUTFChars(thePassword, 0);
char const *key = env->GetStringUTFChars(theKey, 0);
int length =strlen(key);
length=int((7+length)/8)*8;
char* out = (char*) malloc(sizeof(char)*length+1);
memset(out, ' ', length);
out[length] = 0;
int code = (decryptAddress)((char *) pswd, (char *) out, (char*)key);
jstring result = env->NewStringUTF(out);
The return type for GetStringUTFChars()defined in jni.h is const char* and as the pswd and key values are not to be changed I thought it was ok if its defined as const char*.
==========
Further the decrypt function in crypto is defined as
Code:
int __declspec( dllexport ) __stdcall decrypt(char *in, char *out, char *systemKey)
So its expecting arguments of char * type.
Thanks…
Re: LoadLibrary giving system err 183 while loading Crypto dll
Quote:
Originally Posted by
RituP
I tried to register the crytoppp.dll placed in C:\ drive using regsvr32 and got this message:
'C:\cryptopp.dll was loaded, but the DllUnregisterServer entry point was not found. The file can not be registered.'
That is because the DLL is not a COM DLL. It is a garden variety, non-COM, Windows DLL -- you don't use regsrvr32.exe on such DLL's.
Quote:
Here’s the original code that does the casting for pswd and key. The variables thePassword and theKey are jstrings.
The term "jstring" doesn't really mean anything in a C++ forum, unless you tell us exactly, in C++ terms, what a "jstring" is an alias for.
Quote:
Further the decrypt function in crypto is defined as
Code:
int __declspec( dllexport ) __stdcall decrypt(char *in, char *out, char *systemKey)
So its expecting arguments of char * type.
So why are you passing const char* types to this function? If I wrote a function that expects a pointer to an Animal, you can cast a pointer to a Toaster to a pointer to Animal. Does it make it right? No.
Again, what were the compiler errors if you didn't cast? Those errors/warnings really do mean something, and should not be masked by applying inappropriate casts as you're doing now.
If a function wants a char*, it is by convention that the function has full rights in changing the information being pointed to by that char*. So if you really give it a const char* instead, you are risking undefined behaviour and possible crashes when you give this function an unchangeable (that's why it's const char *) string.
Casting a const char* to a char* changes nothing. All it does, again, is shut the compiler up about the compilation error you're code is producing.
You should actually give the function a writeable char buffer for the password. That is the only way to guarantee that nothing goes wrong. In other words, there is no need to cast anything if you send the function the correct types.
Regards,
Paul McKenzie
Re: LoadLibrary giving system err 183 while loading Crypto dll
Try first to LoadLibrary "msvcrt", then LoadLibrary "cryptocpp.dll" (using full path) and then LoadLibrary "crypto.dll" (using full path). I tried to load cryptocpp.dll on my computer and I got an error until I loaded msvcrt first.
Re: LoadLibrary giving system err 183 while loading Crypto dll
@ 2kaud - wow!...this worked! :)
Tried out your suggestion -try first to LoadLibrary "msvcrt", then LoadLibrary "cryptocpp.dll" (using full path) and then LoadLibrary "crypto.dll" (using full path). And it worked. I have to revert back to my original code and then add this piece of code and test it again. But I am sure now it will work. I just wanted to let you guys know that something did work out. Will keep you updated how it goes with my actual code and running it with Java2 program.
@Paul McKenzie
In jni.h you have jstring defined as
Code:
class _jstring : public _jobject {};
typedef _jstring *jstring;
The following link helped me to figure out few things about JNI and C++
http://journals.ecs.soton.ac.uk/java...nting/cpp.html
The jni.h is included in this Cryptowrapper program.
============
If I dont cast the parameters in decryptAddress function
Code:
decryptAddress(pswd, out, key);
it gives me this error - error C2664: 'int (char *,char *,char *)' : cannot convert parameter 3 from 'const char *' to 'char *'
I am not sure how we can achieve this in our scenario– ‘there is no need to cast anything if you send the function the correct types.’
The GetStringUTFChars returns const char *, this value is to be passed to decryptAddress which requires char *, somewhere we will have to do the casting to achieve that, right? Please suggest if there is some correct way to do this. Even if things work out with 2kaud's suggestion I would still like to learn how to do it in a right way.
Thanks..
Re: LoadLibrary giving system err 183 while loading Crypto dll
Quote:
Originally Posted by
RituP
If I dont cast the parameters in decryptAddress function
Code:
decryptAddress(pswd, out, key);
it gives me this error - error C2664: 'int (char *,char *,char *)' : cannot convert parameter 3 from 'const char *' to 'char *'
I am not sure how we can achieve this in our scenario– ‘there is no need to cast anything if you send the function the correct types.’
The GetStringUTFChars returns const char *, this value is to be passed to decryptAddress which requires char *, somewhere we will have to do the casting to achieve that, right? Please suggest if there is some correct way to do this. Even if things work out with 2kaud's suggestion I would still like to learn how to do it in a right way.
Thanks..
Ok. Here is the issue in a nutshell.
A C++ or C function that is prototyped to take a "const char *" guarantees to the caller that the data being sent will not be changed. This is by convention. Therefore, you can pass anything that can be converted to a const char* without intervention. This means a "char *" will also work.
Now, a function that has an argument that is prototyped as a "char *" is different. By convention, this means there is no guarantee that the function will not change the internal contents of the string. This means that passing a "const char *" to such a function not only is wrong, it is dangerous, as changing the contents of something declared as const is undefined behaviour. That's why the compiler is basically yelling at you not to do what you are doing, and that is to pass a const char* to a char*. The types are not the same.
When you applied the cast, you told the compiler to "shut up" -- you did not "convert" or change the types. To get around this, actually create a real, bona-fide, writeable, char buffer and pass that instead.
First of all, the language you're using is C++. Why such low-level 'C' usage? (I know it's C++, since you can't declare variables in the middle of a functional block in C, and that is exactly what you're doing in your code snippets).
Code:
#include <vector>
#include <string>
//...
//.. Create some std::string's here
std::string pswd(env->GetStringUTFChars(thePassword, 0));
std::string key(env->GetStringUTFChars(theKey, 0));
//..
//...Convert them to vectors for writing purposes
std::vector<char> vpswd(pswd.begin(), pswd.end());
std::vector<char> vkey(key.begin(), key.end());
vpswd.push_back(0);
vkey.push_back(0);
//..
//.. now declare the out variable
int length = int((7+length)/8)*8;
std::vector<char> out(length + 1, 0);
//...now call the function
int code = decryptAddress(&vpswd[0], &out[0], &vkey[0]);
jstring result = env->NewStringUTF(&out[0]);
Now, if the parameters were const char*, then there would be no need for the vectors at all, since std::string has a c_str() member function that returns a const char*.
The vector is basically a dynamic array that is writeable. Note how the address of the first element is passed to the function. For vector<T> a pointer to the first element is a T*, thus a vector<char> first element is a char*, and voila.
Also note that there is no need for cleanup -- no calls to free(), delete[], or anything. To be honest with you, you should write your JNI code this way, and that is to use RAII classes that on exit of a functional block, destroy themselves properly (classes like std::string and std::vector). If for some reason a JNI function throws an exception back to Java, you had better make sure you clean up that allocated memory, and you can't do that (or you can't do that easily) calling low-level 'C' functions such as malloc(), or even with operator new.
In addition, you also need to make your JNI functions that create and destroy resources safer. You should make use of (again) RAII -- look up that term, and you will see what it means and why frankly, it is a must if you're writing a JNI layer.
Regards,
Paul McKenzie
Re: LoadLibrary giving system err 183 while loading Crypto dll
An RAII example:
Let's say that there is a JNI function that creates a string, and you know you must call this function's converse to release the string.
So pretend the mythical functions are: JNICreateString and JNIReleaseString:
Code:
const char *p = JNICreateString( whatever );
// now do stuff with p
JNIReleaseString( p );
So that looks OK right? However, what happens if "do stuff with p" throws an exception? You never get to the line of code that calls JNIReleaseString, thus you now have a memory leak.
The way to get around this is to use RAII:
Code:
struct JNIStringHandler
{
const char *theString;
JNIStringHandler( const char *s) : theString(s) {}
~JNIStringHanlder() { JNIReleaseString( theString ); }
};
//...
const char *p = JNICreateString( whatever );
JNIStringHandler handler(p);
// now do stuff with p
What was accomplished? First, there is no need to call JNIReleaseString. Second, if an exception is thrown in "do stuff with p", JNIReleaseString is automatically called. Can you figure out why you don't need to call JNIReleaseString any more, and the JNIReleaseString gets called automatically, regardless of how we leave that block of code (exception, a normal return, whatever)?
That's RAII in a nutshell.
Regards,
Paul McKenzie
Re: LoadLibrary giving system err 183 while loading Crypto dll
Quote:
Cryptowrapper calling crypto which in turn uses cryptopp.
int __declspec( dllexport ) __stdcall decrypt(char *in, char *out, char *systemKey)
Quote:
Now, if the parameters were const char*, then there would be no need for the vectors at all, since std::string has a c_str() member function that returns a const char*.
Do you have the source for crypto? If yes, I suggest that you change the interface so that both in and systemKey are const char *. This would simplify things.
As general good practice, function parameters which are not changed by the function should be passed as const.