Friday, February 9, 2007

Passing Structs from COM to .NET

The easiest way of passing structs built out of primative data types from COM to .NET is to define the struct in your COM IDL file and use that struct in your COM code. Then expose a COM interface method to retrieve that struct and return it using standard COM rules. For example:

In your IDL define a struct like this:

typedef struct tagTeamInfo
{
long TeamId;
BSTR TeamName;
} TEAMINFO;
...
[id(6), helpstring("method GetTeamInfo")] HRESULT GetTeamInfo([in] LONG index, [out,retval] TEAMINFO* pTeamInfo);


Then, in your COM code, use the TEAMINFO struct as normal.

TEAMINFO ti;
ti.TeamId = gd->mObject;
ti.TeamName = StringToBSTR(gd->mName); //NOTE: See BSTR and .NET FAQ entry

In your implementation of the GetTeamInfo interface:

STDMETHODIMP CCollector::GetTeamInfo(LONG index, TEAMINFO* pTeamInfo)
{
const TEAMINFO& ti = mCurrentSession.GetTeamInfo(index);
pTeamInfo->TeamId = ti.TeamId;
pTeamInfo->TeamName = SysAllocString( ti.TeamName );
return S_OK;
}

Note that we allocate a new BSTR to place in the out TEAMINFO that was passed in. The caller is responsible for freeing that BSTR.

The cool part about all of this is that you can now pass a struct from COM to .NET and all of the memory allocations and such are taken care of for you (even the freeing of the BSTR!)

Thursday, February 8, 2007

System.IO.FileNotFoundException occurring with XmlSerializer

Recently I discovered that when loading the a C# app in the debugger and have exception trapping enabled, you will receive an exception "System.IO.FileNotFoundException" with a message similar to: "Could not load file or assembly 'mscorlib.XmlSerializers,..."

Looking around on the Microsoft bug database I found this explination: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=93647

"XmlSerializer attempts to load pre-generated serializers to avoid compilation of the serialization code on the fly. There is no easy way to check for "will assembly be found by the Assembly.Load() call", it would be duplicating Fusion path search and loader logic in XmlSerializer."

Basically, this is not really an error since the exception is caught and the assembly is then generated in order to run the XmlSerializer correctly. There is no way to avoid this exception and it will always be caught by the Exception manager in the debugger when you have CLR Exceptions set to be thrown. It is perfectly safe to just ignore this exception.