-1

[NOT A DUPLICATE, I've searched for solutions for days and had performed a lot of tests only to find nothing really helps. That's why I registered stackoverflow and posted this.]

[SITUATION]
I am trying to perform COM interops in C# but I'm not quite familiar with how COM works.
There's a COM library without any .tlb file. Fortunately I found its .idl file in an open repository on github. Then I copied the interface declarations to my own project and rewrote them in C#.
Everything looks great only if I just retrieve COM objects from which methods can be called. That's how this library works.

[PROBLEM]
Well the problem is, this library requests for an implementation of an interface to perform IO operations which shall be customized(e.g. redirection to stdout/file/printer) by the caller.
It forces me to give an instance of this interface by calling an stdcall function from a dllimport library.
I tried everything I can, just keeps failing.
To be more specific, see the code below.

[CODE]

// The interface I rewrote from .idl file which I must give implementation of.
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid(<GUID>)]
public interface IFoo
{
    int Bar(string s);
}
// The implementation I would like to provide
[ClassInterface(ClassInterfaceType.None), Guid<GUID>]
public class MyFoo : IFoo
{
    public int Bar(string s)
    {
        Console.Write(s);
        return 0; //S_OK
    }
}
// This is the delegate for the function. 
// The function itself is obtained by GetProcAddress
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int Function(IntPtr obj);
// Here's the code I used
Function func = <GetProcAddress stuff>;
IFoo obj = new MyFoo();
IntPtr objPtr = Marshal.GetIUnknownForObject(obj);
int hresult = Function(objPtr);
if (hresult != 0) // S_OK
    throw new Exception($"Failed 0x{hresult:x}");

[SO FAR]
The hresult is supposed to be 0(S_OK) if this function succeeds, but it just keeps getting 0x80131515.
Well, I'm convinced that the problem has nothing to do with the Function, because I found another snippet of code succeeded.
Instead of redeclaring the interface then implement, that code just manually constructs a VTable for the interface by filling it with function pointers.
That's really not what I want, because the code looks not so clean, neither so safe.
I've been searching for solutions for days, but just found little information about this. Seems COM has been out of date.

Qiu
  • 1
  • 1
  • What you are trying to do is far from clear. Your code that mixes COM with GetProcAddress makes little sense. Do you have a completely reproducing project? PS: COM is far from being out of date. – Simon Mourier Dec 13 '21 at 08:56
  • @SimonMourier I'm sorry, actually I'm calling `CLRDataCreateInstance` from mscordacwks.dll. That's an exported C-Style function, so I can only call it this way. I found clrMD doing this way too. But it built its own VTable to provide implementations, see this:[link](https://github.com/microsoft/clrmd/blob/master/src/Microsoft.Diagnostics.Runtime/src/DacInterface/DacDataTargetWrapper.cs) I just try to redeclare `interface ICLRDataTarget` then implement it explicitly. – Qiu Dec 13 '21 at 10:15
  • @SimonMourier In addition, [getprocaddress stuff](https://github.com/microsoft/clrmd/blob/master/src/Microsoft.Diagnostics.Runtime/src/DataTargets/DacLibrary.cs#L136) shows its calling. [my repo](https://github.com/Qiu233/ClrDiagRemote) This is my repo, README shows where the problem is. – Qiu Dec 13 '21 at 10:25
  • I don't see any strictly COM-related issue. The error seems legitimate. But the system is also querying for ICLRDataTarget2, ICLRDataTarget3, ICLRMetadataLocator (and another unknown one) and I think you must implement ICLRMetadataLocator too. – Simon Mourier Dec 13 '21 at 11:49
  • @SimonMourier That's right, but I first tried to delete existed `ICLRMetadataLocator` and `ICLRRuntimeLocator` implementations from clrMD's code, it surprisingly still works well. Only after translating it to explicit does it malfunction. I took some native debugging to CLRDataCreateInstance, and found the problem is just like you said, it's querying for other several interfaces but failed. Well, problem solved, thank you. – Qiu Dec 13 '21 at 12:37

1 Answers1

-1

Problem solved.
The code shown in question was supposed to work, but didn't. I found that's CLR's COM interop issue. Some code in Function cannot simply be called that way.(by letting GC hold the object)
This is a very uncommon situation and it's hard to explain all specifics. For more information, please search for ReleaseHolder in dotnet's runtime repo.
That's all. I just don't know why this answer is said unclear. It can't be more clear anyway.

Qiu
  • 1
  • 1
  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 13 '21 at 20:28