jborean
jborean
CC#
Created by jborean on 4/28/2024 in #help
AssemblyLoadContext LoadfromAssemblyPath vs LoadFromNativeImagePath
What is the difference between LoadfromAssemblyPath and LoadFromNativeImagePath? When would I ever need/want to use the latter?
8 replies
CC#
Created by jborean on 4/8/2024 in #help
sans-io pattern in .NET library
I'm a big fan of writing sans-io implementations https://sans-io.readthedocs.io/ of various protocols which help focus on the actual protocol details while leaving the IO questions to other libraries that implement the code. I am curious what some people might recommend for dealing with the message buffer, that is bytes that are produced to be written to the target and bytes that should be read from the target. I am interested in efficient ways to provide this buffer without producing unnecessary copies and ensure it doesn't slow things down. I was thinking that System.IO.Pipelines would be good for this but curious if there are potentially other options.
6 replies
CC#
Created by jborean on 3/26/2024 in #help
Invoke method with [Optional] with default value through Reflection
Is it possible to through reflection to invoke a method with an [Optional] attribute. For example Type.Missing works for an argument with a default value but not for an [Optional] argument.
using System;
using System.Reflection;
using System.Runtime.InteropServices;

public class Program
{
public static void Main(string[] args)
{
object? test1 = typeof(Program).GetMethod("MethodWithDefault").Invoke(null, new[] { Type.Missing });
object? test2 = typeof(Program).GetMethod("MethodWithOptional").Invoke(null, new[] { Type.Missing });
Console.WriteLine(test1);
Console.WriteLine(test2);
}

public static int MethodWithDefault(int value = 1) => value;
public static int MethodWithOptional([Optional]int value) => value;
}
using System;
using System.Reflection;
using System.Runtime.InteropServices;

public class Program
{
public static void Main(string[] args)
{
object? test1 = typeof(Program).GetMethod("MethodWithDefault").Invoke(null, new[] { Type.Missing });
object? test2 = typeof(Program).GetMethod("MethodWithOptional").Invoke(null, new[] { Type.Missing });
Console.WriteLine(test1);
Console.WriteLine(test2);
}

public static int MethodWithDefault(int value = 1) => value;
public static int MethodWithOptional([Optional]int value) => value;
}
6 replies
CC#
Created by jborean on 3/1/2024 in #help
✅ COM + NativeAOT Help
I'm fairly new to COM and I'm trying to implement an RDP Dynamic Virtual Channel client dll which uses the IWTSPlugin COM interface https://learn.microsoft.com/en-us/windows/win32/api/tsvirtualchannels/nn-tsvirtualchannels-iwtsplugin. Can anyone point out what I might be doing wrong here https://gist.github.com/jborean93/394592c89fc8bfd54990d814a29b924f as this just crashes my process and the WTSPlugin-log.txt is never created. I'm not 100% confident on how I'm setting the COM pointer on the VirtualChannelGetInstance implementation but I know for sure that mstsc is calling that particular method it as the logs are showing that it is called and the process crashes because I am doing something dumb. I do have a few other questions that hopefully someone might be able to clarify + Do I need to save the WTSPlugin and StrategyBasedComWrappers instance or can they be discarded once I've passed the pointer to the unmanaged instance + What is the correct way to define another COM interface (pointer to the interface type in COM land) as an argument + Are there any recommendations for PreserveSig or not having it
32 replies
CC#
Created by jborean on 2/7/2024 in #help
Init only collection property contructor from IEnumerable
I was wondering if there was a way to assign an IEnumerable to a init only collection property. For example I can do
ProcessStartInfo psi = new()
{
ArgumentList = { "foo", "bar" },
};
ProcessStartInfo psi = new()
{
ArgumentList = { "foo", "bar" },
};
But I was wondering if I could somehow do
IEnumerable<string> arguments = ...;
ProcessStartInfo psi = new()
{
ArgumentList = arguments,
};
IEnumerable<string> arguments = ...;
ProcessStartInfo psi = new()
{
ArgumentList = arguments,
};
I'm currently just looping through the enumerable and doing psi.ArgumentList.Add(a); as a fallback but just wanted to check if there was another way
17 replies
CC#
Created by jborean on 1/13/2024 in #help
Create dynamic class that implements interface with static properties
Sorry for the PowerShell but I'm trying to figure out how to create a class that implements an interface with a static property and I have the following
using namespace System.Reflection
using namespace System.Reflection.Emit

$ErrorActionPreference = 'Stop'

Add-Type -TypeDefinition @'
public interface IProperty
{
static abstract int Id { get; }
}

public class CSharpProperty : IProperty
{
public static int Id { get => 1; }
}
'@

$ab = [AssemblyBuilder]::DefineDynamicAssembly(
[AssemblyName]::new("MyAssembly"),
[AssemblyBuilderAccess]::Run)
$mb = $ab.DefineDynamicModule("MyModule")
$tb = $mb.DefineType(
"MyClass",
[TypeAttributes]::Public,
$null,
[type[]]@([IProperty]))

