I've recently learned about opaque pointers in C++. I've started using them to hide private members that are platform specific. Such as references to definitions in <windows.h> etc.
Now, I have several systems that build off each other and need to intercommunicate. For example, Direct3D needing a window handle (HWND). I do not want to expose platform definitions to my core system, however my subsystems need to communicate that data.
I'm exposing the opaque data and allowing access through a void pointer. This allows access to all private data.
Example usage (main.cpp):
// System:: namespace is my platform specific code
System::Window window;
System::DirectX::Direct3D9 gfxcontext(window);
Window definition (System/Window.h):
class Window
{
WindowData* data; // Opaque pointer
public:
void* getHandle() const; // returns an HWND handle
Window();
~Window();
}
How to retrieve useful data (Direct3D9.cpp):
#include "Window.h"
Direct3D9::Direct3D9(const Window& _window)
{
HWND windowHandle = *(HWND*)_window.getHandle();
// [...]
pp.hDeviceWindow = windowHandle;
}
However, this code works!:
*(HWND*)_window.getHandle() = 0; // changes HWND in WindowData to NULL!
Is there a way to communicate the platform specific information between subsystems without exposing it to my independent code -and- keeping private data private?
Edit current WindowData implementation
struct Window::WindowData
{
static LRESULT CALLBACK MessageHandler(HWND, UINT, WPARAM, LPARAM);
HWND windowHandle;
WNDCLASSEX windowClass;
HINSTANCE processInstance;
};
The HWND is used by DirectX in the presentation parameters (D3DPRESENT_PARAMETERS::hDeviceWindow)
I would let getHandle (or better getWindowData return a WindowData * instead of a void *. Then let WindowData be just a forward declaration in the "System/Window.h" file.
Inside "Direct3D9", use the fully definition of WindowData, so:
HWND hwnd = _window.getWindowData()->windowHandle;
If at some later stage, you port to Linux, you can have a completely different structure inside WindowData [based on some #ifdef __WIN32/#else type of structure in the implementation side].
Define functionally what you need to do, then implement it in terms of interface. Don't expose (make public) the pointer. Thereafter, implement the interface in terms of the HWND and the platform specific API.
e.g:
struct WindowHandleImpl
{
virtual void show() = 0;
virtual void maximize() = 0;
//etc...
};
struct Win32WinHandleImpl : WindowHandleImpl
{
std::unique_ptr<HWND> handle_; //Use deleter...
virtual void show(); //In terms of HWND, using Win32 API
virtual void maximize();
};
struct XWinHandleImpl : WindowHandleImpl
{
//In terms of platform specific handle.
};
struct Window
{
void show(); //In terms of WindowHandleImpl
void maximize();//In terms of WindowHandleImpl
private:
std::unique_ptr<WindowHandleImpl> pimpl_;
};
Window::Window( const Factory& factory )
: pimpl_( factory.createWindow() )
{
}
//or
Window::Window()
: pimpl_( SystemFactory::instance().createWindow() )
{
}
You can copy the data and return a unique_ptr. Or you can just return an HWND as void* instead of HWND* since it is just a pointer anyway, although that really exploits the implementation. Keep in mind though, others can still change you window somehow over the HWND, and I guess there's not much you can do about it.
Related
I am currently implementing a small soft, I want this soft work on Mac OS and Window OS, so I want use GLFW for Mac environment and Window API for Windows environment (I know GLFW is cross platform but that's not the point..)
My problem is a design implementation problem:
I have created a windowManager class that keeps an instance of a Window class. This Window keeps an instance of an object that is a PatternWindow, where PatternWindow is an interface. I have an object PatternGLFW3_VULKAN that implements PatternWindow. This PatternGLFW3_VULKAN has a member GLFWwindow * _window, and PatternGLFW3_VULKAN initializes _window with glfwCreateWindow(...).
class Window : public Singleton<Window>
{
public:
somefunction(...)
initializePatternWindow(unique_ptr<PatternWindow>&& patternWindow)
unique_ptr<PatternWindow> getPatternWindow(){return _patternWindow;}
private:
unique_ptr<PatternWindow> _patternWindow;
}
class PatternWindow
{
public:
PatternWindow();
virtual ~PatternWindow();
virtual void initialize() = 0;
virtual void destroy () = 0;
};
class PatternGLFW3_VULKAN : public PatternWindow
{
public:
PatternGLFW3_VULKAN ();
~PatternGLFW3_VULKAN();
virtual void initialize();
virtual void destroy();
const GLFWwindow& getWindow() const {return *_window;}
private:
GLFWwindow * _window;
};
My question is about the getWindow() function in my PatternGLFW3_VULKAN class; how I can create a virtual getWindow() function in my PatternWindow class in order to get my GLFWwindow* window of the PatternGLFW3_VULKAN at run time. If I am on Mac OS environment, I can create a virtual function GLFWwindow& getWindow() in my PatternWindow, but if I run my software in a Window environment, the type GLFWwindow of the virtual function getWindow() of the patternWindow class won't be correct...
How can I do in order to have a virtual getWindow() in PatternWindow my that returns GLFWwindow or a instance the Windows API screen at run time ?
EDIT:
class PatternWindow
{
public:
PatternWindow();
virtual ~PatternWindow();
virtual void initialize() = 0;
virtual void destroy () = 0;
virtual /*UNKNOW TYPE AT THE COMPILATION*/ getWindow() = 0;
};
/*UNKNOW TYPE AT THE COMPILATION*/
is my problem I do not know how to deal with it, for getting a GLFWwindow* when i am in Mac OS and Windows instance for the windows API when I am compiling in the Windows environment..
In the main loop of my software in want something like that
int main(int argc, char** argv)
{
//initialisation of all my managers ans the data ect..
while(!WindowClosed(Window::getPatternWindow()->getWindow()))
{
//DO SOME STUFF
}
}
The pattern you are heading towards can be done, but you might regret it later. I would infer from your setup that you have two overloads of WindowClosed() – one whose parameter is a GLFWwindow, and one whose parameter is a WinAPI type. The former would use GLFW methods to detect if the window is closed, while the latter would use the Windows API. One problem is that one of organization: how many files contain GLFW-specific methods? Maybe you even have a file with both GLFW methods and Win API methods? That's not necessarily wrong, but it could be a pain in the long run. Another problem is that this approach diverges from the traditional object-oriented approach.
Still, let's not force you down one path through lack of knowledge. To make this approach work, you could use the preprocessor and a typedef. If compiling for Mac, you would use a line like typedef PatternGLFW3_VULKAN WindowType;. If compiling for Windows, you'd use a line defining WindowType to be the corresponding Windows type. Choosing between these lines would be accomplished via #ifdef WINDOWS (or whatever condition is most appropriate). Then getWindow() could be declared to return WindowType.
A better approach (which you realized in the comments) is to shift the functionality to the window objects. Instead of function(object), use object.function(). This requires more virtual functions in your interface class, but there is a benefit that you have fewer files that are OS-specific.
class PatternWindow
{
public:
PatternWindow();
virtual ~PatternWindow();
virtual void initialize() = 0;
virtual void destroy () = 0;
virtual bool closed () = 0; // <-- New pure virtual function
};
class PatternGLFW3_VULKAN : public PatternWindow
{
public:
PatternGLFW3_VULKAN ();
~PatternGLFW3_VULKAN();
virtual void initialize();
virtual void destroy();
virtual bool closed(); // <-- OS-specific code is no longer in an extra file
private:
GLFWwindow * _window;
};
Then in your main function, the call would be:
while(!Window::getPatternWindow()->closed())
There is a further step you might consider. (The question appropriately does not have enough details to determine if this is a viable option.) You might not need polymorphism for what you are trying to do. Suppose you were to use the following declaration.
class PatternWindow
{
#ifdef WINDOWS // Or whatever test is appropriate
typedef PatternGLFW3_VULKAN * WindowType;
#else
typedef /* Windows API type */ WindowType;
#endif
public:
PatternWindow();
~PatternWindow();
void initialize();
void destroy ();
bool closed ();
private:
WindowType _window;
};
This interface no longer supports polymorphism. Is that a bad thing? Do you need multiple classes derived from PatternWindow under a single operating system? Perhaps not. Here is a potential implementation file for this class.
#include "PatternWindow.h"
#ifdef WINDOWS // Or whatever test is appropriate
#include "PatternWinAPI.src" // <-- File with an implementation based on Win API
#else
#include "PatternGLFW.src" // <-- File with an implementation based on GLFW
#endif
If you don't like the .src extension, use something else. Just don't make those files look like something to be compiled on their own. Each file would have an implementation appropriate for the API it uses. For example, PatternGLFW.src might contain a function definition like the following.
void PatternWindow::initialize()
{
_window = glfwCreateWindow(...);
// Etc.
}
This eliminates the overhead of polymorphism and does not seem to introduce a coding burden. Also, you don't have to keep track of which files are needed for which operating systems (simpler build setup). The organization of PatternWindow.cpp is uncommon, though.
I have asked two questions earlier about this and for each post there was some solutions i tried them, but the problem still exist.
My first question was : why a windowless Activex does not return the Handle. the suggestion was "change the creation setting an make windowless activate off, i have tried it but still m_hWnd property has returned zero as GetSafeHwnd() method has did.
the second one was the same question this one focused on COleControl class and it's ancestor CWnd. the solution was as this "Create invisible window somewhere in your control initialization code. Handle the messages sent to this window, and call controls methods directly". so i did that but the created class still returns zero handle.
here is my new invisible class source:
// moWind.cpp : implementation file
//
#include "stdafx.h"
#include "PINActive.h"
#include "moWind.h"
#include "include\xfspin.h"
#include <math.h>
// moWind
IMPLEMENT_DYNAMIC(moWind, CWnd)
moWind::moWind(){}
moWind::~moWind(){}
//=============================================================
LRESULT moWind::OnExecuteEvent (WPARAM wParam, LPARAM lParam)
{
WFSRESULT *pResult = (WFSRESULT *)lParam;
CString EK=_T("");
CString str;
int reskey=0;
if (pResult->u.dwEventID=WFS_EXEE_PIN_KEY)
{
LPWFSPINKEY pressedkey;
pressedkey=(LPWFSPINKEY)pResult->lpBuffer;
reskey = log10((double)pressedkey->ulDigit) / log10((double)2);
EK.Format("%d",reskey);
xfsOnKeyEvent->OnKeyRecieved(reskey);
}
else
{
str.Format("ExecuteEvent: ID = %d\r\n", pResult->u.dwEventID);
}
MessageBox("a Execute message Recieved");
return 0;
}
BEGIN_MESSAGE_MAP(moWind, CWnd)
ON_MESSAGE(WFS_EXECUTE_EVENT,OnExecuteEvent)
END_MESSAGE_MAP()
and this is .h file of the class:
// moWind.h
class IXFSEvents
{
protected:
IXFSEvents(){};
virtual ~IXFSEvents(){};
public:
virtual void OnKeyRecieved(int key)=0;
};
class moWind : public CWnd
{
DECLARE_DYNAMIC(moWind)
public:
moWind();
virtual ~moWind();
void Register(IXFSEvents* obj)
{
xfsOnKeyEvent= obj;
}
protected:
IXFSEvents* xfsOnKeyEvent;
LRESULT OnExecuteEvent (WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
};
and at the end here this the way I've used this class in my Activex:
in the myActivex.h file:
include "moWind.h"
class CmyActivexCtrl : public COleControl, public IXFSEvents
{
...
Class definition
...
protected:
moWind tmpWind;
.
.
};
finally in the creation method of myActivex i have initialized the component callback method an wanted to get it's Handle as this:
CmyActivexCtrl::CmyActivexCtrl()
{
InitializeIIDs(&IID_DmyActivex, &IID_DmyActivexEvents);
tmpWind.Register(this);
myOtherComponent.WindowsHandle=tmpWind.GetSafeHwnd(); //here my Cwnd derived class returns zero
//my other component gets the handle and call an API with it to register
//the given handle and force the API to send the messages to that handle.
}
As you mentioned you need a window handle to be able to receive user messages through it, you always have an option of creating a helper window, such as message only window, see Using CreateWindowEx to Make a Message-Only Window.
For your windowless control it is okay to not have any window handle at all, so you cannot really rely on handle availability unless you own a window yourself.
I am calling SetTimer in a function of a Class.
SetTimer(NULL, 0, 10000, (TIMERPROC) TimerCallBack);
Where TimerCallBack is:
static VOID CALLBACK TimerCallBack(HWND, UINT, UINT, DWORD)
Now my need is to call one of the method of class which initiated timer, since TimerCallBack is static it has no access to the class object anymore.
I cant find any way to pass object pointer along with the SetTimer so that I can receive it back on Callback function.
Is there any other way to achieve this, if its not supported using SetTimer then which other way I can implement this.
You don't need a map. Use the idEvent parameter. Microsoft gave it the UINT_PTR type so it fits a pointer, even in 64 bits:
SetTimer(hwnd, (UINT_PTR)bar, 1000, MyTimerProc);
void CALLBACK MyTimerProc(HWND, UINT, UINT_PTR idEvent, DWORD)
{
Bar* bar = (Bar*)idEvent;
}
Note that you need to use an actual HWND. If the HWND is null, Windows will generate the idEvent internally.
Obviously, if you were directing timer messages at a window, you could just store the user data with the window.
The only way to do this with a TimerProc is to make a class that manages a statically scoped map of timer-id's to user data objects.
Something like this (As this is a c++ question, Im just implementing a quick and dirty functor type thing so that the TimerMgr can arrange callbacks directly to members of classes, which is usually why you are trying to store user data:
// Timer.h
#include <map>
class CTimer {
public:
class Callback {
public:
virtual void operator()(DWORD dwTime)=0;
};
template<class T>
class ClassCallback : public Callback {
T* _classPtr;
typedef void(T::*fnTimer)(DWORD dwTime);
fnTimer _timerProc;
public:
ClassCallback(T* classPtr,fnTimer timerProc):_classPtr(classPtr),_timerProc(timerProc){}
virtual void operator()(DWORD dwTime){
(_classPtr->*_timerProc)(dwTime);
}
};
static void AddTimer(Callback* timerObj, DWORD interval){
UINT_PTR id = SetTimer(NULL,0,interval,TimerProc);
// add the timer to the map using the id as the key
_timers[id] = timerObj;
}
static void CALLBACK TimerProc(HWND hwnd,UINT msg,UINT_PTR timerId,DWORD dwTime){
_timers[timerId]->operator()(dwTime);
}
private:
static std::map<UINT_PTR, Callback*> _timers;
};
// In Timer.cpp
#include <windows.h>
#include <Timer.h>
std::map<UINT_PTR,CTimer::Callback*> CTimer::_timers;
// In SomeOtherClass.cpp
class CSomeClass {
void OnTimer1(DWORD dwTime){
}
public:
void DoTimerStuff(){
CTimer::AddTimer( new CTimer::ClassCallback<CSomeClass>(this,&CSomeClass::OnTimer1), 100);
}
};
Removing timers from the map is left as an exercise for the reader :)
ClassCallback needed to inherit Callback.
static variables need to be defined
Code now builds and runs correctly on MSVC 9.0
Given that you don't appear to be using MFC (CWnd::OnTimer means you'd have access to the class), and you don't have a HWND (you could conceivably set a property on the HWND on timer-creation and get it back in your proc), there is another option.
SetTimer returns a UINT_PTR which is the timer ID. This is what you'll get in your TimerProc and will also pass to KillTimer when you're done with it. Using this, we can create a map that maps a timer ID to some user-defined object of your creation:
class MyAppData
{
}; // eo class MyAppData
typedef std::map<UINT_PTR, MyAppData*> MyDataMap;
MyDataMap dataMap;
Then we create your timer:
MyAppData* _data = new MyAppData(); // application-specific data
dataMap[SetTimer(NULL, 0, 10000, (TIMERPROC)TimerCallBack)] = _data;
And in your procedure:
static void CALLBACK TimerCallBack(HWND _hWnd, UINT _msg. UINT_PTR _idTimer, DWORD _dwTime)
{
MyAppData* data = dataMap[_idTimer];
} // eo TimerCallBack
There exists one more solution, but in order to use that one - HWND parameter in SetTimer should be non-NULL.
It's possible to store extra data into window itself, using API function SetWindowLongPtr with parameter GWLP_USERDATA.
So you could add into your class following function:
void SetLocalTimer(UINT_PTR nIDEvent, UINT nElapse)
{
SetWindowLongPtr(m_hWnd, GWLP_USERDATA, (LONG_PTR)this);
SetTimer(nIDEvent, nElapse, _TimerRouter);
}
and timer router function, which determines what to do on given timer.
static void CALLBACK _TimerRouter(HWND hwnd, UINT, UINT_PTR nEventID, DWORD)
{
YourClassName* inst = (YourClassName*)GetWindowLong(hwnd, GWLP_USERDATA);
if( !inst )
return;
switch (nEventID)
{
case 0:
inst->DoThis();
break;
case 1:
inst->DoThat();
break;
}
}
This allows also to use nEventID as function identifier to be called.
There still exists a risk that user data will be used from more than one place, but I think it's good practice to keep UI window matching it's class model this pointer.
I currently have a CFolderDialog class that is used in my CDocManagerEx class for handling file operations as follows:
alt text http://img268.yfrog.com/img268/9271/filedialog.png
I don't know if I need to show the method implementation of this class (I found this from a project posted here), but here is the class definition if it helps:
class CFolderDialog
{
friend static int CALLBACK BrowseDirectoryCallback(
HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData);
public:
CFolderDialog( LPCTSTR lpszFolderName = NULL,
DWORD dwFlags = NULL/*BIF_RETURNONLYFSDIRS*/,
CWnd* pParentWnd = NULL);
virtual ~CFolderDialog();
virtual int DoModal();
CString GetPathName() const;
protected:
virtual void OnInitDialog();
virtual void OnSelChanged(ITEMIDLIST* pIdl);
virtual void CallbackFunction(HWND hWnd, UINT uMsg, LPARAM lParam);
void EnableOK(BOOL bEnable = TRUE);
void SetSelection(LPCTSTR pszSelection);
void SetSelection(ITEMIDLIST* pIdl);
void SetStatusText(LPCTSTR pszStatusText);
CString ShortName(const CString& strName);
public:
BROWSEINFO m_bi;
protected:
CString m_strInitialFolderName;
CString m_strFinalFolderName;
TCHAR m_szDisplayName[MAX_PATH];
TCHAR m_szPath[MAX_PATH];
HWND m_hDialogBox;
};
class CMyFolderDialog : public CFolderDialog
{
public:
CMyFolderDialog(LPCTSTR lpszFolderName = NULL,
DWORD dwFlags = NULL,
CWnd* pParentWnd = NULL,
LPCTSTR pszFileFilter = NULL);
virtual ~CMyFolderDialog();
protected:
virtual void OnSelChanged(ITEMIDLIST* pIdl);
protected:
CString m_strFileFilter;
};
My goal of this question is adding an edit control to the window just below the workspace where the directory is selected. What would be the easiest way to accomplish this?
If you just want an edit control that allows the user to type in the name of a directory entry, that is possible. The C++ class you're using is a wrapper round the Win32 SHBrowseForFolder() method, and that method supports having an edit box by setting the BIF_EDITBOX (or better, BIF_USENEWUI) in the ulFlags member of the BROWSEINFO structure.
Looking at the C++ class, it looks like the simplest way to achieve this will be to pass BIF_USENEWUI as the dwFlags member in the constructor call. (Though I'd be tempted to just call SHBrowseForFolder directly and not bother with the C++ class.)
Do note the warning about this flag in MSDN, though: OleInitialize() or CoInitialize() must have been called before bringing up the dialog with this flag.
More generally, if you want an edit control that you can use for your own purposes, allowing the user to enter anything, that's more of a problem: there's no way to extend the dialog used by SHBrowseForFolder() with custom controls. If you want to do that, you'd end up having to re-implement the whole dialog, which isn't a good idea.
Also, as a final note, if you can limit yourself to Vista (and beyond) then there's another way to have a directory selection dialog: use the new IFileDialog COM interface, with the FOS_PICKFOLDERS flag.
Maybe some of the ideas in this will do what you want?
http://www.codeproject.com/KB/dialog/browse_for_folder_dialog.aspx
or this
http://www.codeguru.com/cpp/w-p/files/browserfunctionsdialogs/article.php/c4443
How can I "hide" parts of a class so that whoever is using the libary does not have to include headers for all the types used in my class. Ie take the MainWindow class below, ho can I have it so when compiled in a static/dynamic libary, whoever is useing the libary does NOT have to include windows.h, ie HWND, CRITICAL_SECTION, LRESULT, etc do not have to be defined.
I know I could split it into two classes, an abstract class with just the public interface, and an implementation class which is hidden that contains the members that require windows.h.
The problem here is that the visible class can no longer be created itsself, and an additional create function (eg CreateMainWindow) is required. That is fine in this case since it is most likly that just a single instance created on the heap is wanted but for other classes this is not.
class MainWindow
{
HWND hwnd;
int width, height;
std::string caption;
bool started,exited;
bool closeRequest;
unsigned loopThread;
CRITICAL_SECTION inputLock;
Input *input;
public:
static void init_type();
Py::Object getattr(const char *name);
MainWindow(int width, int height, std::string caption);
~MainWindow();
bool CloseRequest(const Py::Tuple &args);
bool CloseRequestReset(const Py::Tuple &args);
HWND GetHwnd();
int GetWidth();
int GetHeight();
Input* GetInput();
protected:
unsigned static __stdcall loopThreadWrap(void *arg);
unsigned LoopThreadMain();
LRESULT WndProc(UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT static CALLBACK WndProcWrapper(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
};
You can hide parts of a class using the so-called "cheshire cat", "letter/envelope", or "pimpl" technique (which are, all, different names for the same technique):
class MainWindow
{
private:
//opaque data
class ImplementationDetails;
ImplementationDetails* m_data;
public:
... declare your public methods here ...
}
The best way is probably the abstract class mentioned in your 2nd paragraph (however I failed to understand your last sentence, in which you (tried/failed to) explain what your counter-argument to that is).
As you mentioned in your question, using an abstract interface is your best option. Your DLL should have factory methods for creating/destroying instances of your concrete class. I didn't quite get your point about the downside of this.
One way or the other, you have two options:
let the library user's compiler figure out the memory size needed for your data - then the compiler can place it on stack
or allocate the data on the heap for the library user so that the user's compiler does not need to know how big the data are.
Whether you expose (2) via pimpl or MyAbstractObject *o = createMyObject() is not much different.
A third option (a hack so terrible, it's funny) creates a large byte array in the object you expose to the user, and you initialize your real objects in that array using "in-place" new. Please don't do this. I'll go and wash my brains with soap.
This book may give you some ideas:
http://www.amazon.com/Large-Scale-Software-Addison-Wesley-Professional-Computing/dp/0201633620
Large-Scale C++ Software Design
by John Lakos
As has been said before, you want to use a pimpl. I've done it and it works really well. It's totally transparent to the user of your library.