我的问题是:C#nativly支持后期绑定IDispatch吗?
假装我正在尝试自动化Office,同时兼容客户安装的任何版本.
在.NET世界中,如果您安装了Office 2000,那么从现在到结束,每个开发人员和每个客户都需要拥有Office 2000.
在.NET之前的世界中,我们使用COM与Office应用程序进行通信.
例如:
1)使用版本独立的ProgID
"Excel.Application"
Run Code Online (Sandbox Code Playgroud)
解析为:
clsid = {00024500-0000-0000-C000-000000000046}
Run Code Online (Sandbox Code Playgroud)
然后使用COM,我们要求将其中一个类实例化为一个对象:
IUnknown unk;
CoCreateInstance(
clsid,
null,
CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
IUnknown,
out unk);
Run Code Online (Sandbox Code Playgroud)
现在我们即将参加比赛 - 能够在我的应用程序中使用Excel.当然,如果你真的想要使用该对象,你必须调用一些方法来调用方法.
我们可以得到阿霍德不同的接口声明,翻译成我们的语言.这项技术很好,因为我们得到了
一些示例代码可能是:
Application xl = (IExcelApplication)unk;
ExcelWorkbook workbook = xl.Workbooks.Add(template, lcid);
Worksheet worksheet = workbook.ActiveSheet;
Run Code Online (Sandbox Code Playgroud)
但是使用接口有一个缺点:我们必须得到各种接口声明,转换成我们的语言.我们坚持使用基于方法的调用,必须指定所有参数,例如:
ExcelWorkbook workbook = xl.Workbooks.Add(template, lcid);
xl.Worksheets.Add(before, after, count, type, lcid);
Run Code Online (Sandbox Code Playgroud)
在现实世界中,这证明了我们愿意放弃的这些缺点:
而是使用IDispatch后期绑定:
Variant xl = (IDispatch)unk;
Variant …Run Code Online (Sandbox Code Playgroud) 我需要使用R工具中包含的gcc编译器(R用于windows的统计程序)编译我的一些代码,问题是我需要在我的代码中使用IDispatch来创建访问COM对象的方法,以及gcc编译器不支持我用来执行的大部分代码,这基本上是C++代码.
所以我的问题是如何在C中使用IDispatch来创建COM对象,而不必依赖于MFC,.NET,C#,WTL或ATL.我相信如果我这样做,我将能够毫无问题地编译我的代码.
我正在尝试编写一些使用UPnP进行NAT遍历的代码(仅供家庭使用),使用C#4和Microsoft的基于COM的NAT遍历API(Hnetcfg.dll).
不幸的是(或者幸运的是)我最后一次在.NET中使用COM互操作是在最后一个冰河时代的某个时候,我似乎对C#使用动态类型进行互操作以及如何编写回调感到困惑(所以COM服务器调用我的托管代码).
这是令人兴奋的几行代码:
// Referencing COM NATUPNPLib ("NATUPnP 1.0 Type Library")
using System;
using NATUPNPLib;
class NATUPnPExample
{
public delegate void NewNumberOfEntriesDelegate(int lNewNumberOfEntries);
public static void NewNumberOfEntries(int lNewNumberOfEntries)
{
Console.WriteLine("New number of entries: {0}", lNewNumberOfEntries);
}
public static void Main(string[] args)
{
UPnPNAT nat = new UPnPNAT();
NewNumberOfEntriesDelegate numberOfEntriesCallback = NewNumberOfEntries;
nat.NATEventManager.NumberOfEntriesCallback = numberOfEntriesCallback;
nat.StaticPortMappingCollection.Add(4555, "TCP", 4555, "192.168.0.1", true, "UPnPNAT Test");
// Presumably my NewNumberOfEntries() method should be called by the COM component about now
nat.StaticPortMappingCollection.Remove(4555, "TCP");
} …Run Code Online (Sandbox Code Playgroud) 我无法理解这些术语之间的差异.
COM和ActiveX是同义词吗?
ActiveX对象只是一个公开IDispatch的COM对象吗?
很多旧的MSDN页面都提到没有任何COM上下文的IDispatch.它是否有单独的历史记录,并且刚刚在其生命周期的后期在COM"保护伞"下引入?
OLE适合哪里?它(可观)是否存在于MFC命名和MSDN中 - 所有这些都只是遗产?
维基百科提供了一些见解,但并不多.我找不到更深入的参考资料.
COM中的双接口是能够通过DispInterface或VTable方法访问的接口.
现在可以有人告诉我这两种方法的区别究竟是什么?
我认为VTable是一个虚拟表,它在实现类层次结构时保存指向不同函数的指针,该类层次结构具有可在子类中重写的虚函数.但是我不知道这与COM中的双接口有什么关系?
我正在编写一些测试代码来模拟非托管代码,调用后期绑定COM对象的c#实现.我有一个声明为IDispatch类型的接口,如下所示.
[Guid("2D570F11-4BD8-40e7-BF14-38772063AAF0")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface TestInterface
{
int Test();
}
[ClassInterface(ClassInterfaceType.AutoDual)]
public class TestImpl : TestInterface
{
...
}
Run Code Online (Sandbox Code Playgroud)
当我使用下面的代码调用IDispatch的GetIDsOfNames函数时
..
//code provided by Hans Passant
Object so = Activator.CreateInstance(Type.GetTypeFromProgID("ProgID.Test"));
string[] rgsNames = new string[1];
int[] rgDispId = new int[1];
rgsNames[0] = "Test";
//the next line throws an exception
IDispatch disp = (IDispatch)so;
Run Code Online (Sandbox Code Playgroud)
IDispatch定义为:
//code provided by Hans Passant
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00020400-0000-0000-C000-000000000046")]
private interface IDispatch {
int GetTypeInfoCount();
[return: MarshalAs(UnmanagedType.Interface)]
ITypeInfo GetTypeInfo([In, MarshalAs(UnmanagedType.U4)] int iTInfo, [In, MarshalAs(UnmanagedType.U4)] int …Run Code Online (Sandbox Code Playgroud) 每次我构建我的C#解决方案时,我都会收到一些关于我从未见过或写过的接口的警告.我试过谷歌搜索其中一些,但没有得到点击.这些可能被埋在我正在引用的组件中吗?如果是这样,有没有办法让这些警告消失?
接口'IAlertable'标记为[dual],但不是从IDispatch派生的.它将被转换为IUnknown派生的接口.
接口'ICustomizationPermissionsReports'标记为[dual],但不是从IDispatch派生的.它将被转换为IUnknown派生的接口.
接口'IAlertable2'标记为[dual],但不是从IDispatch派生的.它将被转换为IUnknown派生的接口.
我面临着实现一个IDispatch接口。有四种方法,幸运的是其中 3 种方法很简单:
function TIEEventsSink.GetTypeInfoCount(...): HResult;
{
Result := E_NOTIMPL;
}
function TIEEventsSink.GetTypeInfo(...): HResult;
{
Result := E_NOTIMPL;
}
function TIEEventsSink.GetIDsOfNames(...): HResult;
{
Result := E_NOTIMPL;
}
Run Code Online (Sandbox Code Playgroud)
这是最后一种方法,Invoke这很困难。在这里,我不得不实际处理DispID并调用我的适当方法;从变体数组解组参数。
function Invoke(
dispIdMember: DISPID;
riid: REFIID;
lcid: LCID;
wFlags: WORD;
var pDispParams: DISPPARAMS;
var pVarResult: VARIANT;
var pExcepInfo: EXCEPINFO;
var puArgErr: DWORD
): HRESULT;
Run Code Online (Sandbox Code Playgroud)
不想编写所有乏味的样板代码,我肯定会有错误,我去谷歌搜索 - 而不是做任何工作。
我在以下的 MSDN 文档中IDispatch.Invoke找到了这个片段:
通常,您不应直接实现Invoke。
优秀!我无论如何都不想实施它!继续阅读:
相反,使用调度接口来创建函数CreateStdDispatch和DispInvoke。有关详细信息,请参阅CreateStdDispatch、DispInvoke、 …
我使用WM_COPYDATA来启用我的两个进程A和B之间的通信.与基本数据类型交换数据没有问题.
现在我有一个问题,在某些情况下我想从我的进程A传递一个接口(IDispatch)到我的进程B.是否可能?
我在 C++ 中应用 Invoke 来使用应用程序的对象,但发生错误。错误:信息不可用,没有为 GPNSAutomation.dll 加载符号我的代码是:
::CLSIDFromProgID(OLESTR("SGNSAutomation.SGNSApplication"), &clsid);
IID iid;
HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL,
IID_IDispatch, (LPVOID*)&pWMPDispatch);
IDispatch * pdisp = (IDispatch *)NULL;
DISPID dispid;
DISPPARAMS params= {NULL,NULL,0,0};
params.cArgs =1;
OLECHAR * Name = OLESTR("importCase");
HRESULT hresult =pWMPDispatch->GetIDsOfNames(IID_NULL,
&Name,1,LOCALE_SYSTEM_DEFAULT,&dispid);
hresult =pWMPDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
DISPATCH_METHOD, ¶ms, NULL, NULL,
NULL);
_ASSERT(hr==S_OK);
Run Code Online (Sandbox Code Playgroud)