Question

I'm struggling with a scenario where I have a managed interface exposed through COM and consumed by a native client. I've managed to isolate the problem and it basically boils down to a string being improperly marshalled by the interop runtime, to simulate and reproduce this problem I've created a small project that looks like this:

Server:

[ComVisible(true)]
[Guid("5AF8A86E-B129-4FA0-8B6D-E9DF52DFDD84")]
public interface IUrlSync
{
    void GetUrl(
        [MarshalAs(UnmanagedType.BStr)] [Out] out string url
        );
}

[ComVisible(true)]
[Guid("5AF8A86E-B129-4FA0-8B6D-E9DF52DFDD85")]
public class Urlsync : IUrlSync
{
    private const string AddressHolderPath = "url.txt";

    public Urlsync()
    {
        // nothing
    }

    public void GetUrl(out string url)
    {
        url = File.Exists(AddressHolderPath) ? 
            File.ReadAllText(AddressHolderPath) : null;
    }
}

after compiling this class and executing regasm + gacutil /i, I've built this small

Native Client:

#include <Windows.h>
#import "../comstr/bin/release/comstr.tlb"

int main(int argc, char* argv[])
{
    CoInitialize(NULL); {

        BSTR bstr;
        HRESULT hr = S_OK;

        comstr::IUrlSyncPtr sync(__uuidof(comstr::Urlsync));
        hr = sync->GetUrl(&bstr);

    } CoUninitialize();
    return 0;
}

And here the value in hr is S_OK and bstr is set to NULL (0x000000).

To make sure that the problem is with the marshalling itself I've build a

managed client:

That calls the UrlSync class from a different assembly:

        string bstr;
        comstr.IUrlSync sync = new comstr.Urlsync();

        sync.GetUrl(out bstr);
        Console.WriteLine("the url is: {0}", bstr);

and I'm getting the expected string. what I'm missing here?

Was it helpful?

Solution

I have built your sample programs and found it actually works as expected. There are however some issues with your program.

If the file does not exist you actually get the null response you currently encounter. Could this be the case? Take into account that the run time folder may be different from the managed client you built as an extra test.

You could simply step through both projects in the debugger to see what's going on.

The marshaller code generated by the #import statement throws _com_error exceptions which you do not catch.

Hope this helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top