C# app with COM Interface for array of COM structs

S

Sharon

Hello Experts

I'm exporting COM interface from within my C# application (VS2005 .NET 2.0).
One of my exported function GetROI() return type is a struct defined in a
native COM object.
The method signature is (viewed by the OLE View):
[id(0x60020001)]
HRESULT GetROI(
[in] long partID,
[in] BSTR roiName,
[out, retval] SAFEARRAY(PhysicalLocation_t)* pRetVal);


In the native COM object, the struct is defined as (viewed by the OLE View):
typedef struct tagPhysicalLocation_t {
long ScanLine;
long Pixel;
long Value;
} PhysicalLocation_t;

In the interop of the native COM object, the struct is defined as:

namespace USDALib
{
public struct PhysicalLocation_t
{
public int Pixel;
public int ScanLine;
public int Value;
}
}

This struct is also shown on my C# application by using the OLE View as:

typedef [uuid(7B61D653-82C0-33E9-94AA-913FE5290BC0), version(1.0),
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, USDALib.PhysicalLocation_t)]
struct tagPhysicalLocation_t {
long ScanLine;
long Pixel;
long Value;
} PhysicalLocation_t;

But at the native unmanaged application that invoke this my COM method
GetROI() is crushing with exception when trying to assign the return value to
any kind of variable is end with exception.

It looks like it's impossible to transfer array of structs from my interface
to the native application.

Can I do that and how can do I that?
 
W

Willy Denoyette [MVP]

Sharon said:
Hello Experts

I'm exporting COM interface from within my C# application (VS2005 .NET
2.0).
One of my exported function GetROI() return type is a struct defined in a
native COM object.
The method signature is (viewed by the OLE View):
[id(0x60020001)]
HRESULT GetROI(
[in] long partID,
[in] BSTR roiName,
[out, retval] SAFEARRAY(PhysicalLocation_t)* pRetVal);


In the native COM object, the struct is defined as (viewed by the OLE
View):
typedef struct tagPhysicalLocation_t {
long ScanLine;
long Pixel;
long Value;
} PhysicalLocation_t;

In the interop of the native COM object, the struct is defined as:

namespace USDALib
{
public struct PhysicalLocation_t
{
public int Pixel;
public int ScanLine;
public int Value;
}
}

This struct is also shown on my C# application by using the OLE View as:

typedef [uuid(7B61D653-82C0-33E9-94AA-913FE5290BC0), version(1.0),
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, USDALib.PhysicalLocation_t)]
struct tagPhysicalLocation_t {
long ScanLine;
long Pixel;
long Value;
} PhysicalLocation_t;

But at the native unmanaged application that invoke this my COM method
GetROI() is crushing with exception when trying to assign the return value
to
any kind of variable is end with exception.

What do you mean with any kind of variable? The return type is an array
(SAFEARRAY) of strucures, the structures being of type PhysicalLocation_t.
This means that you have to declare a variable of type SAFEARRAY at the
client side.
It looks like it's impossible to transfer array of structs from my
interface
to the native application.

Sure it's possible, but not all kind of native COM clients can handle arrays
of user defined types (UDT's), so it's better not to expose such types to
COM.

Willy.
 
S

Sharon

My Client is VB Visual Studio 6 and I have a reference to COM Interface from
C# application.
The method signature is (viewed by the OLE View):
[id(0x60020001)]
HRESULT GetROI(
[in] long partID,
[in] BSTR roiName,
[out, retval] SAFEARRAY(PhysicalLocation_t)* pRetVal);

I'm trying to call GetROI and I'm getting exeption with "Element not found"
message.
The code in VB looks like that:

Dim PhLocationPoints() As PhysicalLocation_t
Dim Iface as TheCOClass

Set Iface = new TheCOClass
If Not Iface Is Nothing Then
PhLocationPoints = Iface.GetROI(119, "ROI 3")
end if
 
W

Willy Denoyette [MVP]

Sharon said:
My Client is VB Visual Studio 6 and I have a reference to COM Interface
from
C# application.
The method signature is (viewed by the OLE View):
[id(0x60020001)]
HRESULT GetROI(
[in] long partID,
[in] BSTR roiName,
[out, retval] SAFEARRAY(PhysicalLocation_t)* pRetVal);

I'm trying to call GetROI and I'm getting exeption with "Element not
found"
message.
The code in VB looks like that:

Dim PhLocationPoints() As PhysicalLocation_t
Dim Iface as TheCOClass

Set Iface = new TheCOClass
If Not Iface Is Nothing Then
PhLocationPoints = Iface.GetROI(119, "ROI 3")
end if


Hard to tell without seeing any C# code, are you sure you are returning a
valid array when passed (119,"ROI 3")?


Willy.
 
S

Sharon

Ok, Here is the relevant code.

The method at hand is
USDALib.PhysicalLocation_t[] GetROI(int partID, string roiName);

The USDALib is the USDALib.dll interop for the COM object USDA.dll

The VB6 code is referencing the USDA.ll (the native COM object) that defines
the PhysicalLocation_t
and also referencing the 1000 Gates


///////////////////////////////////
/// File 1000GatesInterface.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
[ComVisible(true),
Guid(GUIDs.IID_I1000Gates),
InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface I1000Gates
{
// The USDALib is the USDALib.dll interop for the COM object USDA.dll
USDALib.PhysicalLocation_t[] GetROI(int partID, string roiName);
}
}

///////////////////////////////////
/// File COMBridge.cs

using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
/// <summary>COMBridgeFor1000Gates is the bridge between the application
/// interfaces and the actual implementation of the methods.</summary>
[Guid(GUIDs.CLASS_1000Gates)]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("MultiBScan.1000Gates")]
[ComVisible(true)]
public class COMBridgeFor1000Gates : ReferenceCountedObjectBase,
I1000Gates
{
public static EvaluationForm m_evalForm;

[DllImport("msvcr70.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int _controlfp(int n, int mask);

[DllImport("kernel32.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool IsWow64Process(IntPtr hProcess, out bool
Wow64Process);

[DllImport("kernel32.dll", CharSet=CharSet.Ansi, ExactSpelling=true)]
public static extern UIntPtr GetProcAddress(IntPtr hModule, string
procName);

public COMBridgeFor1000Gates()
{
// README: according to Microsoft knowledge base!
UIntPtr pIsWow64Process = UIntPtr.Zero;
bool Is64 = false;

// Query for IsWow64Process function, if doesn't exist then not a 64bit
system.
pIsWow64Process =
GetProcAddress(System.Diagnostics.Process.GetCurrentProcess().Handle,"IsWow64Process");
if( pIsWow64Process != UIntPtr.Zero )
{
// Function exists, check it for values.
IsWow64Process(System.Diagnostics.Process.GetCurrentProcess().Handle,out
Is64);
}
// Perform if not a 64bit system.
if( !Is64 )
{ // this flag should be set in 32bit system in order to avoid
an exception in the drawing.
_controlfp(0x9001F, 0xFFFFF);
}
}

~COMBridgeFor1000Gates()
{
m_evalForm.Close();
}

#region I1000Gates Members

USDALib.PhysicalLocation_t[] I1000Gates.GetROI(int partID, string
roiName)
{
return new USDALib.PhysicalLocation_t[0];

USDALib.PhysicalLocation_t[] jp = new
USDALib.PhysicalLocation_t[10];
for( int i=0; i < 10; ++i )
{
jp.Pixel = i;
jp.ScanLine = i;
jp.Value = i;
}
return jp;
}

#endregion I1000Gates Members
}

#region Factory Class for COM object

class BridgeClassFactoryFor1000Gates : ClassFactoryBase
{
public override void virtual_CreateInstance(IntPtr pUnkOuter, ref Guid
riid, out IntPtr ppvObject)
{
if( riid == Marshal.GenerateGuidForType(typeof(I1000Gates)) ||
riid == Program.IID_IDispatch ||
riid == Program.IID_IUnknown )
{
COMBridgeFor1000Gates COMBridge_New = new COMBridgeFor1000Gates();

ppvObject = Marshal.GetComInterfaceForObject(COMBridge_New,
typeof(I1000Gates));
EvaluationConfiguration.ExecutionMode =
EvaluationConfiguration.RunMode.ActiveX;
}
else
{
throw new COMException("No interface", unchecked((int) 0x80004002));
}
}
}

#endregion Factory Class for COM object
}

//////////////////////////////////////////
//// File IClassFactory.cs

using System;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
///<summary>
/// Interface IClassFactory is here to provide a C#
/// definition of the COM IClassFactory interface.
///</summary>
[ComImport, // This interface originated from COM.
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),// Indicate that this
interface is not IDispatch-based.
Guid("00000001-0000-0000-C000-000000000046")]// This GUID is the actual
GUID of IClassFactory.
public interface IClassFactory
{
/// <summary>CreateInstance.</summary>
/// <param name="pUnkOuter">Unknown outer.</param>
/// <param name="riid">RI ID.</param>
/// <param name="ppvObject">PPV Object.</param>
void CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject);

/// <param name="fLock">Lock flag.</param>
void LockServer(bool fLock);
}
}

//////////////////////////////////////////
//// File GUIDs.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
public class GUIDs
{
internal const string CLASS_1000Gates =
"1B4363BF-33DF-49c7-B0D0-A201E631C100";
internal const string IID_I1000Gates =
"BE8E6044-5B18-4d56-AA75-9E5120F27884";
}
}

//////////////////////////////////////////////////////
 
S

Sharon

Ok, Here is the relevant code.

The method at hand is
USDALib.PhysicalLocation_t[] GetROI(int partID, string roiName);

The USDALib is the USDALib.dll interop for the COM object USDA.dll

The VB6 code is referencing the USDA.ll (the native COM object) that defines
the PhysicalLocation_t
and also referencing the 1000 Gates


///////////////////////////////////
/// File 1000GatesInterface.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
[ComVisible(true),
Guid(GUIDs.IID_I1000Gates),
InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface I1000Gates
{
// The USDALib is the USDALib.dll interop for the COM object USDA.dll
USDALib.PhysicalLocation_t[] GetROI(int partID, string roiName);
}
}

///////////////////////////////////
/// File COMBridge.cs

using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
/// <summary>COMBridgeFor1000Gates is the bridge between the application
/// interfaces and the actual implementation of the methods.</summary>
[Guid(GUIDs.CLASS_1000Gates)]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("MultiBScan.1000Gates")]
[ComVisible(true)]
public class COMBridgeFor1000Gates : ReferenceCountedObjectBase,
I1000Gates
{
public static EvaluationForm m_evalForm;

[DllImport("msvcr70.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int _controlfp(int n, int mask);

[DllImport("kernel32.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool IsWow64Process(IntPtr hProcess, out bool
Wow64Process);

[DllImport("kernel32.dll", CharSet=CharSet.Ansi, ExactSpelling=true)]
public static extern UIntPtr GetProcAddress(IntPtr hModule, string
procName);

public COMBridgeFor1000Gates()
{
// README: according to Microsoft knowledge base!
UIntPtr pIsWow64Process = UIntPtr.Zero;
bool Is64 = false;

// Query for IsWow64Process function, if doesn't exist then not a 64bit
system.
pIsWow64Process =
GetProcAddress(System.Diagnostics.Process.GetCurrentProcess().Handle,"IsWow64Process");
if( pIsWow64Process != UIntPtr.Zero )
{
// Function exists, check it for values.
IsWow64Process(System.Diagnostics.Process.GetCurrentProcess().Handle,out
Is64);
}
// Perform if not a 64bit system.
if( !Is64 )
{ // this flag should be set in 32bit system in order to avoid
an exception in the drawing.
_controlfp(0x9001F, 0xFFFFF);
}
}

~COMBridgeFor1000Gates()
{
m_evalForm.Close();
}

#region I1000Gates Members

USDALib.PhysicalLocation_t[] I1000Gates.GetROI(int partID, string
roiName)
{
return new USDALib.PhysicalLocation_t[0];

USDALib.PhysicalLocation_t[] jp = new
USDALib.PhysicalLocation_t[10];
for( int i=0; i < 10; ++i )
{
jp.Pixel = i;
jp.ScanLine = i;
jp.Value = i;
}
return jp;
}

#endregion I1000Gates Members
}

#region Factory Class for COM object

class BridgeClassFactoryFor1000Gates : ClassFactoryBase
{
public override void virtual_CreateInstance(IntPtr pUnkOuter, ref Guid
riid, out IntPtr ppvObject)
{
if( riid == Marshal.GenerateGuidForType(typeof(I1000Gates)) ||
riid == Program.IID_IDispatch ||
riid == Program.IID_IUnknown )
{
COMBridgeFor1000Gates COMBridge_New = new COMBridgeFor1000Gates();

ppvObject = Marshal.GetComInterfaceForObject(COMBridge_New,
typeof(I1000Gates));
EvaluationConfiguration.ExecutionMode =
EvaluationConfiguration.RunMode.ActiveX;
}
else
{
throw new COMException("No interface", unchecked((int) 0x80004002));
}
}
}

#endregion Factory Class for COM object
}

//////////////////////////////////////////
//// File IClassFactory.cs

using System;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
///<summary>
/// Interface IClassFactory is here to provide a C#
/// definition of the COM IClassFactory interface.
///</summary>
[ComImport, // This interface originated from COM.
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),// Indicate that this
interface is not IDispatch-based.
Guid("00000001-0000-0000-C000-000000000046")]// This GUID is the actual
GUID of IClassFactory.
public interface IClassFactory
{
/// <summary>CreateInstance.</summary>
/// <param name="pUnkOuter">Unknown outer.</param>
/// <param name="riid">RI ID.</param>
/// <param name="ppvObject">PPV Object.</param>
void CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject);

/// <param name="fLock">Lock flag.</param>
void LockServer(bool fLock);
}
}

//////////////////////////////////////////
//// File GUIDs.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
public class GUIDs
{
internal const string CLASS_1000Gates =
"1B4363BF-33DF-49c7-B0D0-A201E631C100";
internal const string IID_I1000Gates =
"BE8E6044-5B18-4d56-AA75-9E5120F27884";
}
}

//////////////////////////////////////////////////////

--
Thanks
Sharon
--
Thanks
Sharon


Willy Denoyette said:
Sharon said:
My Client is VB Visual Studio 6 and I have a reference to COM Interface
from
C# application.
The method signature is (viewed by the OLE View):
[id(0x60020001)]
HRESULT GetROI(
[in] long partID,
[in] BSTR roiName,
[out, retval] SAFEARRAY(PhysicalLocation_t)* pRetVal);

I'm trying to call GetROI and I'm getting exeption with "Element not
found"
message.
The code in VB looks like that:

Dim PhLocationPoints() As PhysicalLocation_t
Dim Iface as TheCOClass

Set Iface = new TheCOClass
If Not Iface Is Nothing Then
PhLocationPoints = Iface.GetROI(119, "ROI 3")
end if


Hard to tell without seeing any C# code, are you sure you are returning a
valid array when passed (119,"ROI 3")?


Willy.
 
W

Willy Denoyette [MVP]

Are you sure this is the real code?
This should give you a compiler warning "Unreachable code..."
....
USDALib.PhysicalLocation_t[] I1000Gates.GetROI(int partID, string
roiName)
{
return new USDALib.PhysicalLocation_t[0]; <----- return
here??????
USDALib.PhysicalLocation_t[] jp = new
USDALib.PhysicalLocation_t[10];

...

and throw an "index out of bounds" runtime error when accessing the array
elements.

Willy.

Sharon said:
Ok, Here is the relevant code.

The method at hand is
USDALib.PhysicalLocation_t[] GetROI(int partID, string roiName);

The USDALib is the USDALib.dll interop for the COM object USDA.dll

The VB6 code is referencing the USDA.ll (the native COM object) that
defines
the PhysicalLocation_t
and also referencing the 1000 Gates


///////////////////////////////////
/// File 1000GatesInterface.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
[ComVisible(true),
Guid(GUIDs.IID_I1000Gates),
InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface I1000Gates
{
// The USDALib is the USDALib.dll interop for the COM object USDA.dll
USDALib.PhysicalLocation_t[] GetROI(int partID, string roiName);
}
}

///////////////////////////////////
/// File COMBridge.cs

using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
/// <summary>COMBridgeFor1000Gates is the bridge between the
application
/// interfaces and the actual implementation of the methods.</summary>
[Guid(GUIDs.CLASS_1000Gates)]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("MultiBScan.1000Gates")]
[ComVisible(true)]
public class COMBridgeFor1000Gates : ReferenceCountedObjectBase,
I1000Gates
{
public static EvaluationForm m_evalForm;

[DllImport("msvcr70.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int _controlfp(int n, int mask);

[DllImport("kernel32.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool IsWow64Process(IntPtr hProcess, out bool
Wow64Process);

[DllImport("kernel32.dll", CharSet=CharSet.Ansi, ExactSpelling=true)]
public static extern UIntPtr GetProcAddress(IntPtr hModule, string
procName);

public COMBridgeFor1000Gates()
{
// README: according to Microsoft knowledge base!
UIntPtr pIsWow64Process = UIntPtr.Zero;
bool Is64 = false;

// Query for IsWow64Process function, if doesn't exist then not a 64bit
system.
pIsWow64Process =
GetProcAddress(System.Diagnostics.Process.GetCurrentProcess().Handle,"IsWow64Process");
if( pIsWow64Process != UIntPtr.Zero )
{
// Function exists, check it for values.

IsWow64Process(System.Diagnostics.Process.GetCurrentProcess().Handle,out
Is64);
}
// Perform if not a 64bit system.
if( !Is64 )
{ // this flag should be set in 32bit system in order to
avoid
an exception in the drawing.
_controlfp(0x9001F, 0xFFFFF);
}
}

~COMBridgeFor1000Gates()
{
m_evalForm.Close();
}

#region I1000Gates Members

USDALib.PhysicalLocation_t[] I1000Gates.GetROI(int partID, string
roiName)
{
return new USDALib.PhysicalLocation_t[0];

USDALib.PhysicalLocation_t[] jp = new
USDALib.PhysicalLocation_t[10];
for( int i=0; i < 10; ++i )
{
jp.Pixel = i;
jp.ScanLine = i;
jp.Value = i;
}
return jp;
}

#endregion I1000Gates Members
}

#region Factory Class for COM object

class BridgeClassFactoryFor1000Gates : ClassFactoryBase
{
public override void virtual_CreateInstance(IntPtr pUnkOuter, ref Guid
riid, out IntPtr ppvObject)
{
if( riid == Marshal.GenerateGuidForType(typeof(I1000Gates)) ||
riid == Program.IID_IDispatch ||
riid == Program.IID_IUnknown )
{
COMBridgeFor1000Gates COMBridge_New = new COMBridgeFor1000Gates();

ppvObject = Marshal.GetComInterfaceForObject(COMBridge_New,
typeof(I1000Gates));
EvaluationConfiguration.ExecutionMode =
EvaluationConfiguration.RunMode.ActiveX;
}
else
{
throw new COMException("No interface", unchecked((int) 0x80004002));
}
}
}

#endregion Factory Class for COM object
}

//////////////////////////////////////////
//// File IClassFactory.cs

using System;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
///<summary>
/// Interface IClassFactory is here to provide a C#
/// definition of the COM IClassFactory interface.
///</summary>
[ComImport, // This interface originated from COM.
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),// Indicate that this
interface is not IDispatch-based.
Guid("00000001-0000-0000-C000-000000000046")]// This GUID is the
actual
GUID of IClassFactory.
public interface IClassFactory
{
/// <summary>CreateInstance.</summary>
/// <param name="pUnkOuter">Unknown outer.</param>
/// <param name="riid">RI ID.</param>
/// <param name="ppvObject">PPV Object.</param>
void CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr
ppvObject);

/// <param name="fLock">Lock flag.</param>
void LockServer(bool fLock);
}
}

//////////////////////////////////////////
//// File GUIDs.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
public class GUIDs
{
internal const string CLASS_1000Gates =
"1B4363BF-33DF-49c7-B0D0-A201E631C100";
internal const string IID_I1000Gates =
"BE8E6044-5B18-4d56-AA75-9E5120F27884";
}
}

//////////////////////////////////////////////////////

--
Thanks
Sharon
--
Thanks
Sharon


Willy Denoyette said:
Sharon said:
My Client is VB Visual Studio 6 and I have a reference to COM Interface
from
C# application.
The method signature is (viewed by the OLE View):
[id(0x60020001)]
HRESULT GetROI(
[in] long partID,
[in] BSTR roiName,
[out, retval] SAFEARRAY(PhysicalLocation_t)* pRetVal);


I'm trying to call GetROI and I'm getting exeption with "Element not
found"
message.
The code in VB looks like that:

Dim PhLocationPoints() As PhysicalLocation_t
Dim Iface as TheCOClass

Set Iface = new TheCOClass
If Not Iface Is Nothing Then
PhLocationPoints = Iface.GetROI(119, "ROI 3")
end if


Hard to tell without seeing any C# code, are you sure you are returning a
valid array when passed (119,"ROI 3")?


Willy.
 
S

Sharon

Oopppss, sorry, I didn't clean the original code enought.
Here is is again fixed.

The method at hand is
USDALib.PhysicalLocation_t[] GetROI(int partID, string roiName);

The USDALib is the USDALib.dll interop for the COM object USDA.dll

The VB6 code is referencing the USDA.ll (the native COM object) that defines
the PhysicalLocation_t
and also referencing the 1000 Gates


///////////////////////////////////
/// File 1000GatesInterface.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
[ComVisible(true),
Guid(GUIDs.IID_I1000Gates),
InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface I1000Gates
{
// The USDALib is the USDALib.dll interop for the native (unmanaged)
COM object USDA.dll
USDALib.PhysicalLocation_t[] GetROI(int partID, string roiName);
}
}

///////////////////////////////////
/// File COMBridge.cs

using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
/// <summary>COMBridgeFor1000Gates is the bridge between the application
/// interfaces and the actual implementation of the methods.</summary>
[Guid(GUIDs.CLASS_1000Gates)]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("MultiBScan.1000Gates")]
[ComVisible(true)]
public class COMBridgeFor1000Gates : ReferenceCountedObjectBase,
I1000Gates
{
[DllImport("msvcr70.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int _controlfp(int n, int mask);

[DllImport("kernel32.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool IsWow64Process(IntPtr hProcess, out bool
Wow64Process);

[DllImport("kernel32.dll", CharSet=CharSet.Ansi, ExactSpelling=true)]
public static extern UIntPtr GetProcAddress(IntPtr hModule, string
procName);

public COMBridgeFor1000Gates()
{
// README: according to Microsoft knowledge base!
UIntPtr pIsWow64Process = UIntPtr.Zero;
bool Is64 = false;

// Query for IsWow64Process function, if doesn't exist then not a 64bit
system.
pIsWow64Process =
GetProcAddress(System.Diagnostics.Process.GetCurrentProcess().Handle,"IsWow64Process");
if( pIsWow64Process != UIntPtr.Zero )
{
// Function exists, check it for values.
IsWow64Process(System.Diagnostics.Process.GetCurrentProcess().Handle,out
Is64);
}
// Perform if not a 64bit system.
if( !Is64 )
{ // this flag should be set in 32bit system in order to avoid
an exception in the drawing.
_controlfp(0x9001F, 0xFFFFF);
}
}

~COMBridgeFor1000Gates() {}

#region I1000Gates Members

USDALib.PhysicalLocation_t[] I1000Gates.GetROI(int partID, string
roiName)
{
USDALib.PhysicalLocation_t[] jp = new
USDALib.PhysicalLocation_t[10];
for( int i=0; i < 10; ++i )
{
jp.Pixel = i;
jp.ScanLine = i;
jp.Value = i;
}
return jp;
}

#endregion I1000Gates Members
}

#region Factory Class for COM object

class BridgeClassFactoryFor1000Gates : ClassFactoryBase
{
public override void virtual_CreateInstance(IntPtr pUnkOuter, ref Guid
riid, out IntPtr ppvObject)
{
if( riid == Marshal.GenerateGuidForType(typeof(I1000Gates)) ||
riid == Program.IID_IDispatch ||
riid == Program.IID_IUnknown )
{
COMBridgeFor1000Gates COMBridge_New = new COMBridgeFor1000Gates();

ppvObject = Marshal.GetComInterfaceForObject(COMBridge_New,
typeof(I1000Gates));
EvaluationConfiguration.ExecutionMode =
EvaluationConfiguration.RunMode.ActiveX;
}
else
{
throw new COMException("No interface", unchecked((int) 0x80004002));
}
}
}

#endregion Factory Class for COM object
}

//////////////////////////////////////////
//// File IClassFactory.cs

using System;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
///<summary>
/// Interface IClassFactory is here to provide a C#
/// definition of the COM IClassFactory interface.
///</summary>
[ComImport, // This interface originated from COM.
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),// Indicate that this
interface is not IDispatch-based.
Guid("00000001-0000-0000-C000-000000000046")]// This GUID is the actual
GUID of IClassFactory.
public interface IClassFactory
{
/// <summary>CreateInstance.</summary>
/// <param name="pUnkOuter">Unknown outer.</param>
/// <param name="riid">RI ID.</param>
/// <param name="ppvObject">PPV Object.</param>
void CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject);

/// <param name="fLock">Lock flag.</param>
void LockServer(bool fLock);
}
}

//////////////////////////////////////////
//// File GUIDs.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
public class GUIDs
{
internal const string CLASS_1000Gates =
"1B4363BF-33DF-49c7-B0D0-A201E631C100";
internal const string IID_I1000Gates =
"BE8E6044-5B18-4d56-AA75-9E5120F27884";
}
}

//////////////////////////////////////////////////////

Why the BV6 client is getting an exception?
If I define a struct of my own in the C# application exposoed to COM, then
it works perfectly.
But I can not do that beacuse of design architecture issue.

Any idea?
 
W

Willy Denoyette [MVP]

Sharon said:
Oopppss, sorry, I didn't clean the original code enought.
Here is is again fixed.

The method at hand is
USDALib.PhysicalLocation_t[] GetROI(int partID, string roiName);

The USDALib is the USDALib.dll interop for the COM object USDA.dll

The VB6 code is referencing the USDA.ll (the native COM object) that
defines
the PhysicalLocation_t
and also referencing the 1000 Gates


///////////////////////////////////
/// File 1000GatesInterface.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
[ComVisible(true),
Guid(GUIDs.IID_I1000Gates),
InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface I1000Gates
{
// The USDALib is the USDALib.dll interop for the native (unmanaged)
COM object USDA.dll
USDALib.PhysicalLocation_t[] GetROI(int partID, string roiName);
}
}

///////////////////////////////////
/// File COMBridge.cs

using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
/// <summary>COMBridgeFor1000Gates is the bridge between the
application
/// interfaces and the actual implementation of the methods.</summary>
[Guid(GUIDs.CLASS_1000Gates)]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("MultiBScan.1000Gates")]
[ComVisible(true)]
public class COMBridgeFor1000Gates : ReferenceCountedObjectBase,
I1000Gates
{
[DllImport("msvcr70.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int _controlfp(int n, int mask);

[DllImport("kernel32.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool IsWow64Process(IntPtr hProcess, out bool
Wow64Process);

[DllImport("kernel32.dll", CharSet=CharSet.Ansi, ExactSpelling=true)]
public static extern UIntPtr GetProcAddress(IntPtr hModule, string
procName);

public COMBridgeFor1000Gates()
{
// README: according to Microsoft knowledge base!
UIntPtr pIsWow64Process = UIntPtr.Zero;
bool Is64 = false;

// Query for IsWow64Process function, if doesn't exist then not a 64bit
system.
pIsWow64Process =
GetProcAddress(System.Diagnostics.Process.GetCurrentProcess().Handle,"IsWow64Process");
if( pIsWow64Process != UIntPtr.Zero )
{
// Function exists, check it for values.

IsWow64Process(System.Diagnostics.Process.GetCurrentProcess().Handle,out
Is64);
}
// Perform if not a 64bit system.
if( !Is64 )
{ // this flag should be set in 32bit system in order to
avoid
an exception in the drawing.
_controlfp(0x9001F, 0xFFFFF);
}
}

~COMBridgeFor1000Gates() {}

#region I1000Gates Members

USDALib.PhysicalLocation_t[] I1000Gates.GetROI(int partID, string
roiName)
{
USDALib.PhysicalLocation_t[] jp = new
USDALib.PhysicalLocation_t[10];
for( int i=0; i < 10; ++i )
{
jp.Pixel = i;
jp.ScanLine = i;
jp.Value = i;
}
return jp;
}

#endregion I1000Gates Members
}

#region Factory Class for COM object

class BridgeClassFactoryFor1000Gates : ClassFactoryBase
{
public override void virtual_CreateInstance(IntPtr pUnkOuter, ref Guid
riid, out IntPtr ppvObject)
{
if( riid == Marshal.GenerateGuidForType(typeof(I1000Gates)) ||
riid == Program.IID_IDispatch ||
riid == Program.IID_IUnknown )
{
COMBridgeFor1000Gates COMBridge_New = new COMBridgeFor1000Gates();

ppvObject = Marshal.GetComInterfaceForObject(COMBridge_New,
typeof(I1000Gates));
EvaluationConfiguration.ExecutionMode =
EvaluationConfiguration.RunMode.ActiveX;
}
else
{
throw new COMException("No interface", unchecked((int) 0x80004002));
}
}
}

#endregion Factory Class for COM object
}

//////////////////////////////////////////
//// File IClassFactory.cs

using System;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
///<summary>
/// Interface IClassFactory is here to provide a C#
/// definition of the COM IClassFactory interface.
///</summary>
[ComImport, // This interface originated from COM.
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),// Indicate that this
interface is not IDispatch-based.
Guid("00000001-0000-0000-C000-000000000046")]// This GUID is the
actual
GUID of IClassFactory.
public interface IClassFactory
{
/// <summary>CreateInstance.</summary>
/// <param name="pUnkOuter">Unknown outer.</param>
/// <param name="riid">RI ID.</param>
/// <param name="ppvObject">PPV Object.</param>
void CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr
ppvObject);

/// <param name="fLock">Lock flag.</param>
void LockServer(bool fLock);
}
}

//////////////////////////////////////////
//// File GUIDs.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace MultiBScanDisplay
{
public class GUIDs
{
internal const string CLASS_1000Gates =
"1B4363BF-33DF-49c7-B0D0-A201E631C100";
internal const string IID_I1000Gates =
"BE8E6044-5B18-4d56-AA75-9E5120F27884";
}
}

//////////////////////////////////////////////////////

Why the BV6 client is getting an exception?
If I define a struct of my own in the C# application exposoed to COM, then
it works perfectly.
But I can not do that beacuse of design architecture issue.

Any idea?



This should work, my guess is that your C# code throws an exception.
In order to isolate the issue, you should build a minimal repro sample,
something like this will do....

1) a VB6 AX class project "vbudt"

Type MyStruct
i1 As Long
i2 As Long
End Type

Compile above and use tlbimp to create an interop assembly.
tlbimp vbudt.dll /out:vbudt.dll

2) A C# library
// File: minimal.cs
// Compile and register ....
// csc /r:vbudt.dll /t:library minimal.cs
// regasm /tlb /codebase minimal.dll

using System;
using System.Runtime.InteropServices;
using vbudt; // import vbudt metadata

namespace ComIntSample1
{
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("ea361991-f123-11dc-95a4-001d9233a61f")]
public interface IMyClass
{
MyStruct[] UDTArray { get; }
}

[ComDefaultInterface(typeof(IMyClass))]
[ClassInterface(ClassInterfaceType.AutoDual)]
[Guid("ea361992-f123-11dc-95a4-001d9233a61f")]
public class MyClass : IMyClass
{
public MyStruct[] UDTArray
{
get
{
MyStruct[] myArr = new MyStruct[2];
myArr[0].i1 = 1;
myArr[0].i2 = 2;
myArr[1].i1 = 3;
myArr[1].i2 = 4;
return myArr;
}
}
}
}


3) A VB6 client with references to 1 and 2

....
Dim obj As New MyClass
Dim ar() As MyStruct
ar = obj.UDTArray
For n = LBound(ar) To UBound(ar)
Debug.Print (ar(n).i1)
Debug.Print (ar(n).i2)
Next n

Willy.
 
S

Sharon

Thanks Willy,
Your sample is working nicely.

After registering your .NET tlb – In the OLE View under Structs is empty.

But in my application the OLE View shows the struct I’m returning with my
function. This struct is defined in the COM object DLL (native/Unmanaged).

This is the only difference I have notices between your sample and my
application.

I have tried to exclude this struct when importing the .NET interface to the
VB client - still it does not work.

In any case; the VB client is getting the exception “Element not foundâ€.

I have encircled the C# function in try-catch to see whether any exception
is thrown – but none was caught.

What can be the problem?
 
S

Sharon

One more difference I have noticed between your sample and my application:

In your so simple sample, the executable (yes, I made is exe) path is
registered while in my executable is not, and I should register is manually.

How come?
 
W

Willy Denoyette [MVP]

Sharon said:
Thanks Willy,
Your sample is working nicely.

After registering your .NET tlb – In the OLE View under Structs is empty.
The .NET tlb does not contain a definition of the structure as this one is
defined in the native COM DLL, so, the .NET typelib should not contain a
definition either.
The .NET library imports the typelib from the native COM dll (see the
importlib directives in oleview output), and this is how COM gets at the
structure definition.

But in my application the OLE View shows the struct I’m returning with my
function. This struct is defined in the COM object DLL (native/Unmanaged).

Not sure what you are talking about, "my" .NET tlb does contain this:

[id(0x60020004), propget]
HRESULT UDTArray([out, retval] SAFEARRAY(MyStruct)* pRetVal);

note that I'm using a property that returns a structure array. The MyStruct
being defined in the COM dll and imported via the "importlib" directive.
 
W

Willy Denoyette [MVP]

Sharon said:
One more difference I have noticed between your sample and my application:

In your so simple sample, the executable (yes, I made is exe) path is
registered while in my executable is not, and I should register is
manually.

How come?

I'm not entirely clear on what you mean by this, but I guess you are talking
about the path of the .NET assembly registered for COM interop, you need to
register the assembly with the "/codebase" option, this is not done when
registering for COM interop from VS.
If you don't register using regasm /codebase, you'll have to sign and
register your assembly in the GAC.

Willy.
 
S

Sharon

Thanks again Willy,
I'm not entirely clear on what you mean by this, but I guess you are talking
about the path of the .NET assembly registered for COM interop, you need to
register the assembly with the "/codebase" option, this is not done when
registering for COM interop from VS.
If you don't register using regasm /codebase, you'll have to sign and
register your assembly in the GAC.

Your guess is correct. and after trying to register it with /codebase the
executable does get register as well.
(Because of the codebase usage warning I didn't use it earlier).

The .NET tlb does not contain a definition of the structure as this one is
defined in the native COM DLL, so, the .NET typelib should not contain a
definition either.
The .NET library imports the typelib from the native COM dll (see the
importlib directives in oleview output), and this is how COM gets at the
structure definition.

I agree that my tlb should not contain a definition of the structure. But
the OLE View shows like it does.
Yet, in your sample the structure does not shown on the OLE View for the tlb.
Why? How?
Not sure what you are talking about, "my" .NET tlb does contain this:

I mean that for my C# application that produce the tlb by the regasm, the
OLE View shows the struct (PhysicalLocation_t) returned by the COM viewable
function. But this struct (PhysicalLocation_t) is defined in the COM object
DLL (native/Unmanaged).
I'm guessing that it (PhysicalLocation_t) should not be seen using the OLE
View like it's defined in the tlb.
It's shown for my TLB using the OLE View under the Structs folder like that:

typedef [uuid(B6EBEAA1-31B1-3EFF-A395-2871DC2BC11F), version(1.0),
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, USDALib.PhysicalLocation_t)
]
struct tagPhysicalLocation_t {

long ScanLine;

long Pixel;

long Value;
} PhysicalLocation_t;

