C
C#•4mo ago
jborean

✅ 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
Gist
IWTSPlugin.cs
GitHub Gist: instantly share code, notes, and snippets.
21 Replies
Unknown User
Unknown User•4mo ago
Message Not Public
Sign In & Join Server To View
reflectronic
reflectronic•4mo ago
i would prefer using ComInterfaceMarshaller<IWTSPlugin>.ConvertToUnmanaged over instantiating the StrategyBasedComWrappers yourself
jborean
jborean•4mo ago
If it helps I'm compiling it for win-x64 with
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<InvariantGlobalization>true</InvariantGlobalization>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
</PropertyGroup>

</Project>
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<InvariantGlobalization>true</InvariantGlobalization>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
</PropertyGroup>

</Project>
reflectronic
reflectronic•4mo ago
that doesn't change much, it's just a little cleaner and more efficient i would also skip the PreserveSig, it's just more work
jborean
jborean•4mo ago
I'm assuming if I don't have PreserveSig it's just a void return here as none of those functions have an out return value
reflectronic
reflectronic•4mo ago
yea
jborean
jborean•4mo ago
Thanks for the hint on ComInterfaceMarshaller, I'll start using that
reflectronic
reflectronic•4mo ago
where exactly do your logs say you get to because at a first glance everything seems OK
jborean
jborean•4mo ago
only the VirtualChannelGetInstance is created the WTSPlugin-log.txt is not created which tells me it's failing to call Initialize()
reflectronic
reflectronic•4mo ago
how do you know it's crashing
jborean
jborean•4mo ago
the whole mstsc process crashes and I have an WER event log I think I've got it working
[UnmanagedCallersOnly(EntryPoint = "VirtualChannelGetInstance", CallConvs = [typeof(CallConvStdcall)])]
private unsafe static int VirtualChannelGetInstance(
Guid* refiid,
int* pNumObjs,
void** ppObjArray
)
{
using StreamWriter writer = new(@"C:\temp\ProcessVirtualChannel\VirtualChannelGetInstance-log.txt", true);
string now = DateTime.Now.ToString("[HH:mm:ss.fff]");
writer.WriteLine($"{now} - VirtualChannelGetInstance - {*pNumObjs}");

if (*refiid != typeof(IWTSPlugin).GUID)
{
return unchecked((int)0x80004002); // E_NOINTERFACE
}

*pNumObjs = 1;
if (ppObjArray != null)
{
void* unmanagedPtr = ComInterfaceMarshaller<IWTSPlugin>.ConvertToUnmanaged(_plugin);
*ppObjArray = unmanagedPtr;

now = DateTime.Now.ToString("[HH:mm:ss.fff]");
writer.WriteLine($"{now} - Created pointer - {*pNumObjs}");
}
else
{
now = DateTime.Now.ToString("[HH:mm:ss.fff]");
writer.WriteLine($"{now} - setting pNumObjs");
}

return 0;
}
[UnmanagedCallersOnly(EntryPoint = "VirtualChannelGetInstance", CallConvs = [typeof(CallConvStdcall)])]
private unsafe static int VirtualChannelGetInstance(
Guid* refiid,
int* pNumObjs,
void** ppObjArray
)
{
using StreamWriter writer = new(@"C:\temp\ProcessVirtualChannel\VirtualChannelGetInstance-log.txt", true);
string now = DateTime.Now.ToString("[HH:mm:ss.fff]");
writer.WriteLine($"{now} - VirtualChannelGetInstance - {*pNumObjs}");

if (*refiid != typeof(IWTSPlugin).GUID)
{
return unchecked((int)0x80004002); // E_NOINTERFACE
}

*pNumObjs = 1;
if (ppObjArray != null)
{
void* unmanagedPtr = ComInterfaceMarshaller<IWTSPlugin>.ConvertToUnmanaged(_plugin);
*ppObjArray = unmanagedPtr;

now = DateTime.Now.ToString("[HH:mm:ss.fff]");
writer.WriteLine($"{now} - Created pointer - {*pNumObjs}");
}
else
{
now = DateTime.Now.ToString("[HH:mm:ss.fff]");
writer.WriteLine($"{now} - setting pNumObjs");
}

return 0;
}
Used ConvertToUnmanaged and played around with the ppObjArray signature
reflectronic
reflectronic•4mo ago
i mean that looks the same, but if it works it works
jborean
jborean•4mo ago
you're telling me 🙂
reflectronic
reflectronic•4mo ago
idk i couldn't tell that anything was wrong
jborean
jborean•4mo ago
I'm assuming I messed up my ppObjArray signature and setting that value somehow but as you said if it works it works Do I need to keep the WTSPlugin instance alive as a static field or can it be dropped after providing the pointer to it?
reflectronic
reflectronic•4mo ago
it can be dropped
jborean
jborean•4mo ago
Thanks for the advice!
Unknown User
Unknown User•4mo ago
Message Not Public
Sign In & Join Server To View
MODiX
MODiX•4mo ago
Use the /close command to mark a forum thread as answered
Unknown User
Unknown User•4mo ago
Message Not Public
Sign In & Join Server To View
jborean
jborean•4mo ago
As sorry I wasn’t aware that was a thing here 🙂
Want results from more Discord servers?
Add your server
More Posts
Using a concrete derived type in place of an interface in a constructor signatureI have a base class whose constructor takes in an instance of a generic interface: `public Odometry(C#, Process Memory slowly going up but snapshots not indicating memory leakHello, so I've been working on testing pythonnet for use in our companies application and now am do✅ Primary Key not recognizingCan't seem to rid my code of this error, my primary key looks correctly organized for recogonition. Images doesn't show up in C# wpfhello, so i've got an assignment due next week, i've got to create a wpf which, when it launches, sh✅ C# .NET in Linux Mint : VSCode or Vbox?Does any of you frequently code using c# .net and asp.net in linux? Last time I checked vs code exte✅ WPF application doesn't boot when packed to single fileHello, I made a program in WPF, and in the publish settings I enabled "Produce single file", but the✅ Unable to configure HTTPS endpoint.The container builds successfully but then at the end it says: ```at Microsoft.Extensions.Hosting.In✅ How to share my C# console application with MacOS friends?hello. i made a very very basic c# console application game using jetbrains rider i want to share m'scriptcs' is not recognized as an internal or external commandI get this error even when I just want to print a hello world. This has not happened before.Problem with my scriptI have a problem that says (look at the picture) and here is the "Item" code (see the .cs file) th