Skip to content

What is an "Assembly qualified delegate type name"? #16646

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

Closed
brianjenkins94 opened this issue Jan 12, 2020 — with docs.microsoft.com · 11 comments
Closed

What is an "Assembly qualified delegate type name"? #16646

brianjenkins94 opened this issue Jan 12, 2020 — with docs.microsoft.com · 11 comments
Assignees
Milestone

Comments

Copy link

Does this provide me a way to specify the function signature of the C# method?

What would an example of this parameter look like?

https://github.com/dotnet/samples/blob/master/core/hosting/HostWithHostFxr/src/NativeHost/nativehost.cpp#L104


Document Details

Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

@brianjenkins94
Copy link
Author

brianjenkins94 commented Jan 15, 2020

@brianjenkins94
Copy link
Author

brianjenkins94 commented Jan 15, 2020

Ah, it looks like I need to fallback on the CoreClrHost API:

https://github.com/dotnet/runtime/blob/master/src/coreclr/src/hosts/inc/coreclrhost.h#L79-L99

@brianjenkins94
Copy link
Author

brianjenkins94 commented Jan 21, 2020

Still interested in the answer to the original question, though.

@Thraka
Copy link
Contributor

Thraka commented Jan 28, 2020

I'll ping the author on email.

@Thraka Thraka added product-question waiting-on-feedback Waiting for feedback from SMEs before they can be merged and removed ⌚ Not Triaged Not triaged labels Jan 28, 2020
@mjrousos
Copy link
Member

Regarding the original question, yes, my understanding is that HostFxr allows specifying a particular overload of a managed method by giving the (assembly-qualified) name of a delegate defining the method signature (as opposed to hosting with CoreClrHost.h, which only looks up managed entry points by method name).

You should be able to just provide a string containing the assembly-qualified name of the delegate type matching your entry point's signature (including, perhaps, marshaling attributes).

cc'ing @vitek-karas to confirm this, though, because I'm not very experienced with HostFxr.

@vitek-karas
Copy link
Member

The code which consumes that string is here: https://github.com/dotnet/runtime/blob/eb95163a0880cac1ba127b81e3cb753e5a65f8cc/src/coreclr/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComponentActivator.cs#L64

If you specify null it defaults to the `ComponentEntryPoint delegate: https://github.com/dotnet/runtime/blob/eb95163a0880cac1ba127b81e3cb753e5a65f8cc/src/coreclr/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComponentActivator.cs#L19

If you specify a value, it is effectively passed to Type.GetType(yourValue, ...): https://github.com/dotnet/runtime/blob/eb95163a0880cac1ba127b81e3cb753e5a65f8cc/src/coreclr/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComponentActivator.cs#L114

It should be assembly qualified to avoid possible issues with duplicate type names across assemblies, but in reality it's not enforced.

As @mjrousos noted this lets you declare the method signature via declaring a delegate type in C#. The added benefit is that you can use marshalling attributes in the delegate if necessary.

@brianjenkins94
Copy link
Author

brianjenkins94 commented Jan 30, 2020

So I should be able to invoke this:

namespace SamplePrecompiledAssembly {
	public static class Startup {
		public static Func<object, Task<object>> Func(string code) { // <--

Like this?:

returnCode = load_assembly_and_get_function_pointer_fn(loadAssemblyAndGetFunctionPointer)(
	assemblyPath.c_str(),
	assemblyQualifiedTypeName.c_str(),
	methodName.c_str(),
	std::string("SamplePrecompiledAssembly.Startup+Func, SamplePrecompiledAssembly").c_str(), // <--
	nullptr,
	reinterpret_cast<void **>(&run));

@vitek-karas
Copy link
Member

The string should point to a delegate type, not a method. So something like this should work:

namespace SamplePrecompiledAssembly {
	public static class Startup {
                public delegate Func<object, Task<object>> MyFuncDelegate(string);

		public static Func<object, Task<object>> Func(string code) { 
                }
        }
}

And then you should be able to use:
SamplePrecompiledAssembly.Startup.MyFuncDelegate as the string for the function.

Note that given this sample it may not work as I don't know how the interop would marshal a Func<,> to native code. And even if it did manage to do that, there would be no way from the native code to operate on Task<object>.

@brianjenkins94
Copy link
Author

brianjenkins94 commented Feb 1, 2020

Hmm, I'm beginning to think this might be a product bug.

Steps to Reproduce:

git clone https://github.com/brianjenkins94/Run-DNC.git
cd Run-DNC
npm install
npm build # For whatever reason on Windows you just need to keep building through errors about architecture mismatches and errors writing to the program database.
npm start

Output on Windows 10:

> [email protected] start C:\Users\User\Documents\GitHub\Run-DNC
> node test.js

get_hostfxr_path() = 0
hostfxr_initialize_for_runtime_config_fn() = 0
hostfxr_get_runtime_delegate_fn() = 0
hostfxr_close_fn() = 0

assembly_path = "C:\\Users\\User\\Documents\\GitHub\\Run-DNC\\src\\SamplePrecompiledAssembly\\bin\\Debug\\netstandard2.1\\SamplePrecompiledAssembly.dll"
type_name = SamplePrecompiledAssembly.Startup, SamplePrecompiledAssembly
method_name = Invoke
delegate_type_name = SamplePrecompiledAssembly.Startup.InvokeDelegate, SamplePrecompiledAssembly

load_assembly_and_get_function_pointer_fn() = 0
run() = 0

Output on macOS 10.15 and Ubuntu 18.04:

> [email protected] start /Users/bjenks/Sites/Run-DNC
> node test.js

get_hostfxr_path() = 0
hostfxr_initialize_for_runtime_config_fn() = 0
hostfxr_get_runtime_delegate_fn() = 0
hostfxr_close_fn() = 0

assembly_path = "/Users/bjenks/Sites/Run-DNC/src/SamplePrecompiledAssembly/bin/Debug/netstandard2.1/SamplePrecompiledAssembly.dll"
type_name = SamplePrecompiledAssembly.Startup, SamplePrecompiledAssembly
method_name = Invoke
delegate_type_name = SamplePrecompiledAssembly.Startup.InvokeDelegate, SamplePrecompiledAssembly

load_assembly_and_get_function_pointer_fn() = -2146233054
run() = zsh: segmentation fault

So it's working on Windows, but not on Mac or Linux.

Where would be the appropriate place to pursue this? Since I assume docs isn't it.

@vitek-karas
Copy link
Member

I didn't try to run it, but looking at the code there's a difference between Windows and Linux/Mac - when you're calling the load_assembly_and_get_function_pointer you pass the delegate type name in the Linux/Mac path, but not in the Windows path. Also the output above doesn't seem to match the code in the repo: The code in the repo would specify SamplePrecompiledAssembly.InvokeDelegate as the delegate type name (without the Startup) but the output above has it - so maybe you have local fixes?

The error code is COR_E_TYPELOAD - this would happen if the call Type.GetType(delegateTypeName) failed.

@brianjenkins94
Copy link
Author

I made those fixes and it works now.

Thank you very much for your help and patience.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants