3

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?

Karim Agha
  • 3,606
  • 4
  • 32
  • 48
  • It probably works just fine, your C++ EXE is running with a different default directory so File.Exists() returns false. Giving you the expected null string. – Hans Passant Jan 03 '12 at 22:55

1 Answers1

2

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.

  • That was not the case. It was returning NULL event when I set the value of url explicitly to a string literal. – Karim Agha Jan 04 '12 at 03:43
  • 1
    I suggest you start debugging. Make sure you set the 'Debugger Type' to 'Mixed' which enables you to debug both the native client code and the managed server code. – Vapour in the Alley Jan 04 '12 at 07:59