当ActiveXObject托管在Windows桌面/边栏小工具中时,该ActiveXObject会被缓存,并且其DLL文件被锁定(意味着它无法移动,删除或重命名).问题是这样的; 当小工具随后关闭时,DLL仍然被Windows边栏锁定,无法删除.这导致了一个严重的问题,即新版本的小工具无法安装在小工具的先前版本的顶部,在删除它的过程中失败而没有任何错误消息.
这不是非常用户友好,所以我正在寻找一种方法来在小工具的卸载事件中以某种方式"切断"与ActiveX控件的联系.我希望有人可以告诉我这是否可能,以及是否给我一些关于如何实现它的想法.
仅供参考,Windows边栏小工具实际上只是Internet Explorer服务器窗口,因此假设IE表现出相同的行为可能是安全的.
编辑: Unlocker似乎做了我需要做的事情,所以如何在.NET中以编程方式实现相同的功能呢?
我有一个 C# 程序集,用作非托管 C++ 应用程序使用的进程内 COM 服务器。该程序集使用永远不会更改的 Web 服务,因此无需更新 Web 服务代理类。这就是为什么代理类被创建一次,Reference.cs文件被简单地放入存储库中并仅从那里进行编译。
问题是默认情况下 Web 服务代理类是公共的,因此暴露给 COM。这会导致类型库膨胀并污染注册表。将可见性更改为内部会破坏程序集,因此这些实体需要保持公共状态,但不需要暴露给 COM。
愚蠢的方法是接近文件中的每个公共接口/类Reference.cs并将其标记为
[System.Runtime.InteropServices.ComVisible(false)]
Run Code Online (Sandbox Code Playgroud)
此后,它不再暴露于 COM。
有没有更好的办法?
我最近将所有测试项目从dotnet 4切换到了dotnet 3.5(因为我想在CLR 2.0下测试代码(见这里).大多数工作正常,但是一个测试项目依赖于IWshRuntimeLibrary.这由以下csproj指定片段:
<COMReference Include="IWshRuntimeLibrary">
<Guid>{F935DC20-1CF0-11D0-ADB9-00C04FD58A0B}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
Run Code Online (Sandbox Code Playgroud)
我们将测试项目构建为"AnyCPU".当测试项目是.Net 4时,这似乎产生了一个ANYCPU interop dll.现在它是.Net 3.5,interop dll是x86,它System.BadImageFormatException在64位平台上运行时.在降级测试项目之前没有发生此问题.
我在ASP.NET 4.0框架下使用以下代码从Web应用程序获取MSI文件的版本:
string strVersion = "";
try
{
Type InstallerType;
WindowsInstaller.Installer installer;
InstallerType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
installer = (WindowsInstaller.Installer)Activator.CreateInstance(InstallerType);
WindowsInstaller.Database db = installer.OpenDatabase(strMSIFilePath, 0);
WindowsInstaller.View dv = db.OpenView("SELECT `Value` FROM `Property` WHERE `Property`='ProductVersion'");
WindowsInstaller.Record record = null;
dv.Execute(record);
record = dv.Fetch();
strVersion = record.get_StringData(1).ToString();
dv.Close();
//db.Commit();
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(dv);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(db);
}
catch
{
//Failed
strVersion = "";
}
Run Code Online (Sandbox Code Playgroud)
它工作正常,但是当代码完成运行时它保存一个内部MSI文件句柄,所以当我尝试移动或重命名MSI文件时,我得到文件仍在使用的错误.这一直持续到我实际离开调用上述方法的ASPX页面.
我的问题是,我显然没有在上面的代码中关闭一些句柄或对象.但这可能是什么?
PS.我正在VS2010的开发IDE中测试它.
编辑:编辑代码应该是在阿德里亚诺的建议之后.谢谢!
我正在编写一个项目并使用另一方DLL.
他们的DLL函数想要一个IStream对象来保存结果,但我无法理解如何创建一个IStream对象.
任何人都可以帮我解决我的问题吗?
我的最终目标是用 C# 构建一个类库 (Calculator.dll),其中包含可通过 VBA 访问 Excel 的函数。
我本来希望避免注册 dll 的需要,而是在 VBA 代码中使用 Declare Function 语句,但显然这是不可能的,我的研究表明我需要使类库 COM-Visible,然后注册并将其添加为 VBA 项目的引用。在早期的 Visual Studio 版本中,这似乎是单击项目属性对话框中的框的问题,但我在 VS2022 中没有看到该框?!
这些是我对“玩具”示例采取的步骤,以及我遇到的问题。
(1) 我用一个计算类和一个简单的方法来添加两个整数,构建了以下 .dll。由于我们使用 32 位 Excel,因此我将其配置为 x86。
namespace ClassLibraryCalculator
{
public class Calculate
{
public int Add(int a,int b){ return a + b; }
}
}
Run Code Online (Sandbox Code Playgroud)
(2) 在命令提示符下,以管理员身份运行,我尝试运行 regsvr32“ClassLibraryCalculator.dll”,但遇到错误“..已加载,但未找到入口点 DllRegisterServer”
经过搜索,据说解决这个问题的方法是修改项目属性,这是(在早期版本的VS中?)一个对话框

带有一个复选框,但我在 Visual Studio 2022 项目属性中没有看到任何与 COM 相关的内容。
我使用.Net 3.5在C#中编写了一个支持COM interop的类库.该对象旨在为经典ASP页面提供一些实用程序功能.我编写了一个test.asp页面,该页面实例化了所需的对象并调用了它的方法.在我的机器上正常工作.
在另一台计算机(Windows Server 2003 - 标准版)上,虽然正确地向regasm注册了程序集,但它不起作用.我已经检查了注册表并且看起来没问题.
我得到的错误是"ASP 0177"(错误代码),"8000ffff; Server.CreateObject-Fehler"(错误描述),它转换为Server.CreateObject-Error.
顺便说一句.程序集已签名,并且没有任何其他自定义构建程序集作为依赖项(只是系统内容).
有人经历过类似的事吗?
我有一个C#dll通过com-interop暴露给vb6.这一切都有效,但是当我将.Net的自定义对象数组传递给VB6时,我注意到了一些奇怪的事情.
从VB6访问数组让我感到困惑.如果我直接访问数组,我必须这样做:
Dim manager as New ObjectManager
'Access with two sets of parentheses:
msgbox manager.ReturnArrayOfObjects()(0).Name
Run Code Online (Sandbox Code Playgroud)
但是,如果我先复制数组,我可以访问它通常所期望的:
Dim manager as New ObjectManager
Dim objectArray() As CustomObject
'copy the array
objectArray = manager.ReturnArrayOfObjects
'access normally:
msgbox objectArray(0).Name
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,我不得不用2套括号:manager.ReturnArrayOfObjects()(0).Name 在第二种情况下,我可以只使用一个括号中:objectArray(0).Name
有谁知道为什么会这样?我可能在这里做错了吗?
这是C#interop代码的快速存根/示例.
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("[Guid here...]")]
public interface IObjectManager
{
[DispId(1)]
CustomObject[] ReturnArrayOfObjects();
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("[guid here...]")]
public class ObjectManager: IObjectManager
{
public CustomObject[] ReturnArrayOfObjects()
{
return new CustomObject[] { new CustomObject(), …Run Code Online (Sandbox Code Playgroud) 我正在开发一个项目,我需要将C++代码转换为C#.
我_bstr_t在代码中遇到了我想知道C#中的等价物.
我有一节课:
public class A
{
public delegate void SetTextDel(string value);
public void Test()
{
SetTextDel setText = someInterface.SetText;
icom.Set(setText);
}
}
[ComVisible(true), Guid("81C99F84-AA95-41A5-868E-62FAC8FAC263"), InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface Icom
{
void Set(Delegate del);
}
[ComVisible(true)]
[Guid("6DF6B926-8EB1-4333-827F-DD814B868097")]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(Icom))]
public class B : Icom
{
Set(Delegate del)
{
del.DynamicInvoke("some text");
}
}
Run Code Online (Sandbox Code Playgroud)
我在Set(Delegate del)中获得了targetinvocation异常.有没有更好的方法来转发委托作为参数?或者我在这里犯了一些我没有看到的错误.我想做的是将someInterface.SetText这个方法作为参数传递.谢谢你的帮助.
com-interop ×10
c# ×8
.net ×7
com ×5
activex ×1
arrays ×1
asp-classic ×1
asp.net ×1
c++ ×1
createobject ×1
dll ×1
handle ×1
vb6 ×1
winapi ×1