所有这些问题:
解决了C#在使用后没有正确释放Excel COM对象的问题.解决这个问题主要有两个方向:
有人说过2太繁琐了,你是否忘记在代码中的某些地方忘记遵守这条规则总是存在一些不确定性.仍然1对我来说似乎很脏并且容易出错,我想在有限的环境中试图杀死一个进程可能会引发安全错误.
所以我一直在考虑通过创建另一个模仿Excel对象模型的代理对象模型来解决问题2(对我来说,实现我实际需要的对象就足够了).原则如下:
例:
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)
我特别向你提问:
此处描述了在没有管理员权限的情况下调用regasm的解决方法:
我正在尝试创建一个COM库,我的用户可以在没有管理员权限的情况下从Excel VBA部署和使用它.我喜欢regasm解决方法,因为似乎人们在使用Excel VBA中的免注册COM对象方面没有太大成功.我也希望早期绑定,以便我的用户可以从语法完成中受益.
但是,上述问题中接受的答案并未描述将汇编dll放在用户计算机上的位置.管理员权限是在GAC中安装程序集所必需的,所以我想知道在哪里可以放置dll文件.我假设应用程序的目录正在搜索任何引用的dll,但我不能将我的dll放在Excel的目录中而没有管理员权限.是否可以使用Excel客户端的变通方法?有没有其他方法从VBA调用COM对象而不需要管理员权限来首先部署它们?
我试图从.NET程序集返回一系列部门,以便通过COM Interop使用ASP.使用.NET我会返回一个通用集合,例如List<Department>,但似乎泛型不适用于COM Interop.那么,我的选择是什么?
我想迭代列表并能够通过索引访问项目.我应该继承List<Department>,实施IList,IList<Department>或另一个接口,或者是有没有更好的办法?理想情况下,我不希望为我需要的每种类型的列表实现自定义集合.此外,List[index]甚至可以使用COM Interop?
谢谢,迈克
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)
<%
Function PrintDepartments(departments)
Dim department
For Each department In departments
Response.Write(department.Code & ": " & department.Name & "<br />")
Next …Run Code Online (Sandbox Code Playgroud) 我使用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) 是否有手动方式在.NET中调用GAC中的COM对象,而不将其添加为引用?
我问的原因是我只知道如何在C#中编码并想要调用.NET COM对象并测试其CMO调用是否可见,但显然您无法将.NET COM对象添加到.NET程序集中!因为你必须引用它,所以我想知道如果它通过c#代码手动在GAC中注册,你可以调用它吗?
我做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#数组?
尝试加载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崩溃.
我有这个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#时会回来.但我不认为这是一个强有力的证据,证明阵列固定,而不是来回复制.
我有(遗留)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) com-interop ×10
c# ×7
com ×3
.net ×2
asp-classic ×1
asp.net ×1
asp.net-mvc ×1
c++ ×1
clr ×1
collections ×1
comvisible ×1
excel ×1
excel-vba ×1
generics ×1
iis-7.5 ×1
interop ×1
pia ×1
regasm ×1
typelib ×1
vb6 ×1
vba ×1