When the USDALib is the interop for the USDA.dll native COM object that
contains the PhysicalLocation_t defenition

And the method for my tlb looks like that:

[id(0x60020001)]
SAFEARRAY(PhysicalLocation_t) GetROI(
[in] long partID,
[in] BSTR roiName);

note that I'm using a property that returns a structure array. The MyStruct
being defined in the COM dll and imported via the "importlib" directive.

I'm not sure what do you mean.
I have added the COM object DLL as a reference COM DLL, and the VS as
generated an interop for it which I'm using in my project.
How can I do that otherwise like you are referring by "importlib" directive?
 
W

Willy Denoyette [MVP]

Sharon said:
Thanks again Willy,



Your guess is correct. and after trying to register it with /codebase the
executable does get register as well.
(Because of the codebase usage warning I didn't use it earlier).



I agree that my tlb should not contain a definition of the structure. But
the OLE View shows like it does.

It should not. This structure is defined in the native code DLL.
Yet, in your sample the structure does not shown on the OLE View for the
tlb.
Why? How?

Because the structure is not defined in the C# code.
Not sure what you are talking about, "my" .NET tlb does contain this:

I mean that for my C# application that produce the tlb by the regasm, the
OLE View shows the struct (PhysicalLocation_t) returned by the COM
viewable
function. But this struct (PhysicalLocation_t) is defined in the COM
object
DLL (native/Unmanaged).
I'm guessing that it (PhysicalLocation_t) should not be seen using the OLE
View like it's defined in the tlb.
It's shown for my TLB using the OLE View under the Structs folder like
that:

typedef [uuid(B6EBEAA1-31B1-3EFF-A395-2871DC2BC11F), version(1.0),
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, USDALib.PhysicalLocation_t)
]
struct tagPhysicalLocation_t {

long ScanLine;

long Pixel;

long Value;
} PhysicalLocation_t;

When the USDALib is the interop for the USDA.dll native COM object that
contains the PhysicalLocation_t defenition

And the method for my tlb looks like that:

[id(0x60020001)]
SAFEARRAY(PhysicalLocation_t) GetROI(
[in] long partID,
[in] BSTR roiName);

note that I'm using a property that returns a structure array. The
MyStruct
being defined in the COM dll and imported via the "importlib" directive.

I'm not sure what do you mean.
I have added the COM object DLL as a reference COM DLL, and the VS as
generated an interop for it which I'm using in my project.
How can I do that otherwise like you are referring by "importlib"
directive?

When you set a reference to your native COM DLL in your C# project, then the
typelib generated by regasm should contain a reference to this DLL's typelib
in the form of a "importlib" directive.

Suppose you have a C# module named "csharp.dll" and a native COM dll named
"myCOM.dll", then you should find the following in the tlb produced by
"regasm /tlb /codebase csharp.dll"

library csharp
{
// TLib : // TLib : : {GUID of imported typelib}
importlib("myCOM.dll");
// other imports here after...

....

importlib is the directive that instructs COM to include typelib info from
"myCOM" in the current typelib.
Note that I'm building the sample from the command line, it's possible that
VS embeds the referenced typelib in the current typelib when registering the
managed assembly for COM interop.
Anyways, this is not the source of your problem.

Willy.
 
S

Sharon

I have found something I can not explain.

I took your sample that works, and added a reference to the COM dll named
USDA.dll which is the COM object I'm using in my real project.
Then I added to methods to the C# code to be exposed to COM, so now it looks
like that:


using System;
using System.Runtime.InteropServices;
using MyTest; // import vbudt metadata
using USDALib;

namespace ComIntSample1
{
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("ea361991-f123-11dc-95a4-001d9233a61f")]
[ComVisible(true)]
public interface INetClass
{
MyType_t[] UDTArray { get; }

PhysicalLocation_t SinglePhysicalLocation { get; }

PhysicalLocation_t[] PhysicalLocationArray { get; }
}

[ComDefaultInterface(typeof(INetClass))]
[ClassInterface(ClassInterfaceType.AutoDual)]
[Guid("ea361992-f123-11dc-95a4-001d9233a61f")]
[ComVisible(true)]
public class NetClass : INetClass
{
public MyType_t[] UDTArray
{
get
{
MyType_t[] myArr = new MyType_t[2];
myArr[0].Param1 = 1;
myArr[0].Param2 = 2;
myArr[0].Param3 = 3;
myArr[1].Param1 = 4;
myArr[1].Param2 = 5;
myArr[1].Param3 = 6;
return myArr;
}
}

public PhysicalLocation_t SinglePhysicalLocation
{
get
{
PhysicalLocation_t myArr;
myArr.ScanLine = 1;
myArr.Pixel = 2;
myArr.Value = 3;
return myArr;
}
}

public PhysicalLocation_t[] PhysicalLocationArray
{
get
{
PhysicalLocation_t[] myArr = new PhysicalLocation_t[2];
myArr[0].ScanLine = 1;
myArr[0].Pixel = 2;
myArr[0].Value = 3;
myArr[1].ScanLine = 4;
myArr[1].Pixel = 5;
myArr[1].Value = 6;
return myArr;
}
}
}
}

And now the PhysicalLocation_t struct which is defined in the USDA.dll (the
native COM dll), is shown on the OLE View as if it is defined in the tlb
generated from my C# code.
Why???

And in the VB6 client I have added some code, so now it looks like that:

Private Sub Command1_Click()

Dim theClass As netClass
Dim theStruct() As MyType_t

Set theClass = New netClass
theStruct = theClass.UDTArray ' OK!

End Sub

Private Sub Command2_Click()

Dim pl As PhysicalLocation_t
Dim plArr() As PhysicalLocation_t
Dim netClass As INetClass

Set netClass = New netClass
pl = netClass.SinglePhysicalLocation ' FAIL !!!

plArr = netClass.PhysicalLocationArray ' FAIL !!!

End Sub


The call to netClass.SinglePhysicalLocation and to
netClass.PhysicalLocationArray fail with error:
"Run-time error '-2147319765 (8002802b)
Method 'SinglePhysicalLocation/PhysicalLocationArray' of object 'INetClass'
failed."

