- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在使用 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/
我正在尝试在我的代码库中为我正在编写的游戏服务器更多地使用接口(interface),并了解高级概念以及何时应该使用接口(interface)(我认为)。在我的例子中,我使用它们将我的包相互分离,并使
我有一个名为 Widget 的接口(interface),它在我的整个项目中都在使用。但是,它也用作名为 Widget 的组件的 Prop 。 处理此问题的最佳方法是什么?我应该更改我的 Widget
有一个接口(interface)可以是多个接口(interface)之一 interface a {x:string} interface b {y:string} interface c {z:st
我遇到了一种情况,我需要调用第三方服务来获取一些信息。这些服务对于不同的客户可能会有所不同。我的界面中有一个身份验证功能,如下所示。 interface IServiceProvider { bool
在我的例子中,“RequestHandlerProxy”是一个结构,其字段为接口(interface)“IAdapter”,接口(interface)有可能被调用的方法,该方法的输入为结构“Reque
我有一个接口(interface)Interface1,它已由类A实现,并且设置了一些私有(private)变量值,并且我将类A的对象发送到下一个接受输入作为Interface2的类。那么我怎样才能将
假设我有这样的类和接口(interface)结构: interface IService {} interface IEmailService : IService { Task SendAs
有人知道我在哪里可以找到 XML-RPC 接口(interface)的定义(在 OpenERP 7 中)?我想知道创建或获取对象需要哪些参数和对象属性。每个元素的 XML 示例也将非常有帮助。 最佳答
最近,我一直在阅读有关接口(interface)是抽象的错误概念的文章。一篇这样的帖子是http://blog.ploeh.dk/2010/12/02/InterfacesAreNotAbstract
如果我有一个由第三方实现的现有 IInterface 后代,并且我想添加辅助例程,Delphi 是否提供了任何简单的方法来实现此目的,而无需手动重定向每个接口(interface)方法?也就是说,给定
我正在尝试将 Article 数组分配给我的 Mongoose 文档,但 Typescript 似乎不喜欢这样,我不知道为什么它显示此警告/错误,表明它不可分配. 我的 Mongoose 模式和接口(
我有两个接口(interface): public interface IController { void doSomething(IEntity thing); } public inte
是否可以创建一个扩展 Serializable 接口(interface)的接口(interface)? 如果是,那么扩展接口(interface)的行为是否会像 Serilizable 接口(int
我试图在两个存储之间创建一个中间层,它从存储 A 中获取数据,将其转换为相应类型的存储 B,然后存储它。由于我需要转换大约 50-100 种类型,我希望使用 map[string]func 并根据 s
我正在处理一个要求,其中我收到一个 JSON 对象,其中包含一个日期值作为字符串。我的任务是将 Date 对象存储在数据库中。 这种东西: {"start_date": "2019-05-29", "
我们的方法的目标是为我们现有的 DAO 和模型类引入接口(interface)。模型类由各种类型的资源 ID 标识,资源 ID 不仅仅是随机数,还带有语义和行为。因此,我们必须用对象而不是原始类型来表
Collection 接口(interface)有多个方法。 List 接口(interface)扩展了 Collection 接口(interface)。它声明与 Collection 接口(int
我有一个 Java 服务器应用程序,它使用 Jackson 使用反射 API 对 DTO 进行一般序列化。例如对于这个 DTO 接口(interface): package com.acme.libr
如果我在 Kotlin 中有一个接口(interface): interface KotlinInterface { val id: String } 我可以这样实现: class MyCla
我知道Java中所有访问修饰符之间的区别。然而,有人问了我一个非常有趣的问题,我很难找到答案:Java 中的 private 接口(interface)和 public 接口(interface)有什
我是一名优秀的程序员,十分优秀!