Callback using CustomWndProc for Message Only Window Handle - winapi

I am developing a NPAPI plugin using firebreath. I am using a third party dll to integrate to a gaming device.The inputs on the devices are propagated to the plugin through a message only window(HWND) registered while opening a channel to the device.
Initially, handshake with the device driver,
handshake(HWND,...) and after which on user input, a callback is made on CustomWinProc() to notify.
I did the following,
-Created an Header&CPP file under the WIN-CustomCallbackHandler.h ,
#include "Win\PluginWindowWin.h"
#include "Win\WindowContextWin.h"
class CustomCallbackHandler : public FB::PluginWindowWin
{
public:
CustomCallbackHandler (const FB::WindowContextWin& ctx);
protected:
virtual bool CustomWinProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM
lParamm,LRESULT & lRes);
};
-CustomCallbackHandler.cpp
[code]
#include "CustomCallbackHandler.h"
#include "PluginWindowForwardDecl.h"
#include "Win\WindowContextWin.h"
#include "Win\PluginWindowWin.h"
CustomCallbackHandler::CustomCallbackHandler(const FB::WindowContextWin& ctx) :
FB::PluginWindowWin(ctx){
}
bool CustomCallbackHandler::CustomWinProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM
lParamm,LRESULT & lRes){
//if WPARAM is something some operation has to be performed.
return false;
}
[/code]
-Factory.cpp - Added the following method to override the PluginWindowWin
FB::PluginWindowWin* createPluginWindowWin(const FB::WindowContextWin& ctx)
{
return new CustomCallbackHandler(ctx);
}
-MyFirstPluginAPI.cpp-(The auto generated JSAPIAuto subclass)- JS method.
bool MyFirstPluginAPI::handshake(FB::JSObjectPtr &callback)
{
FB::WinMessageWindow window;
thirdpartymethod(window.getHWND());
}
Now,When I debug I could see the customcallbackhandler being invoked a couple of times for the regular plugin events but the events generated by the devices are not available.I believe a different instance of message window is passed on to the dll.
-How do I get the handle of the PluginWindowWin?
-Once I receive a callback on the CustomCallbackHandler,How do I generate a custom sendEvent()?
Your help is highly appreciated.
I am a Java developer and don't have much experience in C++ programming. I believe I am missing something fundamental.

What you want is to use WinMessageWindow:
https://github.com/firebreath/FireBreath/blob/master/src/PluginCore/Win/WinMessageWindow.h
You don't want to use PluginWindowWin; that's too specific for other things. WinMessageWindow was created specifically to do the types of things you are trying to do, and it allows you to make a winproc handler on the containing class.
I recently posted an example of using WinMessageWindow in order to receive WM_DEVICENOTIFY messages; I'm sure you can use it as an example of how the class works to get you started.

Related

wxTimer not calling overriden Notify()

