C++/CLI LoadLibrary在将System::String转换为LPCWSTR和const char*时失败



试图传入一个用户提供的字符串,该字符串有一个到jvm.dll的路径,但它不会加载库,除非我用以下硬代码:

#define RUNTIME_DLL _T("C:\Program Files\Java\jre7\bin\Server\jvm.dll")

如果我尝试以下操作,它会编译但失败:

HINSTANCE handle = LoadLibrary((const char*)Marshal::StringToHGlobalAnsi(string).ToPointer());

"string"var具有与_T()完全相同的复制粘贴路径,但仍然失败。不是C/C++方面的专家,所以我不确定是什么_T()让它起作用。

更新:

尝试过这个:

// System::String always stored as Unicode, get a Unicode pointer with no conversion necessary
        pin_ptr<const WCHAR> lib_name = PtrToStringChars(string);
        // Always use the Unicode version of LoadLibrary
        HINSTANCE handle = LoadLibraryW(lib_name);

但是它仍然不会加载jvm.dll文件。只有当我这样做时,它才会加载:

#define RUNTIME_DLL _T("C:\Program Files\Java\jre7\bin\Server\jvm.dll")
        // System::String always stored as Unicode, get a Unicode pointer with no conversion necessary
        pin_ptr<const WCHAR> lib_name = PtrToStringChars(RUNTIME_DLL);
        // Always use the Unicode version of LoadLibrary
        HINSTANCE handle = LoadLibraryW(lib_name);

也尝试过:

        // System::String always stored as Unicode
        marshal_context^ ctx = gcnew marshal_context();
        pin_ptr<const WCHAR> lib_name = PtrToStringChars(jvmDllPath);           
        //const wchar_t * lib_name = ctx->marshal_as<const wchar_t*, System::String^>(jvmDllPath);
        printf("JVM Path: %s", lib_name);
        // Always use the Unicode version of LoadLibrary
        handle = LoadLibraryW(lib_name);            
        if( handle == 0) {
            printf("Failed to load jvm dll n");
            //printf(ErrorExit((LPTSTR)(const char*)"Initialize"));
                            // this is the part that will work
            System::String^ string = gcnew System::String("C:\Program Files\Java\jre7\bin\Server\jvm.dll");
            pin_ptr<const WCHAR> lib_name = PtrToStringChars(string);
            handle = LoadLibraryW(lib_name);
        }
        delete ctx;  // do this for now to not create memory leaks

C++/CLI方法签名为:

void Initialize(String^ jvmDllPath)

正文基本上就是上面的代码

用字符串参数调用这个的C#代码是这样的:

obj.Initialize("c:\program files\java\jdk7\jre\bin\server\jvm.dll");

从Ben的建议中提供答案,这样人们/新手和临时的c/c++/cli程序员就可以找到一个快速的答案来避免我所经历的:

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

System::String^中获取C样式字符串有更好的方法。查看VC++提供的marshal_asmarshal_context模板。

这里的直接问题是,您正在为Unicode进行编译,因此LoadLibrary需要Unicode字符串,但StringToHGlobalAnsi不返回Unicode字符串。再多的指针投射也不会改变所指向字符串的编码。

您还存在内存泄漏。

试试这个:

#include <vcclr.h>
// System::String always stored as Unicode, get a Unicode pointer with no conversion necessary
pin_ptr<const WCHAR> lib_name = PtrToStringChars(string);
// Always use the Unicode version of LoadLibrary
HINSTANCE handle = LoadLibraryW(lib_name);

如果这是有效的,而上面没有,那么从C#发送的字符串有问题:

System::String^ string = gcnew System::String(L"C:\Program Files\Java\jre7\bin\Server\jvm.dll");
pin_ptr<const WCHAR> lib_name = PtrToStringChars(string);
HINSTANCE handle = LoadLibraryW(lib_name);

最新更新