It looks like the problem lies in the USDA.dll native com object or at its
interop.
What can be the problem?
 
W

Willy Denoyette [MVP]

Sharon said:
I have found something I can not explain.

I took your sample that works, and added a reference to the COM dll named
USDA.dll which is the COM object I'm using in my real project.
Then I added to methods to the C# code to be exposed to COM, so now it
looks
like that:


using System;
using System.Runtime.InteropServices;
using MyTest; // import vbudt metadata
using USDALib;

namespace ComIntSample1
{
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("ea361991-f123-11dc-95a4-001d9233a61f")]
[ComVisible(true)]
public interface INetClass
{
MyType_t[] UDTArray { get; }

PhysicalLocation_t SinglePhysicalLocation { get; }

PhysicalLocation_t[] PhysicalLocationArray { get; }
}

[ComDefaultInterface(typeof(INetClass))]
[ClassInterface(ClassInterfaceType.AutoDual)]
[Guid("ea361992-f123-11dc-95a4-001d9233a61f")]
[ComVisible(true)]
public class NetClass : INetClass
{
public MyType_t[] UDTArray
{
get
{
MyType_t[] myArr = new MyType_t[2];
myArr[0].Param1 = 1;
myArr[0].Param2 = 2;
myArr[0].Param3 = 3;
myArr[1].Param1 = 4;
myArr[1].Param2 = 5;
myArr[1].Param3 = 6;
return myArr;
}
}

public PhysicalLocation_t SinglePhysicalLocation
{
get
{
PhysicalLocation_t myArr;
myArr.ScanLine = 1;
myArr.Pixel = 2;
myArr.Value = 3;
return myArr;
}
}

public PhysicalLocation_t[] PhysicalLocationArray
{
get
{
PhysicalLocation_t[] myArr = new PhysicalLocation_t[2];
myArr[0].ScanLine = 1;
myArr[0].Pixel = 2;
myArr[0].Value = 3;
myArr[1].ScanLine = 4;
myArr[1].Pixel = 5;
myArr[1].Value = 6;
return myArr;
}
}
}
}

And now the PhysicalLocation_t struct which is defined in the USDA.dll
(the
native COM dll), is shown on the OLE View as if it is defined in the tlb
generated from my C# code.
Why???

And in the VB6 client I have added some code, so now it looks like that:

Private Sub Command1_Click()

Dim theClass As netClass
Dim theStruct() As MyType_t

Set theClass = New netClass
theStruct = theClass.UDTArray ' OK!

End Sub

Private Sub Command2_Click()

Dim pl As PhysicalLocation_t
Dim plArr() As PhysicalLocation_t
Dim netClass As INetClass

Set netClass = New netClass
pl = netClass.SinglePhysicalLocation ' FAIL !!!

plArr = netClass.PhysicalLocationArray ' FAIL !!!

End Sub


The call to netClass.SinglePhysicalLocation and to
netClass.PhysicalLocationArray fail with error:
"Run-time error '-2147319765 (8002802b)
Method 'SinglePhysicalLocation/PhysicalLocationArray' of object
'INetClass'
failed."

It looks like the problem lies in the USDA.dll native com object or at its
interop.
What can be the problem?



I don't get it, your typelib should *not* contain the definition of the
structure defined in another typelib.
What importlib's do you see in your C# module's typelib?

I mean stuff like this:
....
importlib("stdole2.tlb");

Also, what tool has been used to build USDA.DLL? My guess is C++ and ATL,
what version of C++ and ATL and what version of Windows are you running?

The 8002802b HRESULT is an indication that you may have a versioning issue,
I would suggest you to un-register and re-register all components used in
this project (native COM and the C# assembly).
Also make sure that these are only registered once, you can check this with
oleview.
Willy.
 
S

Sharon

I don't get it, your typelib should *not* contain the definition of the
structure defined in another typelib.
What importlib's do you see in your C# module's typelib?

I mean stuff like this:
....
importlib("stdole2.tlb");

I don't see any importlib, not in the sample that works, not in sample that
doesn't work and not in the read project.
In all cases I simply added the native COM dll as a reference and the VS has
added an interop for me automatically.
Also, what tool has been used to build USDA.DLL? My guess is C++ and ATL,

Your guess is correct, it's C++ and ATL, it was build using the VC 6 with
the latest service pack.
what version of C++ and ATL and what version of Windows are you running?

The version of C++ and ATL is the version used in the VC 6 with the latest
service pack.
The USDA.dll was built with VC 6 on Windws2000.
The VB 6 client was also built on Windows2000.
The C# application (that export the COM interface) was build with VS2005+SP1
on WinXP SP2.
The 8002802b HRESULT is an indication that you may have a versioning issue,
I would suggest you to un-register and re-register all components used in
this project (native COM and the C# assembly).
Also make sure that these are only registered once, you can check this with
oleview.

I also suspected that, so I made sure of that, still the same.


Any idea will be highly appreciated.
 
W

Willy Denoyette [MVP]

Sharon said:
I don't see any importlib, not in the sample that works, not in sample
that
doesn't work and not in the read project.
In all cases I simply added the native COM dll as a reference and the VS
has
added an interop for me automatically.
You must be looking in the wrong typelib!
The typelib you need to look at is the resultant typelib from the regasm.exe
command.
regasm.exe /tlb /codebase csharp.dlll, generates a typelib (.tlb) file, this
is the typelib I'm talking about and that's also the typelib you need to
reference in your VB6 client project.

Willy.
 
S

Sharon

Actually I'm not looking directly to the tlb file.
In the VB client I'm simply marking name that matches the tlb file (which is
the same name as the C# exe file but with the tlb extension instead of the
exe) in the References list.

Also when using the oleview to look for the C# COM exposure - I see that the
struct like it's defined in there in spite the fact that this struct is
defined in the native COM DLL.

My guess that something is wrong in the native COM dll USDA.dll that
whenever I'm referencing it in the C# project its struct get like defined in
the C# tlb.
It does not happen in the activeX test we made.

Maybe there a way to generate the interop (using the TlbImp.exe) for the
USDA.dll so its struct will nor get defined in the C# tlb?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top