Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Help passing multibyte unicode characters as string parameters to clr methods. #11163

Closed
weliwita opened this issue Sep 28, 2018 · 3 comments
Closed
Labels
area-Interop-coreclr question Answer questions and provide assistance, not an issue with source code or documentation.
Milestone

Comments

@weliwita
Copy link

I'm trying to find the root cause of the issue I created in this repo(agracio/edge-js#50).
I was trying to repro the issue with following steps.

  1. Copied and ran the sample https://github.com/dotnet/samples/tree/master/core/hosting successfully.
  2. Added the following method to my core app.
public static void Run(string s)
	{
        var x = "a";
        var y = "å";
        var z = s;
        Console.WriteLine(x);
        Console.WriteLine(y);
        Console.WriteLine(z);
    }
  1. Calling the Run method from native code.
typedef void (STDMETHODCALLTYPE RunMethodFp)(char* args);
void *pfnDelegate = NULL;
    hr = runtimeHost->CreateDelegate(
   	  domainId,
   	  L"Core",	// Target managed assembly
   	  L"Test",				// Target managed type
   	  L"Run",									// Target entry point (static method)
   	  (INT_PTR*)&pfnDelegate);
    if (FAILED(hr))
    {
   	  printf("ERROR - Failed to create delegate.\nError code:%x\n", hr);
   	  return -1;
    }
char* param= "å";
((RunMethodFp*)pfnDelegate)(param);
  1. I got for the z parameter. (c3 00 a5 00).

  2. I tried the following combinations without luck.

  • following code would just print à (c3 00 00 00)
 typedef void (STDMETHODCALLTYPE RunMethodFp)(LPWSTR args);
LPWSTR param= L"å";
  • following code would just print à (c3 00 00 00)
 typedef void (STDMETHODCALLTYPE RunMethodFp)(BSTR args);
BSTR param= SysAllocString(L"å"); 
  • Tried to encode with active code point and pass as char* didn't work either.
bool acp_encode(const std::wstring &str, std::vector<char>* out)
{
	out->clear();
	size_t size = ::WideCharToMultiByte(CP_ACP, 0, str.c_str(), -1, nullptr, 0, nullptr, nullptr);
    if (size == 0)
    {
        return false;
    }
    out->resize(size, '\0');
    return WideCharToMultiByte(CP_ACP, 0, str.c_str(), -1, out->data(), out->size(), nullptr, nullptr) != 0;
}

Can you please point me to a sample on how to achieve this conversion?

@weliwita
Copy link
Author

weliwita commented Oct 1, 2018

I found the answer here http://yizhang82.me/hosting-coreclr. But I would like to have a little more detailed explanation(docs) on how the default marshaling applied cross-platform.

@weliwita
Copy link
Author

weliwita commented Oct 1, 2018

Adding [MarshalAs(UnmanagedType.LPUTF8Str)] to the managed method argument resolved initial issue. But still, I'm not able to pass a structure with UTF8 strings.

typedef struct bootstrapperContext
{
	const char* runtimeDirectory;
	const char* applicationDirectory;
	const char* dependencyManifestFile;
} BootstrapperContext;

BootstrapperContext context;
context.runtimeDirectory = "";
context.applicationDirectory="å";
context.dependencyManifestFile="";

The CLR side.


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct EdgeBootstrapperContext
{
    [MarshalAs(UnmanagedType.LPUTF8Str)]
    public string RuntimeDirectory;

    [MarshalAs(UnmanagedType.LPUTF8Str)]
    public string ApplicationDirectory;

    [MarshalAs(UnmanagedType.LPUTF8Str)]
    public string DependencyManifestFile;
}

public static void Run2(EdgeBootstrapperContext c)
{
        var z = c.ApplicationDirectory;
        Console.WriteLine(z);
}

Please suggest proper attributes or point me to some documentation where the marshaling behavior is defined.

@AaronRobinsonMSFT
Copy link
Member

@weliwita Please see the new Native interoperability documentation that @jkoritzinsky has written. The marshalling of strings is non-trivial due to the intersection of platform and "default" encoding. If there is something missing in our new documentation please create an issue and tag @jkoritzinsky and me. Thanks!

@msftgits msftgits transferred this issue from dotnet/coreclr Jan 31, 2020
@msftgits msftgits added this to the 3.0 milestone Jan 31, 2020
@dotnet dotnet locked as resolved and limited conversation to collaborators Dec 15, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-Interop-coreclr question Answer questions and provide assistance, not an issue with source code or documentation.
Projects
None yet
Development

No branches or pull requests

3 participants