$getAttr = $tb.DefineMethod(
"get_Id",
[MethodAttributes]"Public, Static, HideBySig, SpecialName",
[int],
[type]::EmptyTypes)
$getAttrIl = $getAttr.GetILGenerator()
$getAttrIl.Emit([OpCodes]::Ldc_I4_1)
$getAttrIL.Emit([OpCodes]::Ret)

$pb = $tb.DefineProperty(
"Id",
[PropertyAttributes]::None,
[int],
$null)
$pb.SetGetMethod($getAttr)

$null = $tb.CreateType()

[MyClass]::Id
using namespace System.Reflection
using namespace System.Reflection.Emit

$ErrorActionPreference = 'Stop'

Add-Type -TypeDefinition @'
public interface IProperty
{
static abstract int Id { get; }
}

public class CSharpProperty : IProperty
{
public static int Id { get => 1; }
}
'@

$ab = [AssemblyBuilder]::DefineDynamicAssembly(
[AssemblyName]::new("MyAssembly"),
[AssemblyBuilderAccess]::Run)
$mb = $ab.DefineDynamicModule("MyModule")
$tb = $mb.DefineType(
"MyClass",
[TypeAttributes]::Public,
$null,
[type[]]@([IProperty]))

$getAttr = $tb.DefineMethod(
"get_Id",
[MethodAttributes]"Public, Static, HideBySig, SpecialName",
[int],
[type]::EmptyTypes)
$getAttrIl = $getAttr.GetILGenerator()
$getAttrIl.Emit([OpCodes]::Ldc_I4_1)
$getAttrIL.Emit([OpCodes]::Ret)

$pb = $tb.DefineProperty(
"Id",
[PropertyAttributes]::None,
[int],
$null)
$pb.SetGetMethod($getAttr)

$null = $tb.CreateType()

[MyClass]::Id
It's failing with
Exception calling "CreateType" with "0" argument(s): "Virtual static method 'get_Id' is not implemented on type 'MyClass' from assembly 'MyAssembly, Version=0.0.0.0,Culture=neutral, PublicKeyToken=null'."
Looking at the IL code in sharplab.io for the equivalent C# code doesn't have anything jumping out at me https://sharplab.io/#v2:C4LglgNgPgAgzAAjAO2AUwE4DMCGBjNBASQAUMB7AB02AE8BYAKAG8mF2EYBGANgRwBGAZ2AZ8wJKmIATBMwQBzNMADcCAL5NNjJvE4AmBAGEAygAscGSmSo1aCEMRvUMdJq0YdOibnxQSiWXklCQBeAD4ELjVtdSA==. When adding the MethodAttributes.Virtual to the get_Id method builder it fails saying methods can't be static and virtual. Am I just missing something simple or is there something else I need to do here?
18 replies
CC#
Created by jborean on 10/10/2022 in #help
Uncaught Exception C++ hostfxr Handling
Hi I have a C++ dll that I am using to host some dotnet assembly and normally things work but when something bad happens, like a missing reference assembly, it fails with an uncaught exception. Now I know the code I have is wrong but what I am hoping to figure out is how to get the exception details. I can use dotnet-dump to dump the process, then dotnet-analyse to then select the proper thread and then pe -lines to get the exception information but I am hoping to just get that as part of the hosting code and log that somewhere in a file. I've tried to wrap the function ptr in a try/catch with various exception types as well as just
c++
typedef void(CORECLR_DELEGATE_CALLTYPE * custom_entry_point_fn)(worker_args_t args);
custom_entry_point_fn dotnet_main = nullptr;
int rc = load_assembly_and_get_function_pointer(
dotnetlib_path.c_str(),
L"...",
L"Main",
UNMANAGEDCALLERSONLY_METHOD,
nullptr,
(void **)&dotnet_main);

worker_args_t args{...};

try
{
dotnet_main(args);
}
catch (...)
{
std::cerr << "testing" << '\n';
}
c++
typedef void(CORECLR_DELEGATE_CALLTYPE * custom_entry_point_fn)(worker_args_t args);
custom_entry_point_fn dotnet_main = nullptr;
int rc = load_assembly_and_get_function_pointer(
dotnetlib_path.c_str(),
L"...",
L"Main",
UNMANAGEDCALLERSONLY_METHOD,
nullptr,
(void **)&dotnet_main);

worker_args_t args{...};

try
{
dotnet_main(args);
}
catch (...)
{
std::cerr << "testing" << '\n';
}
But no matter what I try to catch it with, the debugger always displays uncaught exception without any way to get those exception details, e.g.
Exception has occurred: W32/0xE0434352 Unhandled exception at 0x00007FF8EC62FF6C (KernelBase.dll) in notepad.exe: 0xE0434352 (parameters: 0xFFFFFFFF80070002, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x00007FF8A1AF0000).
I've then tried to hook up my own handler for hostfxr_set_error_writer that calls a simple function like the below but it is never called
c++
void hostfxr_error_handler(const char_t *message)
{
return;
}
c++
void hostfxr_error_handler(const char_t *message)
{
return;
}
I've tried to wrap the C# code it's calling in just a generic try { } catch {} as well as AppDomain.CurrentDomain.UnhandledException to try and see if I can just catch the exception to handle accordingly but none of it works. Does anyone have any suggestions or hints as to what I could potentially try.
2 replies