标签: com-interop

通过.NET调用COM对象的手动方式

是否有手动方式在.NET中调用GAC中的COM对象,而不将其添加为引用?

我问的原因是我只知道如何在C#中编码并想要调用.NET COM对象并测试其CMO调用是否可见,但显然您无法将.NET COM对象添加到.NET程序集中!因为你必须引用它,所以我想知道如果它通过c#代码手动在GAC中注册,你可以调用它吗?

c# com com-interop

10
推荐指数
1
解决办法
5475
查看次数

当返回E_POINTER和E_INVALIDARG时?

COM接口方法可以返回各种HRESULT值来表示传递的无效参数值.我什么E_POINTER时候回来E_INVALIDARG

据我所知,如果一个方法在封装集合中接收索引并且它超出了界限E_INVALIDARG.如果一个方法接收到一个Interface**指针,它指的是存储一个指向新创建的对象的指针E_POINTER.

HRESULT CImpl::GetItem( long index; Interface** result )
{
    if( result == 0 ) {
        return E_POINTER;
    }
    if( index < 0 || index >= internalArray.size() ) {
        return E_INVALIDARG;
    }
    *result = CreateWrapperObject( internalArray[index] );
    return S_OK;
}
Run Code Online (Sandbox Code Playgroud)

但是,如果它收到一个WCHAR*文件名为"in"参数的缓冲区并且这WCHAR*是空的呢?是这个E_POINTER还是E_INVALIDARG

或者一个方法接收一个指向某个结构的指针,并期望通过该指针填充结构,并且该指针为空 - 是这个E_POINTER还是E_INVALIDARG

