I need to make a piece of C# code interact through COM with all kinds of implementations.
我需要让一段C#代码通过COM与各种实现进行交互。
To make it easeier for users of that integration, I included the interacted interfaces in IDL (as part of a relevant existing DLL, but without coclass or implementation), then got that into my C# code by running Tlbimp to create the types definition.
为了使该集成的用户更容易,我在IDL中包含了相互作用的接口(作为相关现有DLL的一部分,但没有coclass或实现),然后通过运行Tlbimp来创建类型定义,将其纳入我的C#代码。
I implemented my C#, creating COM objects based on Windows registry info and casting the object into the interface I need.
我实现了我的C#,根据Windows注册表信息创建COM对象,并将对象转换为我需要的接口。
I then created a C# implementation of the interface in a seperate project and registered it. The main program creates the testing COM object correctly but fails to cast it into the interface (gets a null object when using C# 'as', gets an InvalidCastException of explicit cast).
然后我在一个单独的项目中创建了一个接口的C#实现并注册了它。主程序正确创建测试COM对象但未能将其强制转换为接口(使用C#'作为'时获取空对象,获取显式强制转换的InvalidCastException)。
Can someone suggest why the interface is not identified as implemented by the testing object?
有人可以建议为什么界面未被识别为测试对象实现的?
This is the interface defition in IDL (compiled in C++ in VS 2005):
这是IDL中的接口定义(在VS 2005中用C ++编译):
[
object,
uuid(B60C546F-EE91-48a2-A352-CFC36E613CB7),
dual,
nonextensible,
helpstring("IScriptGenerator Interface"),
pointer_default(unique)
]
interface IScriptGenerator : IDispatch{
[helpstring("Init the Script generator")]
HRESULT Init();
[helpstring("General purpose error reporting")]
HRESULT GetLastError([out] BSTR *Error);
};
This is the stub created for C# by Tlbimp:
这是Tlbimp为C#创建的存根:
[TypeLibType(4288)]
[Guid("B60C546F-EE91-48A2-A352-CFC36E613CB7")]
public interface IScriptGenerator
{
[DispId(1610743813)]
void GetLastError(out string Error);
[DispId(1610743808)]
void Init();
}
This is part of the main C# code, creating a COM object by its ProgID and casting it to the IScriptGenerator interface:
这是主要C#代码的一部分,通过其ProgID创建COM对象并将其转换为IScriptGenerator接口:
public ScriptGenerator(string GUID)
{
Type comType = Type.GetTypeFromProgID(GUID);
object comObj = null;
if (comType != null)
{
try
{
comObj = Activator.CreateInstance(comType);
}
catch (Exception ex)
{
Debug.Fail("Cannot create the script generator COM object due to the following exception: " + ex, ex.Message + "\n" + ex.StackTrace);
throw ex;
}
}
else
throw new ArgumentException("The GUID does not match a registetred COM object", "GUID");
m_internalGenerator = comObj as IScriptGenerator;
if (m_internalGenerator == null)
{
Debug.Fail("The script generator doesn't support the required interface - IScriptGenerator");
throw new InvalidCastException("The script generator with the GUID " + GUID + " doesn't support the required interface - IScriptGenerator");
}
}
And this is the implementing C# code, to test it's working (and it's not):
这是实现C#代码,以测试它的工作(而不是):
[Guid("EB46E31F-0961-4179-8A56-3895DDF2884E"),
ProgId("ScriptGeneratorExample.ScriptGenerator"),
ClassInterface(ClassInterfaceType.None),
ComSourceInterfaces(typeof(SOAAPIOLELib.IScriptGeneratorCallback))]
public class ScriptGenerator : IScriptGenerator
{
public void GetLastError(out string Error)
{
throw new NotImplementedException();
}
public void Init()
{
// nothing to do
}
}
2 个解决方案
#1
2
Again - thanks for the suggestions.
再次 - 感谢您的建议。
I was able to finally resolve the issue on my own. I tried the above suggestions and didn't made any progress. Then I changed the namespace of the interop in the 'testing' code - it varied from the one in the main code because of different argument use when using Tlbimp. This solved the problem.
我终于能够自己解决这个问题了。我尝试了上述建议并没有取得任何进展。然后我在'testing'代码中更改了interop的名称空间 - 它与主代码中的名称空间不同,因为在使用Tlbimp时使用了不同的参数。这解决了这个问题。
Here's my guess to why: .Net creates the COM object, but when it detects this is actually a .Net object, it bypass the COM layer and communicates directly. In which case, queryInterface (with the interface GUID) is not used and the interface do differ because of different C# namespaces.
以下是我的猜测:.Net创建COM对象,但是当它检测到这实际上是一个.Net对象时,它会绕过COM层并直接进行通信。在这种情况下,不使用queryInterface(带有接口GUID),并且由于不同的C#名称空间,接口确实不同。
This means that in order to supprot integration with .Net code, I will need to publish my original interop assembly aside the IDL.
这意味着为了支持与.Net代码的集成,我需要在IDL之外发布我原来的互操作程序集。
Thanks, Inbar
#2
0
I think you need this on the interface
我认为你需要在界面上这样做
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
#1
2
Again - thanks for the suggestions.
再次 - 感谢您的建议。
I was able to finally resolve the issue on my own. I tried the above suggestions and didn't made any progress. Then I changed the namespace of the interop in the 'testing' code - it varied from the one in the main code because of different argument use when using Tlbimp. This solved the problem.
我终于能够自己解决这个问题了。我尝试了上述建议并没有取得任何进展。然后我在'testing'代码中更改了interop的名称空间 - 它与主代码中的名称空间不同,因为在使用Tlbimp时使用了不同的参数。这解决了这个问题。
Here's my guess to why: .Net creates the COM object, but when it detects this is actually a .Net object, it bypass the COM layer and communicates directly. In which case, queryInterface (with the interface GUID) is not used and the interface do differ because of different C# namespaces.
以下是我的猜测:.Net创建COM对象,但是当它检测到这实际上是一个.Net对象时,它会绕过COM层并直接进行通信。在这种情况下,不使用queryInterface(带有接口GUID),并且由于不同的C#名称空间,接口确实不同。
This means that in order to supprot integration with .Net code, I will need to publish my original interop assembly aside the IDL.
这意味着为了支持与.Net代码的集成,我需要在IDL之外发布我原来的互操作程序集。
Thanks, Inbar
#2
0
I think you need this on the interface
我认为你需要在界面上这样做
[InterfaceType(ComInterfaceType.InterfaceIsDual)]