I'm running into an issue where I implemented a derived wxTimer class to override the Notify() call since I'm not using an owner implementation as described in the documentation.
When I debug the run, I can see
the timer is being instantiated
my_timer_instance->IsRunning() returns true
MyTimer::Notify() is never called
This leads me to believe that the timer is being set and running, but when it expires it's calling the base class Notify() procedure and not my override it's not calling notify() but I'm not sure why.
EDIT: I added frame->getTimer()->Notify(); to my app and the correct procedure was called. Therefore, the timer just isn't calling Notify when it expires.
EDIT2: Added this minimal working example, and the timer works as expected. I'll try to compare the two and see what the problem is.
MyApp.hpp
#pragma once
#ifndef __NONAME_H__
#define __NONAME_H__
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/statusbr.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/string.h>
#include <wx/frame.h>
#include <wx/timer.h>
///////////////////////////////////////////////////////////////////////////
class MyTimerClass : public wxTimer
{
wxFrame* MyFrame;
public:
MyTimerClass(wxFrame* frame): MyFrame(frame) {};
void Notify() override;
};
///////////////////////////////////////////////////////////////////////////////
/// Class MyFrame1
///////////////////////////////////////////////////////////////////////////////
class MyFrame1 : public wxFrame
{
private:
protected:
wxStatusBar* m_statusBar1;
MyTimerClass* MyTimer;
public:
void StartTimer(int TimeInSeconds);
MyFrame1(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(500, 300), long style = wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL);
~MyFrame1();
};
#endif //__NONAME_H__
MyApp.cpp
#include "MyApp.hpp"
#include "wx/wxprec.h"
// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
///////////////////////////////////////////////////////////////////////////
void MyTimerClass::Notify()
{
MyFrame->SetStatusText("Timer popped", 0);
}
MyFrame1::MyFrame1(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxFrame(parent, id, title, pos, size, style)
{
MyTimer = new MyTimerClass(this);
this->SetSizeHints(wxDefaultSize, wxDefaultSize);
m_statusBar1 = this->CreateStatusBar(1, wxSTB_SIZEGRIP, wxID_ANY);
this->Centre(wxBOTH);
this->StartTimer(5);
}
void MyFrame1::StartTimer(int TimeInSeconds)
{
SetStatusText("Timer started with " + std::to_string(TimeInSeconds) + " seconds.");
MyTimer->Start(TimeInSeconds * 1000);
}
MyFrame1::~MyFrame1()
{
}
// ----------------------------------------------------------------------------
// resources
// ----------------------------------------------------------------------------
// the application icon (under Windows it is in resources and even
// though we could still include the XPM here it would be unused)
#ifndef wxHAS_IMAGES_IN_RESOURCES
#include "../sample.xpm"
#endif
// ----------------------------------------------------------------------------
// private classes
// ----------------------------------------------------------------------------
class MyApp : public wxApp
{
public:
virtual bool OnInit() wxOVERRIDE;
};
enum
{
// menu items
Minimal_Quit = wxID_EXIT,
Minimal_About = wxID_ABOUT
};
wxIMPLEMENT_APP(MyApp);
bool MyApp::OnInit()
{
// call the base class initialization method, currently it only parses a
// few common command-line options but it could be do more in the future
if (!wxApp::OnInit())
return false;
// create the main application window
MyFrame1 *frame = new MyFrame1(NULL, -1, "Test Frame");
frame->Show(true);
return true;
}
#BobbyTables,
From the documentation:
This member should be overridden by the user if the default
constructor was used and SetOwner() wasn't called.
Is it the case?
Nothing seems to be wrong in the code you show (although I'd change a few things, such as using raw pointer for my_timer_instance), so the problem must be elsewhere. As usual, the best would be to come up with a SSCCE, without it I can only offer some guesses as to what the problem actually is.
Are you running the event loop? The timers will only fire when it's running, so if you block doing some computation, this wouldn't happen.
Also, what is frame in Notify()? Is this a global (I'd rather pass it as parameter to MyTimer ctor)?
So after mimicking the code provided in the question, the following changes were made:
Instead of using a getter and setter to access the private timer member, I instead use
void refreshTimer(int time_in_seconds) in my parent frame class and create the timer in the parent frame's constructor rather than letting the app create it and pass it in.
I don't see why either of those two things would change the behavior of the timer but the timer now works as expected. I apologize for not being able to identify a concrete bug as the source of the problem.
NOTE: This behavior was caused by the timer being invoked outside the wxwindow's thread. Be careful when creating multithreaded programs using wxwidgets as a GUI. To circumvent this issue since I needed the timer to be invoked in a different thread, I created my own timer class that works correctly.

C++/CLI unhandled exception passing 3 or more parameters to delegate

Just stumbled upon strange behavior.
I have an unmanaged class (actually wrapper around some native lib):
//.h
class Wrapper
{
private:
void(*pCallback)(int, int /*, int*/);
public:
void SetCallback(void(*callback)(int, int /*, int*/));
void InvokeCallback();
};
//.cpp
void Wrapper::SetCallback(void(*callback)(int, int /*, int*/))
{
pCallback = callback;
}
void Wrapper::InvokeCallback()
{
pCallback(0, 0 /*, 0*/); //(1)
//(3)
}
And managed class which is winforms control and uses unmanaged wrapper described above:
public ref class MineControl : public System::Windows::Forms::Control
{
private:
Wrapper *pWrapper;
delegate void CallbackDelegate(int, int /*, int*/);
public:
MineControl()
{
/* rest of initialization here */
pWrapper = new Wrapper;
auto dlg = gcnew CallbackDelegate(this, &MineControl::Method);
auto ptr = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(dlg);
void(*callback)(int, int /*, int*/) = (void(*)(int, int /*, int*/))(ptr.ToPointer());
pWrapper->SetCallback(callback);
pWrapper->InvokeCallback();
}
void Method(int a, int b /*, int c*/)
{
//some code or even nothing at all
//(2)
}
}
This works fine.
Until I uncomment third parameter. After that I put breakpoint on (1). I can enter to MineControl::Mehod - (2). But everything fails on exiting this method. Point (3) become unreachable. I'm getting unhandled exception on exiting that method. Moreover being attached, VS still cannot handle that exception (all settings to debug unmanaged and managed code are set - this is the only case VS cannot catch exception). So Windows tries to handle it - standard App has stopped working window with two options - Debug and Close program. But I cannot debug because VS is still attached and either do not want to detach or app dies on VS detach.
I can wrap all parameters into some structure and this will work well. However can someone explain me why adding third parameter makes it impossible to get back from managed to unmanaged code?
I have no idea what is going on.
Environment: VS2013, x86 project, .net4.5
Ok, I'll post answer by myself. Solution is actually in Hans's comment.
Default calling convention is sdtcall but in my case I need cdecl calling convention.
Decorating delegate with [UnmanagedFunctionPointer(CallingConvention.Cdecl)] attribute solved my problem.
There is also а valuable note that keep delegate in a local variable is a bad idea.

Splitting the main message map (BEGIN_MSG_MAP_EX) into two files

I'm experimenting with WTL, and I'd like to separate a large message map to two or more files. For example, I'd like to move the tray icon logic into a separate file. I'm aware of CHAIN_MSG_MAP and CHAIN_MSG_MAP_MEMBER, but what should I use in this case?
Also, how will I be able to access the window handle from the second class?
You may be looking for something like this (not tested; my WTL is rather rusty; caveat emptor).
class TrayIconHandler : public CWindow, public CMessageMap {
public:
BEGIN_MSG_MAP(TrayIconHandler)
// Message handlers to taste
END_MSG_MAP()
};
class MainWindow : public CWindowImpl<MainWindow> {
public:
BEGIN_MSG_MAP(MainWindow)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
// Other message handlers
CHAIN_MSG_MAP_MEMBER(tray_icon_)
END_MSG_MAP()
LRESULT OnCreate(UINT, WPARAM, LPARAM, BOOL&) {
tray_icon_.m_hWnd = m_hWnd;
}
private:
TrayIconHandler tray_icon_;
};
The two classes may be in different source files and/or headers, of course.

(MFC) How can a parent class receive a control's messages if the control is a private member?

Let's say my main class has a private member that is a class derived from a CTreeView control. How can I handle the messages from this tree view control on the main class itself?
This is similar to the MDI base application that Visual Studios builds for you, where you have two dockable tree view controls named CClassView and CFileView and each has a private member that's derived from CTreeView.
Can I pass the message from the child member control CViewTree to my CFileView class with like this?
void CViewTree::OnTvnSelchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
GetParent()->SendMessage(WM_NOTIFY, 0, (LPARAM)pNMHDR);
}
This code throws an exception, but if this does work, how would I handle the TVN_SELCHANGED message in the parent class?
Edit:
So I've tried the following suggestions but haven't had much luck with either one.
//First try, in the parent .h file:
afx_msg BOOL OnSelChange(NMHDR *pNMHDR, LRESULT *pResult);
//In the .cpp file:
ON_NOTIFY_REFLECT_EX(TVN_SELCHANGED, OnSelChange)
//and
BOOL ParentClass::OnSelChange(NMHDR *pNMHDR, LRESULT *pResult)
{
AfxMessageBox(L"in handler");
Return TRUE;
}
Second try:
//in the parent .h file:
afx_msg void OnSelChange(NMHDR *pNMHDR, LRESULT *pResult);
//In the .cpp file:
ON_NOTIFY(TVN_SELCHANGED, AFX_IDW_PANE_FIRST, OnSelChange)
//and
void ParentClass::OnSelChange(NMHDR *pNMHDR, LRESULT *pResult)
{
AfxMessageBox(L"in handler");
}
Not sure why you want to do this, you have less code reusability as you have a tight coupling between the view and the parent. If you want to reuse the selection logic, you can extract it out into a separate class like the DRAWCLI sample does.
TVN_SELCHANGED is already sent to the parent. However MFC's message reflection routes the notification to the child window's message map when ON_NOTIFY_REFLECT is present in the child.
If you want the parent to have a say in the message processing as well, you can change ON_NOTIFY_REFLECT to ON_NOTIFY_REFLECT_EX and return FALSE in the reflected message handler.
You will get a WM_NOTIFY at the parent so the way you handle the notification is to add a ON_NOTIFY macro to the parent of the tree view like you normally do for a tree control on a dialog. The view's id is likely AFX_IDW_PANE_FIRST if you haven't specified one.
Sheng was able to figure out my problem, which looking back now was quite trivial. Maybe this will help others who might have the same question.
In the MDI w/ visual studio style program that I generated from Visual Studio 2010, the CFileView has a child member instance of CViewTree. CViewTree was derived from CTreeCtrl.
By default, MFC is already passing the messages up the child-to-parent chain. The answer is determining the control ID to get notification messages from in your parent class.
So, first things first, we need to know the ID of the tree control. In the OnCreate method of CFileView, you can see this code:
if (!m_wndFileView.Create(dwViewStyle, rectDummy, this, 4))
MSDN has the following for the Create method:
virtual BOOL Create(
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
UINT nID
);
In my example, the id is 4. Now in the parent (CFileView in this case), just create your ON_NOTIFY macro as such:
BEGIN_MESSAGE_MAP(CFileView, CDockablePane) //precreated for you
ON_NOTIFY(TVN_SELCHANGED, 4, OnSelChanged) //you create this
END_MESSAGE_MAP() //precreated for you
I had to type the line above by hand because the class wizard or message property for the parent didn't have a =TVN_SELCHANGED message. Next, make sure your handler method OnSelChanged is declared in the CFileView.h file as:
afx_msg void OnSelChanged(NMHDR *pNMHDR, LRESULT *pResult);
Now I'm able to handle the TVN_SELCHANGED message like this (back in the CFileView.cpp):
void CFileView::OnSelChanged(NMHDR *pNMHDR, LRESULT *pResult)
{
HTREEITEM item = m_wndFileView.GetSelectedItem();
AfxMessageBox(m_wndFileView.GetItemText(item));
}
In the described case if you want to notify parent CFileView from control CViewTree with WM_NOTIFY TVN_SELCHANGED message, you should do it in virtual OnNotify function, not using message map. If OnNotify doesn't met correct handler, message would go to parent CMainFrame, and there you can use message map.
BOOL CFileView::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
if (nmHdr->idFrom != 4)
return CDockablePane::OnNotify(wParam, lParam, pResult);
if (nmHdr->code == TVN_SELCHANGED)
{
OnItemsSelChanged((NMHDR*)lParam, pResult);
return TRUE;
}
return FALSE;
}

Make IWebBrowser2 Control safe for scripting

I'm using IWebBrowser2 control in my application to display external web pages.
The problem is that the object is not safe for scripting and calls to get_Document fails (with S_FALSE as return value).
I've implemented a new class, IScriptableWebBrowser2 that inherits both from IWebBrowser2 & IObjectSafety, and tried to use it instead of IWebBrowser2 but that didn't do the trick.
How do I make my IWebBrowser2 control safe for scripting ?
class IScriptableWebBrowser2 :
public CComObjectRootEx<CComSingleThreadModel>,
public IWebBrowser2,
public IObjectSafety
{
BEGIN_COM_MAP(IScriptableWebBrowser2)
COM_INTERFACE_ENTRY(IObjectSafety)
END_COM_MAP()
// IObjectSafety implementation
STDMETHODIMP GetInterfaceSafetyOptions(REFIID riid,
DWORD *pdwSupportedOptions,
DWORD *pdwEnabledOptions )
{
*pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER |
INTERFACESAFE_FOR_UNTRUSTED_DATA;
*pdwEnabledOptions = *pdwSupportedOptions;
return S_OK;
}
STDMETHODIMP SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions)
{
return S_OK;
}
};
I guess you created the browser in a thread and passed it on to another thread.
If that's the case, here's what you should do:
Before passing the IWebBrowser2 instance to another thread, in the creating thread, call CoMarshalInterThreadInterfaceInStream, that will marshal (convert) it to a thread-safe IStream object, and only then pass it to the tagert thread.
Later, in the target thread, you should call CoGetInterfaceAndReleaseStream with the previously marshaled IStream instance, which will unmarshal it back to your original object in the target thread (and release the IStream object along the way).
CoMarshalInterThreadInterfaceInStream in MSDN
CoGetInterfaceAndReleaseStream in MSDN
Hope that helps.
Well, I finally had some time to come back to this one..
It turns out that get_Document fails if you call it BEFORE the page completely loaded but the return value (S_FALSE) indicates a completely different error ("not safe for scripting")
btw, Loading local pages will give you the desirable behavior.
Therefore, calling get_Document after the page was loaded (DISPID_NAVIGATECOMPLETE2, DISPID_DOWNLOADCOMPLETE, DISPID_DOCUMENTCOMPLETE) will do the trick.
Hope this helps.

Resources