HRESULT CImpl::SaveToFile( WCHAR* fileName )
{
    if( fileName == 0 ) { …
Run Code Online (Sandbox Code Playgroud)

windows com pointers com-interop

9
推荐指数
1
解决办法
6876
查看次数

C#.Net4:正确处理(动态)COM对象

我需要从我的.Net4应用程序自动化办公文档(Word和Excel).

由于我无法真正强迫我的用户使用特定的Office版本,因此我不使用互操作程序集或tlbimp,因此我的项目不包含任何其他引用,如果未安装Office,整个应用程序也将失败(功能刚赢了)不可用).

相反,我问系统哪个COM服务器可以处理"Word.Application"或"Excel.Application":

dynamic app = Activator.CreateInstance(Type.GetTypeFromProgID("Word.Application"));
app.Foo();
Run Code Online (Sandbox Code Playgroud)

我担心如何在完成后正确处理"app"对象,因为现在我有两个内部管理系统需要担心(COM引用计数和.Net引用跟踪).理想情况下,我应该能够将动态app对象包装到一次性包装器类中,并确保在处理包装器时底层COM对象未被引用.

编辑:此外,我想知道当我完成它时如何正确地使COM对象"活着",因为Word是在一个单独的过程中.我应该能够实例化Word应用程序,自动化它,然后释放我的所有引用,但Word应用程序应该保持打开状态.

.net c# com com-interop

9
推荐指数
1
解决办法
6089
查看次数

如何使用tlbimp指定不同的File和Assembly版本?

我们使用tlbimp来生成互操作程序集.我们想用文件版本和汇编版本标记互操作程序集.但是,tlbimp上的/ asmversion选项似乎将这两个选项设置为相同的值.

有谁知道如何使用tlbimp在互操作程序集上设置不同的文件和程序集版本?

.net com-interop tlbimp

9
推荐指数
1
解决办法
897
查看次数

将BSTR传递到C#(COM互操作)的COM函数的约定

我正在编写用C++编写COM的API,还编写一个在C#中使用这个API的程序.我的问题是关于将BSTR传递给COM函数时的BSTR内存管理语义.说我的IDL看起来像:

HRESULT SomeFunction([in] BSTR input);
Run Code Online (Sandbox Code Playgroud)

目前这个功能是这样实现的:

HRESULT SomeFunction(BSTR input) {
    // Do stuff ..., then:
    SysFreeString(input);
}
Run Code Online (Sandbox Code Playgroud)

当我用C#调用它时,C#SomeFunction(myString)会生成这样的东西(伪代码):

myString = SysAllocString("string");
SomeFunction(myString);
Run Code Online (Sandbox Code Playgroud)

或者更喜欢这样:

myString = SysAllocString("string");
SomeFunction(myString);
SysFreeString(myString);
Run Code Online (Sandbox Code Playgroud)

也就是说,C#是否释放它生成的BSTR来编组COM接口,还是应该在我的函数中释放它?谢谢!

c# c++ com com-interop

9
推荐指数
1
解决办法
3388
查看次数

Visual Studio的调试器/交互式窗口如何在.NET中转储COM对象的属性?

在这个相关的问题中,我注意到Visual Studio的调试器能够枚举System.__ComObject引用的属性,这是"当包装器类型不明确时使用的隐藏类型" - 例如,当您从另一个获取它时获得的对象类型COM对象,不要自己实例化它:

COM对象调试视图

此外,如果您只是将COM对象的标识符写入立即窗口,其属性和值将被类似地转储:

COM对象立即窗口

请注意,这与VS2010的" 动态视图 " 是分开的,我认为它使用IDispatchCOM反射来枚举COM对象的属性,而不使用PIA和.NET反射.我正在使用的对象没有实现IDispatch(也没有实现IProvideClassInfo),因此,"动态视图"无法获取有关它们的任何信息:

动态视图

有趣的是,SharpDevelop的调试器无法列出System.__Comobjects(例如point.Envelope)的成员,只能列出强类型的RCW(例如point).

SharpDevelop调试器

那么Visual Studio如何才能做到呢?

我相信在这种情况下,这是因为主互操作程序集存在这些对象支持的接口的定义,并且Visual Studio可能使用反射来枚举支持的接口和属性.那是准确的吗?如果是这样,它是如何工作的?

对于初学者,它如何访问PIA?它只查看当前加载的PIA还是动态加载它们(如果是,如何)?它如何确定哪个界面可以有多个枚举属性?它似乎只使用一个,而不一定是第一个.从我正在使用的API(ArcObjects)的文档中,这些对象的默认接口是IUnknown,所以它不仅仅使用默认接口.

在屏幕截图的示例中,它枚举成员的IEnvelope接口是接口,它继承自IGeometry接口.VS2010如何知道不会枚举成员IGeometry,在我的测试中,如果你只是枚举PIA中的所有接口类型,它首先出现?一些非常聪明的事情或者我错过了一些明显的东西?

我问的原因是LINQPad 的开发人员似乎愿意实现相同的功能,如果他知道VS如何做到这一点.所以这里一个好的答案可以帮助改进这个非常受欢迎的工具.

com arcobjects com-interop visual-studio-2010 linqpad

9
推荐指数
1
解决办法
1167
查看次数

如何通过COM公开可空类型

我一直在努力解决这个问题一天半,希望有人可以帮助我.假设我在C#中有这样的结构:

public struct Part
{
    public double? x;  // or System.Nullable<double> x, doesn't really matter
}
Run Code Online (Sandbox Code Playgroud)

(这些结构表示数据库表,从Linq转换为SQLMetal创建的SQL代码)

我需要能够将这些包含可空类型的结构公开给COM,以便它们可以在另一个应用程序(C++)中使用.但我无法弄清楚,对于我的生活,如何做到这一点.我以为我可以创建类来封装可空类型:

public class NullableDouble
{
    private double _Value;
    // class methods...
}

public struct Part
{
    public NullableDouble x;
}
Run Code Online (Sandbox Code Playgroud)

这种工作,但在C++方面,我最终得到一个类的指针,但没有类定义(只是一个接口):

interface DECLSPEC_UUID("{E8EE4597-825D-3F4C-B20B-FD6E9026A51C}") _NullableDouble;

struct Part
{
    MyDll_tlb::_NullableDouble* x;
}
Run Code Online (Sandbox Code Playgroud)

因此,我无法取消引用没有类定义的指针,从中可以访问C++端的数据成员/方法.如果我能弄清楚如何在C++中获取类定义(我是COM的新手),这仍然是一个不错的选择.

我想也许我可以使用不安全的代码,但我无法弄清楚如何从double转换?加倍*(我也是C#的新手!):

unsafe public struct Part
{
    public double* x;
}

Part part = new Part()
{
    x = AnotherObject.x // AnotherObject.x is a System.Nullable<double>
}
Run Code Online (Sandbox Code Playgroud)

我想也许我可以使用System.Variant,但C#也不喜欢它(不一致的可访问性,无论这意味着什么).

public struct Part
{
    public Variant …
Run Code Online (Sandbox Code Playgroud)

c# c++ com-interop

9
推荐指数
1
解决办法
1018
查看次数

WebBrowserSite:如何在派生类中调用私有COM接口方法?

这是挑战.我来自Framework的WebBrowserSite类.我的派生类的实例ImprovedWebBrowserSite是通过WebBrowser.CreateWebBrowserSiteBase,我在我的WebBrowser类的派生版本中重写- 特别是提供自定义站点对象.Framework的WebBrowser实现进一步将其传递给底层的非托管WebBrowser ActiveX控件.

到目前为止,我已经设法IDocHostUIHandler在我的ImprovedWebBrowserSite实现中覆盖(像这样).我现在正在寻找更多核心COM接口,比如IOleClientSite,我想要传递给它WebBrowserSite.所有这些都暴露在与COM ComImport,但声明privateinternal由框架实施的WebBrowserSite/ UnsafeNativeMethods.因此,我无法在派生类中明确地重新实现它们.我必须像我一样定义自己的版本IDocHostUIHandler.

所以,问题是,如何WebBrowserSite从我的派生类中调用定义的私有或内部COM接口的方法?例如,我想打电话IOleClientSite.GetContainer.我可以使用反射(像这样),但这将是最后的手段,其次是WebBrowser从头开始重新实现.

我的想法是,因为Framework的私有UnsafeNativeMethods.IOleClientSite和我自己ImprovedWebBrowserSite.IOleClientSite都是COM接口,用ComImport属性声明,相同的GUID和相同的方法签名..NET 4.0+中有COM类型等价,因此必须有一种方法可以在没有反射的情况下完成.

[更新]现在我已经有了一个解决方案,我相信它为自定义WinForms版本WebBrowser控件开启了一些新的和有趣的可能性.

这个版本的问题是在我最初尝试以更抽象的形式表达问题之后创建的,被评论员称为误导.评论已被删除,但我决定保留这两个版本.

为什么我不想用反射来解决这个问题?原因如下:

  • 依赖于实现者给出的内部或私有方法的实际符号名称WebBrowserSite,与COM接口不同,它与二进制v表合同有关.

  • 庞大的反射代码.例如,考虑调用base的私有TranslateAcceleratorvia Type.InvokeMember …

.net c# com com-interop webbrowser-control

9
推荐指数
1
解决办法
1939
查看次数

在Windows 10上使用Excel interop无法打开超过11个Excel实例

在C#中使用Excel Interop,在具有16GB内存的Macbook Pro上的Windows 10下,我无法打开超过11个Excel实例.在第11个实例之后,我在"弹出窗口"中收到以下错误:

"不能使用对象链接和嵌入"

这是我使用的代码:

List<Application> apps = new List<Application>();
for (int i = 0; i < 15; i++)
{
    Application a = new Application();
    apps.Add(a);
}
Run Code Online (Sandbox Code Playgroud)

每个Excel进程大约15k的内存,远远超过机器上的16GB内存...

我使用.NET Framework 4.5.2,Windows 10,macbook pro,16GB内存和Excel个人.

c# excel com-interop office-interop

9
推荐指数
1
解决办法
856
查看次数

使用C#中的复杂用户定义类型(UDT)调用VB6 DLL函数

我正在编写一个C#应用程序来调用第三方VB6 DLL.我在References-> COM选项卡中添加了对VB6 DLL的引用.

DLL中的特定方法采用VB6 UDT(用户定义类型)作为参数.

此UDT在COM的自动生成的.NET包装器中显示为结构.该结构具有许多子UDT /结构以及VBA.Collection类型的成员(如.NET元数据所示).它还有常规数据类型,如string,short,double,int等.

我在我的C#代码中初始化这个结构为:

udtEmployee udtEmpData = default(udtEmployee);
Run Code Online (Sandbox Code Playgroud)

我也试过了

udtEmpData = new udtEmployee();
Run Code Online (Sandbox Code Playgroud)

如果我没有使用default或new初始化它,我无法编译我的C#代码,因为编译器抱怨使用未分配的变量.

我需要传递这个结构作为参考.我是这样做的:

clsEmployee.SetData(ref udtEmpData);
Run Code Online (Sandbox Code Playgroud)

在调用VB6 DLL的这个方法时,我收到错误:

错误:尝试读取或写入受保护的内存.这通常表明其他内存已损坏.

原因是什么,解决方案是什么?

注意,我无法更改VB6 DLL,因为我没有其源代码.我正在使用VS 2005.

编辑1:

这是一个完整的背景:

有一个本地开发的ERP产品,它支持使用VB6的附加开发.它有一个配置文件,它指定要加载的附加DLL的名称.然后,这些插件将显示在ERP应用程序的菜单中.在菜单上单击,ERP调用名为StartAddOn()的函数,该函数应存在于VB6 DLL中.

我想在C#中开发附加组件,所以我开发了一个带有StartAddOn方法的简单VB6插件,后者又将控制权传递给我的.NET DLL.

.NET DLL使用ERP公开的业务类,并来回传递数据对象.在.NET DLL中,我添加了对ERP供应商发布的DLL的COM引用.

所以架构是这样的:ERP-> VB6 AddOn和StartAddOn方法 - > .NET DLL->使用ERP供应商发布的COM DLL及其数据类(结构/ UDT).

如何调试内存错误?

c# vb6 dll com-interop user-defined-types

9
推荐指数
1
解决办法
691
查看次数