all groups > dotnet interop > september 2004 >
You're in the

dotnet interop

group:

Returning UDT encapsulated in a Variant from a COM method leads to exception in managed code


Returning UDT encapsulated in a Variant from a COM method leads to exception in managed code Jürgen Weiss
9/27/2004 4:55:20 PM
dotnet interop:
Hi,
I've encountered a very basic problem when dealing with User Defined Types (UDT) in a COM class.
If a COM method returns a UDT in a VARIANT, the calling .NET application receives an
exception "The specified record cannot be mapped to a managed value class.".

In order to reproduce this problem, create a new C++ ATL project that implements an inproc-server (dll) component.
The name of the project is API.
Then create a simple C# console application 'TestApp' and add the COM object as a reference.

-- This is the contents of the idl file API.idl:

import "oaidl.idl";
import "ocidl.idl";

[
object,
uuid(4DA8E86C-C8D2-443D-8940-B52C2151E37C),
dual,
nonextensible,
helpstring("ITest Interface"),
pointer_default(unique)
]
interface ITest : IDispatch {
HRESULT Test([in] BSTR message, [out,retval] VARIANT* result);
};
[
uuid(1ECB0F02-F896-473D-ADFE-44BB1602F08D),
version(1.0),
helpstring("API 1.0 Type Library")
]
library APILib
{
importlib("stdole2.tlb");

typedef [uuid(5523d721-5fe5-4a40-892e-8824b14aea0d)] struct MyStruct
{
double X;
double Y;
double Z;
} MyStruct;

[
uuid(C0A1CB57-1726-4729-874A-3C607E90F0EC),
]
coclass Test
{
[default] interface ITest;
};
}

-- This is the implementation of COM object Test (file Test.cpp)

#include "stdafx.h"
#include "Test.h"
#include ".\test.h"

void convertStructToVariant(VARIANT& var, const MyStruct& s)
{
CComPtr<IRecordInfo> pRecInfo;
HRESULT hr;
GUID structUuid;
hr = CLSIDFromString(L"{5523d721-5fe5-4a40-892e-8824b14aea0d}", &structUuid);
hr = GetRecordInfoFromGuids(LIBID_APILib, 1, 0, GetUserDefaultLCID(), structUuid, &pRecInfo);

if (pRecInfo)
{
VariantClear(&var);

var.vt = VT_RECORD;
var.pvRecord = pRecInfo->RecordCreate();
var.pRecInfo = pRecInfo.Detach();

*((MyStruct*)var.pvRecord) = s;
}
}

STDMETHODIMP CTest::Test(BSTR message, VARIANT* result)
{
USES_CONVERSION;

CComVariant var;
if (!wcsicmp(message, L"RETURN-STRING"))
{
var = CComVariant("TEST-RESULT");
}
else if (!wcsicmp(message, L"RETURN-STRUCT"))
{
MyStruct s;
s.X = 1;
s.Y = 2;
s.Z = 3;

convertStructToVariant(var, s);
}

var.Detach(result);

return S_OK;
}

-- TestApp.cs
using System;
using System.Windows.Forms;

namespace TestApp
{
class Application
{
[STAThread]
static void Main(string[] args)
{
APILib.Test test = new APILib.Test();
object result;

try
{
result = test.Test("RETURN-STRING");

MessageBox.Show(result.ToString(), "String Test");
}
catch (Exception e)
{
MessageBox.Show("Caught exception \"" + e.ToString() + "\"", "Struct Test");
}

try
{
result = test.Test("RETURN-STRUCT");

MessageBox.Show(result.ToString(), "Struct Test");
}
catch (Exception e)
{
MessageBox.Show("Caught exception \"" + e.ToString() + "\"", "Struct Test");
}
}
}
}

If I run TestApp.exe, 2 MessageBoxes appear:
The first one for the string test prints "TEST-RESULT".
The second one shows:
Caught exception "System.ArgumentException: The specified record cannot be mapped to a managed value class.
at APILib.TestClass.Test(String message)
at TestApp.Application.Main(String[] args) in c:\temp\udt\testapp\testapp.cs:line 28"

Any help would be greatly appreciated.
Thanks,
- Jürgen





Re: Returning UDT encapsulated in a Variant from a COM method leads to exception in managed code Robert Jordan
9/27/2004 5:01:12 PM
Hi Jürgen,

[quoted text, click to view]

http://support.microsoft.com/default.aspx?scid=kb;en-us;309329

bye
AddThis Social Bookmark Button