我正在使用 IUserNotification2向软件用户显示通知。
我使用 Microsoft 的现有实现,请参见此处。 (请注意,我删除了标准 header 并进行了一些简化)。
#include <Shobjidl.h> //IUserNotification2 interface header
void NotifyUser(const std::wstring &title,
const std::wstring &text){
if (!SUCCEEDED(CoInitializeEx(nullptr, COINIT_MULTITHREADED)))
throw std::exception("could not init COM");
IUserNotification2 * handleNotification = nullptr;
auto result = CoCreateInstance(CLSID_UserNotification, 0, CLSCTX_ALL, IID_IUserNotification2, (void**)&handleNotification);
if (!SUCCEEDED(result) || !handleNotification) {
throw std::exception("could not create CLSID_UserNotification");
}
DWORD notif_flags = NIIF_RESPECT_QUIET_TIME|NIIF_WARNING;
result = handleNotification->SetBalloonInfo(title.c_str(), text.c_str(), notif_flags);
if (!SUCCEEDED(result))
throw std::exception("could not SetBalloonInfo of notification");
if (!SUCCEEDED(handleNotification->Show(nullptr, 5000,nullptr))
throw std::exception("failed Show of notification");
在没有回调的情况下执行此操作(即显示一条消息,但对点击事件没有任何操作)我没有问题,我的代码可以正常工作。
为了添加这样的回调,需要传递一个IUserNotificationCallback。反对 Show IUserNotification2 对象的方法。
看这里,我只更改了对 Show 的调用。
Callback cbk;
if (!SUCCEEDED(handleNotification->Show(nullptr, 5000,& cbk)))
throw std::exception("failed Show of notification");
Callback 类实现了 IUserNotificationCallback。请参阅下面的类的实现。
class Callback : public IUserNotificationCallback {
public:
virtual HRESULT STDMETHODCALLTYPE OnBalloonUserClick(POINT * pt) override {return S_OK;}
virtual HRESULT STDMETHODCALLTYPE OnContextMenu(POINT * pt) override {}
virtual HRESULT STDMETHODCALLTYPE OnLeftClick(POINT * pt) override {return S_OK;}
/// Implementing IUnknown Interface
virtual ULONG STDMETHODCALLTYPE AddRef()override { return 1; }
virtual ULONG STDMETHODCALLTYPE Release() override { return 0; }
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID inRiid, void ** outAddressOfObjectPointer)override {
if (outAddressOfObjectPointer) {
if (inRiid == IID_IUnknown || inRiid == IID_IUserNotificationCallback)
{
*outAddressOfObjectPointer = this;
AddRef();
return NOERROR;
}
}
*outAddressOfObjectPointer = nullptr;
return E_NOINTERFACE;
}
};
是不是当我调用Show方法时,我的IUserNotificationCallback 对象在IUnknown 的QueryInterface 上被调用?界面。采用经典的 COM 风格。但是我收到了 IID_IMarshall 的查询,我通过添加检查了它
else if (inRiid == IID_IMarshal) {
printf("interface queried is IMarshall\n");
在查询接口(interface)方法中。
但是为什么我应该收到这个,文档中没有任何地方提到我应该回答这个 IID。 在这种情况下,我让 E_NOINTERFACE 在 void** 参数中返回一个 nullptr。
我这会导致显示方法失败。
我读了notifu的代码看看是否有帮助,但它与我的基本相同。
显然 Roman R. 提供了一个可行的解决方案.
将对 CoInitializeEx 的调用更改为 if (!SUCCEEDED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED))) 使其有效!
再次感谢
最佳答案
nowhere in the documentation it is mentionned that I should answer to this IID
可能会查询任何 COM 对象以获取对象未知的接口(interface)。这是正常的,更重要的是,COM 对象必须正确响应此操作,然后任何 COM 对象都必须实现 IUnknown 和此方法。
所以你基本上应该将 *ppvObject 设置为 NULL 并返回 E_NOINTERFACE 如果你没有实现接口(interface),否则返回 S_OK 并使用有效指针初始化 *ppvObject,一旦调用者不再需要该指针,就为 IUnknown::Release 调用做好准备。
你的解决方案
Apparently the solution (suggested by a friend) is too always give back the this pointer even when returning
E_NOINTERFACE.
因此是不正确的。如果调用者提供了一个由智能指针管理的变量,然后无论如何都试图释放它,那么有时也可能非常危险。这对于标准编码 OS 代码来说不太可能,因为后者更愿意立即丢弃该值。
如果你这样做,你的实现将是正确的
*outAddressOfObjectPointer = NULL;
if (inRiid == IID_IUnknown)
{
printf("interface required is IUnknown\n");
*outAddressOfObjectPointer = this;
AddRef();
return NOERROR;
}
// ...
NULL 或 nullptr 不会在此处导致失败。但是,您的代码在其他方面也很危险:COM 初始化、Release 调用中的零返回以及本地堆栈支持的回调类实例,该实例在超出范围时被销毁,但稍后仍可能通过公开的接口(interface)调用指针。
现在回到最初的问题,编码在这里到底做了什么?您正在初始化 MTA 线程,并在那里创建单元线程 COM 对象 CLSID_UserNotification。 COM 在侧 STA 线程中为您创建通知 API,然后它尝试将您的回调传递到那里以匹配线程。它必须询问您的 COM 对象是它自己进行编码(marshal)处理,还是需要提供这个东西。您的对象必须说它不会自行编码并且对此一无所知。这就是正在发生的事情。使其成为 COINIT_APARTMENTTHREADED,您将看到不同的画面。
关于c++ - 为什么在 IUserNotificationCallback COM 对象上查询 IMarshall 接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28166791/
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev
我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss