我有一个托管(实际上是asp.net)项目,它引用了一个COM DLL.现在,.csproj中的引用如下所示:
<COMReference Include="thenameinquestion">
<Guid>{someguidhere}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
</COMReference>
Run Code Online (Sandbox Code Playgroud)
这是有效的,但它有一个令人遗憾的结果,DLL需要在构建机器上注册,这意味着(除其他外)在同一构建机器上构建使用不同版本的DLL的项目的多个版本是不方便的.
MSDN显示ResolveComReference任务看起来它做的正确,但我的google-search-fu还不够好,无法提供其使用的实际示例.有可能做我想要的吗?我是在正确的轨道上吗?
我正在构建一个加载32位COM dll的C#应用程序.编译的应用程序在32位Windows上正常运行,但在64位Windows上运行barfs,因为它无法加载32位COM.有没有办法在VC#2008 Express Edition中设置32位构建目标?
或者,有没有办法强制编译到AnyCPU构建目标的.NET应用程序在64位Windows上以32位模式运行?
一些用户报告说,如果他们通过双击Excel文件启动Excel,则加载项将不会加载.但是,如果他们通过"开始"菜单(或"快速启动"工具栏)打开Excel,则加载项可以正常加载.
一些细节,以防他们帮助:
任何有关原因的想法或如何解决这个问题将不胜感激.
更新:我相信我找到了解决这个问题的方法.
当注册IDTExtensibility2 dll时,它会自动为加载行为,加载项名称等创建HKCU条目.但是我也让我的安装文件注册了HKLM的加载项,以便所有用户都可以使用它.机.这导致系统上的双重注册表项.
我不认为这会是问题的原因.我手动编辑了HKCU条目,Excel似乎忽略了它们并遵循HKLM条目.但是,我收到另一位开发人员的提示,解释他们遇到了同样的问题,他们的解决方案是删除重复的注册表项.我试过了,似乎已经解决了报告这个bug的(极少数)人的问题.
下面的Inno设置代码将添加HKLM条目,仔细检查加载行为是否正确(因为我是偏执狂),然后删除HKCU条目.在您看到所有大写字母的任何地方替换您的文件属性.
[Registry]
Root: HKLM; Subkey: Software\Microsoft\Office\Excel\Addins\CONNECT_CLASS; Flags: uninsdeletekey
Root: HKLM; Subkey: Software\Microsoft\Office\Excel\Addins\CONNECT_CLASS; ValueType: string; ValueName: FriendlyName; ValueData: ADDIN_NAME
Root: HKLM; Subkey: Software\Microsoft\Office\Excel\Addins\CONNECT_CLASS; ValueType: string; ValueName: Description; ValueData: ADDIN_DESC
Root: HKLM; Subkey: Software\Microsoft\Office\Excel\Addins\CONNECT_CLASS; ValueType: dword; ValueName: LoadBehavior; ValueData: 3
Root: HKLM; Subkey: Software\Microsoft\Office\Excel\Addins\CONNECT_CLASS; ValueType: dword; ValueName: CommandLineSafe; ValueData: 0
// Set load behavior to on start up
procedure ResetAddinRegKeys();
var
bUpdate : Boolean;
LoadBehaviorKey : Cardinal;
begin …Run Code Online (Sandbox Code Playgroud) 想要了解更多关于Windows Internals的人,阅读"Windows Internals"一书,并想进入驱动程序开发,是否正在学习COM编程是一个好主意?
我应该深入了多少?考虑到上述情况,只需了解基础知识或理解是否应该进行.
是否有可靠的方式以编程方式打开特定的bloomberg终端页面(例如"MSFT Equity")?
我对任何建议和代码示例持开放态度:
非常感谢
我正在编写Python 2.6代码,通过Windows中的COM 与NI TestStand 4.2连接.我想为变量创建一个"NAN"值,但如果我传递它float('nan'),TestStand 会将其显示为IND.
显然,TestStand区分浮点"IND"和"NAN"值.根据TestStand的帮助:
IND对应于Visual C++中的信令NaN,而NAN对应于QuietNaN这意味着Python 在通过COM时float('nan')实际上是一个信令NaN.然而,从我读到的有关信号NaN的内容来看,似乎信号NaN有点"异国情调"而Quiet NaN是你的"常规"NaN.所以我怀疑Python会通过COM 传递信令NaN.我怎么能知道Python float('nan')是通过COM作为信令NaN还是Quiet NaN传递,还是可能不确定?
在与其他语言连接时,有没有办法在Python中建立信令NaN与QuietNaN或Indeterminate?(ctypes或许使用?)我认为这将是一个特定于平台的解决方案,在这种情况下我会接受.
更新:在TestStand序列编辑器中,我尝试制作两个变量,一个设置为NAN,另一个设置为IND.然后我把它保存到一个文件中.然后我打开文件并使用Python读取每个变量.在这两种情况下,Python都将它们作为nanfloat 读取.
我有一个COM服务器(C++/STA(基于MFC的应用程序))和一个COM客户端(C#/ MTA).COM服务器必须位于STA中,因为它是一个MFC应用程序(在这个问题上我别无选择).客户端向服务器发出调用,服务器向客户端发出回调.这就是错误发生的地方(RPC_E_CANTCALLOUT_ININPUTSYNCCALL).我猜测服务器是否是MTA,这个问题永远不会出现,但遗憾的是,MFC的文档明确否认将公寓初始化为MTA.
关于如何解决这个问题的任何想法?
我一直在想让服务器对象(我通过运行对象表公开的对象)住在自己的公寓(MTA)中.这是一个好主意,还是先尝试一些简单的东西?
UPDATE
服务器对象只是指向应用程序中某些功能的精简界面.大多数情况下,它只是读取和写入内存位置,但有些情况下它会向应用程序中的各个窗口生成窗口消息.服务器对象本身不是整个应用程序.
任何人都可以解释为什么,如果一个C++应用程序运行一个.NET UI组件(所有在主线程上),它反过来产生一个模态.NET对话框,然后尝试TaskScheduler.FromCurrentSynchronizationContext();在一个Task.Factory.StartNew调用中使用该任务在一个工作线程上运行?如果我没有显示对话框或者在显示对话框之前存储了上下文,则不会发生这种情况.
我试图创建一个虚拟程序来显示它但失败了,我认为它可能与一个主进程是COM有关.
有任何想法吗?
好的,我的代码看起来像这样
private void RunStateMachine(IQ4UpgraderState State)
{
_State = State;
Task.Factory.StartNew(() => StateMachine(), _TokenSource.Token, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}
private void StateMachine()
{
switch (_State)
{
//Some Code
}
}
Run Code Online (Sandbox Code Playgroud)
当任务启动时,当前上下文是主线程,但是当StateMachine调用运行时,它在工作线程上,当且仅当 我在运行此代码之前打开了模式对话框时.TaskScheduler.FromCurrentSynchronizationContext()返回的上下文在启动任务时似乎是正确的.我甚至比较了两种情况下返回的内容,似乎没有区别.
使用COM时,我通常依赖于ATL智能指针,如ATL::CComPtr和ATL::CComBSTR,用于资源管理.但是我正在调用的一些方法使用输出参数来返回指向我必须释放的已分配存储的指针.例如:
WCHAR *pszName = nullptr;
if (SUCCEEDED(pShellItem->GetDisplayName(SIGDN_FILESYSPATH, &pszName))) {
DoSomething(pszName);
CoTaskMemFree(pszName);
}
Run Code Online (Sandbox Code Playgroud)
请注意,GetDisplayName为字符串分配内存并通过输出参数返回指向它的指针.调用者有责任释放内存CoTaskMemFree.
如果DoSomething抛出异常,则上述代码将泄漏.我想使用某种智能指针pszName来避免这种泄漏,但API需要WCHAR**,所以我不知道除了哑指针的地址之外我怎么能传递.由于我不是那个分配,我不能使用RAII.
如果我可以像这样制作一个删除器,我可以使用RRID:
struct CoTaskMemDeleter {
void operator()(void *p) { ::CoTaskMemFree(p); }
};
Run Code Online (Sandbox Code Playgroud)
然后立即将返回的指针分配给标准智能指针,如下所示:
WCHAR *pszName = nullptr;
if (SUCCEEDED(pShellItem->GetDisplayName(SIGDN_FILESYSPATH, &pszName))) {
std::unique_ptr<WCHAR, CoTaskMemDeleter> guard(pszName);
DoSomething(pszName);
}
Run Code Online (Sandbox Code Playgroud)
这样可行,但似乎容易引入额外的保护变量.例如,这种方法pszName指向释放的内存,因此很容易意外地再次使用它.
对于输出参数返回的COM服务器分配的内存,是否有更简洁的方法来使用智能指针或RAII包装器?我错过了ATL提供的东西吗?
这是由我正在研究的另一个问题引发的.阅读可能太长了,所以请耐心等待.
显然,在MSDN CoWaitForMultipleHandles上没有记录的行为.
下面的代码(基于原始问题)是一个控制台应用程序,它启动一个带有测试Win32窗口的STA线程并尝试发布并抽取一些消息.它做了三个不同的测试CoWaitForMultipleHandles,都没有 COWAIT_WAITALL标志.
测试#1旨在验证这一点:
COWAIT_INPUTAVAILABLE如果设置,如果队列输入存在,则对CoWaitForMultipleHandles的调用将返回S_OK,即使已使用对另一个函数(如PeekMessage)的调用看到(但未删除)输入.
这不会发生,CoWaitForMultipleHandles阻塞并且在发出等待句柄之前不会返回.我不认为任何未决的消息应被视为输入(与同MWMO_INPUTAVAILABLE的MsgWaitForMultipleObjectsEx,它按预期工作).
测试#2旨在验证这一点:
COWAIT_DISPATCH_WINDOW_MESSAGES允许从ASTA或STA中的CoWaitForMultipleHandles分派窗口消息.ASTA中的默认值是没有调度的窗口消息,STA中的默认值只是一小部分特殊的消息调度.该值在MTA中没有意义,将被忽略.
这也不起作用.当CoWaitForMultipleHandles仅使用COWAIT_DISPATCH_WINDOW_MESSAGES标志调用时,它会立即返回错误CO_E_NOT_SUPPORTED(0x80004021).如果它是一个组合COWAIT_DISPATCH_WINDOW_MESSAGES | COWAIT_DISPATCH_CALLS,则呼叫阻止但不抽取任何消息.
测试#3演示了我可以CoWaitForMultipleHandles使用调用线程的Windows消息队列的唯一方法.它是一个组合COWAIT_DISPATCH_WINDOW_MESSAGES | COWAIT_DISPATCH_CALLS | COWAIT_INPUTAVAILABLE.这确实是泵送和发送消息,尽管显然它是一种无证件的行为.
测试代码(可立即运行的控制台应用程序):
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleTestApp
{
static class Program
{
// Main
static …Run Code Online (Sandbox Code Playgroud)