Search code examples
.netc++-clijava-native-interface

Converting characters to Unicode with C++/CLI results in random characters


I'm reading in some text from across the net and some of it may have foreign language characters... reading it in through C++/CLI and wan't to convert the string to a managed String^ but seem to be having some trouble. Here is the code snippet I am using

String^ NativeToCliString(const char * nString) {
    String^ converted; // = gcnew String("");
    if (nString != NULL)
    {
        converted = (gcnew marshal_context())->marshal_as<String^>(nString);
    }
    return converted;
}

The function doesn't throw errors, however, when I output the code to the windows form it shows a bunch of random (ASCII) characters...

The JNI method I use is fairly simple.... I can post that code as well if needed. Essentially, I just call into the Java layer and it returns a const char * and then I pass that here. It works, but just is not converted to properly to unicode.

---- UPDATE ---- Here is the working new code based on Hans' suggestion:

int bufSize = MultiByteToWideChar(CP_UTF8, 0 , raw , -1, NULL , 0 );
wchar_t* wstr = new wchar_t[bufSize];
MultiByteToWideChar( CP_UTF8 , 0 , raw , -1, wstr , bufSize );
String^ val = gcnew String(wstr);                           
delete[] wstr;

Solution

  • Here's how to do it... I used an if statement as I had two virtual machines with two different OS's but either way works on either one.

            String^ JStringToCliString(const jstring string){
            String^ converted = gcnew String("");
            JNIEnv* envLoc = GetJniEnvHandle();
            std::wstring value;
            jboolean isCopy;
    
            if(string){
                try{
                    jsize len = env->GetStringLength(string);
                    if(Environment::OSVersion->Version->Major >= 6) // 6 is post XP/2003                                        
                    {
                        TraceLog::Log("Using GetStringChars() for string conversion");
                        const jchar* raw = envLoc->GetStringChars(string, &isCopy);
                        // todo add exception handling here for jvm
                        if (raw != NULL) {                          
                            value.assign(raw, raw + len);
                            converted = gcnew String(value.c_str());
                            env->ReleaseStringChars(string, raw);
                        }
                    }else{
                        TraceLog::Log("Using GetStringUTFChars() for string conversion.");
                        const char* raw = envLoc->GetStringUTFChars(string, &isCopy);
                        if(raw) {
                            int bufSize = MultiByteToWideChar(CP_UTF8, 0 , raw , -1, NULL , 0 );
                            wchar_t* wstr = new wchar_t[bufSize];
                            MultiByteToWideChar( CP_UTF8 , 0 , raw , -1, wstr , bufSize );
                            String^ val = gcnew String(wstr);                           
                            delete[] wstr;
    
                            converted = val; // partially working
                            envLoc->ReleaseStringUTFChars(string, raw);
                        }                       
                    }
                }catch(Exception^ ex){
                    TraceLog::Log(ex->Message);
                }
            }
            return converted;
        }