2

I have a native program that hosts the CLR (i.e. starts it up manually, gets a reference to an AppDomain, etc. - this is not C++/CLI). Within that context, I want to instantiate a FileStream object.

To my understanding, the best way of creating objects in this context is to use reflection:

SAFEARRAY* pArgs = SafeArrayCreateVector(VT_VARIANT, 0, 2);
...
BSTR assemblyName = SysAllocString(L"mscorlib");
BSTR typeName = SysAllocString(L"System.IO.FileStream");
pAppDomain->CreateInstance_3(assemblyName, typeName, VARIANT_TRUE, BindingFlags_Default, NULL, pArgs, NULL, NULL, NULL, &result);

This works fine for all sorts of other types I've tried to create; e.g. MemoryStream. But FileStream specifically has got me stumped, seemingly because FileStream expects Enum types in its constructor (e.g. System.IO.FileAccess). If I try to give it a VT_I4 (the base type of the Enum) in the place of the FileAccess parameter, it complains that it can't find the constructor (HRESULT is COR_E_MISSINGMETHOD) - which does make sense... but given Enums are value types, there's no obvious VARIANT type to use.

Is there a way to use reflection in the context of using a hosted CLR, to invoke arbitrary constructors/methods, when some of the parameters are Enums?

2
  • VT_RECORD maybe? Commented Jul 10, 2023 at 13:26
  • That's not possible. Possible workarounds are to call Type.GetConstructor() so you can call the FileStream constructor you want directly and, easier, just to write a little helper assembly in C# that takes care of the tough cases. Commented Jul 10, 2023 at 23:13

1 Answer 1

0

Indeed, constants need to be "boxed"; passing them as integers fails. I found a way to do that when writing a low-level library to access .NET. What worked for me was to generate the constants at run-time:

  • generate a compiler object

  • compile and run the code below to generate an assembly containing a BoxHelper object with a Box method,

  • create a BoxHelper object and invoke on it Box(name of the assembly, name of the constant type, value of the constant) in your case, something like: myBoxHelper.Box("mscorlib", "System.IO.FileAccess", 1) with the following values:

    FileAccess_Read = 1, FileAccess_Write = 2, FileAccess_ReadWrite = 3

The source code to send to the compiler: "using System; using System.Reflection; using System.Runtime.InteropServices; public class BoxHelper {public IntPtr Box(string assem, string typ, int valu) {Type t=Type.GetType(typ); if(t==null){Assembly a=Assembly.LoadWithPartialName(assem); t = a.GetType(typ);}; return Marshal.GetIUnknownForObject(Enum.ToObject(t,valu));}}"

hope it helps

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.