标签: com-interop

使用Wrapper对象正确清理excel互操作对象

所有这些问题:

解决了C#在使用后没有正确释放Excel COM对象的问题.解决这个问题主要有两个方向:

  1. 不再使用Excel时终止Excel进程.
  2. 注意首先明确地将用于变量的每个COM对象分配,并保证最终在每个上执行Marshal.ReleaseComObject.

有人说过2太繁琐了,你是否忘记在代码中的某些地方忘记遵守这条规则总是存在一些不确定性.仍然1对我来说似乎很脏并且容易出错,我想在有限的环境中试图杀死一个进程可能会引发安全错误.

所以我一直在考虑通过创建另一个模仿Excel对象模型的代理对象模型来解决问题2(对我来说,实现我实际需要的对象就足够了).原则如下:

  • 每个Excel Interop类都有其代理,用于包装该类的对象.
  • 代理在其终结器中释放COM对象.
  • 代理模仿Interop类的接口.
  • 最初返回COM对象的任何方法都会更改为返回代理.其他方法只是将实现委托给内部COM对象.

例:

public class Application
{
    private Microsoft.Office.Interop.Excel.Application innerApplication
        = new Microsoft.Office.Interop.Excel.Application innerApplication();

    ~Application()
    {
        Marshal.ReleaseCOMObject(innerApplication);
        innerApplication = null;
    }

    public Workbooks Workbooks
    {
        get { return new Workbooks(innerApplication.Workbooks); }
    }
}

public class Workbooks
{
    private Microsoft.Office.Interop.Excel.Workbooks innerWorkbooks;

    Workbooks(Microsoft.Office.Interop.Excel.Workbooks innerWorkbooks)
    {
        this.innerWorkbooks = innerWorkbooks;
    }

    ~Workbooks()
    {
        Marshal.ReleaseCOMObject(innerWorkbooks);
        innerWorkbooks = null;
    }
}
Run Code Online (Sandbox Code Playgroud)

我特别向你提问:

  • 谁发现这是一个坏主意,为什么?
  • 谁发现这是一个可怕的想法?如果是这样,为什么没有人实施/发布这样的模型呢?是仅仅是因为努力,还是我错过了这个想法的杀戮问题?
  • 在终结器中执行ReleaseCOMObject是不可能/不好/容易出错的吗?(我只看到过将它放在Dispose()而不是终结器中的建议 - 为什么?)
  • 如果方法有意义,有什么建议可以改进吗?

c# excel interop com-interop

11
推荐指数
1
解决办法
4479
查看次数

在Excel VBA中调用没有COM互操作管理权限的regasm

此处描述了在没有管理员权限的情况下调用regasm的解决方法:

COM Interop没有regasm

我正在尝试创建一个COM库,我的用户可以在没有管理员权限的情况下从Excel VBA部署和使用它.我喜欢regasm解决方法,因为似乎人们在使用Excel VBA中的免注册COM对象方面没有太大成功.我也希望早期绑定,以便我的用户可以从语法完成中受益.

但是,上述问题中接受的答案并未描述将汇编dll放在用户计算机上的位置.管理员权限是在GAC中安装程序集所必需的,所以我想知道在哪里可以放置dll文件.我假设应用程序的目录正在搜索任何引用的dll,但我不能将我的dll放在Excel的目录中而没有管理员权限.是否可以使用Excel客户端的变通方法?有没有其他方法从VBA调用COM对象而不需要管理员权限来首先部署它们?

com vba com-interop regasm excel-vba

11
推荐指数
2
解决办法
4231
查看次数

什么是COM Interop的通用集合的替代品?

我试图从.NET程序集返回一系列部门,以便通过COM Interop使用ASP.使用.NET我会返回一个通用集合,例如List<Department>,但似乎泛型不适用于COM Interop.那么,我的选择是什么?

我想迭代列表并能够通过索引访问项目.我应该继承List<Department>,实施IList,IList<Department>或另一个接口,或者是有没有更好的办法?理想情况下,我不希望为我需要的每种类型的列表实现自定义集合.此外,List[index]甚至可以使用COM Interop?

谢谢,迈克

示例.NET组件(C#):

public class Department {
    public string Code { get; private set; }
    public string Name { get; private set; }
    // ...
}

public class MyLibrary {
    public List<Department> GetDepartments() {
        // return a list of Departments from the database
    }
}
Run Code Online (Sandbox Code Playgroud)

示例ASP代码:

<%
Function PrintDepartments(departments)
    Dim department
    For Each department In departments
        Response.Write(department.Code & ": " & department.Name & "<br />")
    Next …
Run Code Online (Sandbox Code Playgroud)

.net generics collections com-interop asp-classic

10
推荐指数
2
解决办法
6538
查看次数

警告MSB3391:<DLL>不包含可以为COM Interop取消注册的任何类型

我使用VS2005制作了一个简单的C#DLL(这是一个更大的项目的一部分).我需要通过VBA代码在Excel中使用DLL,所以我在程序集上使用COM Interop.我正在尝试使构建过程自动生成必要的TLB文件,这样我就不需要在每次构建之后转到命令行并使用regasm.

我的问题是虽然DLL编译和构建正常,但它不会生成TLB文件.相反,标题中的错误在输出框中打印出来.

我已经获得了其他DLL来构建TLB文件,方法是转到VS2005中的项目属性 - > Build - > Output - > Check "Register for COM interop".另外,我在AssemblyInfo.cs中[assembly:ComVisible(true)].

以下是问题DLL的源代码摘要以及它为返回类型引用的DLL:

using System;
using System.IO;
using System.Runtime.InteropServices;
using SymbolTable;

namespace ProblemLibrary
{
    public class Foo
    {    
        public Foo(string filename)
        {
            ...
        }

        // method to read a text file into a SymbolTable
        public SymbolTable BuildDataSet(string[] selected)
        {
            ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是SymbolTable.dll的摘要.它包含ProblemLibrary使用的返回类型.

using System;
using System.Collections.Generic;

namespace SymbolTable
{
    public class SymbolTable
    {
        readonly Dictionary<SymbolInfoStub, string> …
Run Code Online (Sandbox Code Playgroud)

c# com-interop comvisible typelib visual-studio

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

Visual Studio 2010:嵌入互操作类型

我在Scott Hanselmans博客上找到了一些关于此的信息

有人确切知道这是什么意思吗?

这仅适用于Office主互操作程序集,还是我可以使用它来嵌入我的Redemption库或其他COM库?

clr com-interop pia visual-studio-2010

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

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

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

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

c# com com-interop

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

什么是我用COM互操作得到的`Object [*]`类型?

我做C#excel互操作.我从C#调用宏,我期待对象的数组.我能够从返回二维数组的宏中获取二维对象数组.

但是,其他(第三方)宏应该返回一维数组.我无法得到(object[])xlApp.Run(...)工作(它抛出一个异常),调试器中的类型信息表示结果是类型Object[*].来自异常的实际消息是

Unable to cast object of type 'System.Object[*]' to type 'System.Object[]'.
Run Code Online (Sandbox Code Playgroud)

这是什么Object[*]类型,如何从中检索一维数组?

编辑:我想到这可能意味着SAFEARRAY的VARIANTS.但随后出现了两个问题:为什么二维数组一切正常?如何将SAFEARRAY转换为C#数组?

c# com-interop

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

w3wp.exe中发生未处理的win32异常

尝试加载ASP.NET MVC网站时出现以下异常:

w3wp.exe中0x07070a91处的未处理异常:0xC0000005:访问冲突读取位置0x00000000.

Visual Studio实时调试器打开,我在调试器中看到的唯一信息是:

调用堆栈位置:

MSVBVM60.DLL!06c00a91()

该网站使用了一些COM对象,一切正常,直到上周.这个问题突然出现了.

这是Windows事件查看器的错误日志:

错误应用程序名称:w3wp.exe,版本:7.5.7601.17514,时间戳:0x4ce7a5f8
错误模块名称:MSVBVM60.DLL,版本:6.0.98.15,时间戳:0x4a5bda6c
异常代码:0xc0000005
错误偏移量:0x00030a91
错误进程id:0x1a0
错误应用程序启动时间:0x01cd31fcb47f66d8
错误应用程序路径:C:\ Windows\SysWOW64\inetsrv\w3wp.exe
错误模块路径:C:\ Windows\system32\MSVBVM60.DLL
报告ID:f5db0ae3-9def-11e1-ad79-005056c00008

您有什么建议可以帮助解决这个问题吗?

编辑:我设法解决问题,现在一切正常.该解决方案涉及调整自定义dll所需的一些注册表设置,以便正常运行.所以问题实际上并没有出现,我只是没有意识到一些注册表值被修改,这导致一个com dll崩溃.

c# asp.net asp.net-mvc com-interop iis-7.5

10
推荐指数
2
解决办法
5万
查看次数

.NET互操作来回复制数组数据,还是固定数组?

我有这个COM方法签名,在C#中声明:

void Next(ref int pcch,
          [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
          char[] pchText);
Run Code Online (Sandbox Code Playgroud)

我称之为:

int cch = 100;
var buff = new char[cch];
com.Next(ref cch, buff);
Run Code Online (Sandbox Code Playgroud)

.NET互操作层是否首先将整个数组复制到临时的非托管内存缓冲区,然后将其复制回来?或者数组是否自动固定并通过引用传递?

为了尝试,我在COM对象(C++)中做到了这一点:

*pcch = 1;
pchText[0] = L'A';
pchText[1] = L'\x38F'; // '?'
Run Code Online (Sandbox Code Playgroud)

'?'回来时检查buff[1]C#时会回来.但我不认为这是一个强有力的证据,证明阵列固定,而不是来回复制.

.net c# c++ com com-interop

10
推荐指数
2
解决办法
538
查看次数

在C#中使用VB6字符串数组

我有(遗留)VB6代码,我想从C#代码中使用.

这有点类似于这个问题,但它指的是从VB6传递一个消耗C#dll的数组.我的问题恰恰相反.

在VB中,一个dll中有一个接口,另一个中有一个实现.

接口:

[
  odl,
  uuid(339D3BCB-A11F-4fba-B492-FEBDBC540D6F),
  version(1.0),
  dual,
  nonextensible,
  oleautomation,
      helpstring("Extended Post Interface.")        
]
interface IMyInterface : IDispatch {

    [id(...),helpstring("String array of errors.")]
    HRESULT GetErrors([out, retval] SAFEARRAY(BSTR)* );
};
Run Code Online (Sandbox Code Playgroud)

cMyImplementationClass中的实现(片段):

Private Function IMyInterface_GetErrors() As String()

    If mbCacheErrors Then
        IMyInterface_GetErrors = msErrors
    End If

End Function
Run Code Online (Sandbox Code Playgroud)

我用tlbimp.exe包装了这两个dll,并尝试从C#调用该函数.

public void UseFoo()
{
    cMyImplementationClass foo;
    ...
    var result = foo.GetErrors();
    ...
}
Run Code Online (Sandbox Code Playgroud)

调用foo.GetErrors()会导致SafeArrayRankMismatchException.我认为,这表明在安全数组一节中描述的编组问题在这里.

建议似乎是使用tlbimp.exe的/ sysarray参数或手动编辑我生成的IL,我试过.

最初的IL看起来像这样:

.method public hidebysig newslot virtual 
    instance string[] 
    marshal( safearray bstr) …
Run Code Online (Sandbox Code Playgroud)

c# vb6 com-interop

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