C++ DLL: Not exposing the entire class - c++

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.

Related

What's wrong with my attempt at subclassing CButton?

I tried to create a subclassed control for the first time, but I feel like I did something wrong. The control is a Button, which I placed in the designer. This is its class:
class TTTField : public CButton
{
public:
BEGIN_MSG_MAP_EX(TTTField)
MSG_WM_INITDIALOG(OnInitDialog);
END_MSG_MAP()
TTTField operator=(const CWindow& btn);
private:
const BOOL OnInitDialog(const CWindow wndFocus, const LPARAM lInitParam);
};
Nothing fancy so far.
However, I can't really achieve to receive windows messages in this control. This is bad, considering the main reason for trying to subclass a control was the fact that this should be a reusable class with reusable, custom Paint behaviour. I want to overwrite certain message handlers, while keeping those I didn't explicitely ask for to the usual CButton routine.
As you can see, I implemented a message map, but the messages are just not coming in.
This is how I tried to setup the instance of this class:
TTTField fld;
is a member variable of my main dialog class. In this class I added the following DDX_MAP:
BEGIN_DDX_MAP(TTTMainDialog)
DDX_CONTROL_HANDLE(IDC_BTN, fld)
END_DDX_MAP()
with IDC_BTN being the id of the button on the designer.
In the assignment operator overload for TTTField I have the following:
TTTField TTTField::operator=(const CWindow& btn)
{
Attach(btn);
return *this;
}
I feel like this operator overload might be the source of my problems, but I just can't manage to find a website which is properly explaining the whole topic without using code which seems outdated for like 20 years.
What am I doing wrong here? I am really lost right now.
The button class should be defined as follows:
class TTTField : public CWindowImpl<TTTField, CButton>
{
protected:
BEGIN_MSG_MAP_EX(TTTField)
MSG_WM_LBUTTONDOWN(OnLButtonDown)
END_MSG_MAP()
protected:
LRESULT OnLButtonDown(UINT, CPoint)
{
//Edit: this override is meant for testing the subclass only
//it's insufficient for handling button clicks
MessageBox(L"Testing override...");
return 0;
}
};
Override dialog box's OnInitDialog, call SubclassWindow to subclass the button:
class TTTMainDialog: public CDialogImpl<CMainDialog>
{
public:
enum { IDD = IDD_MYDIALOG };
BEGIN_MSG_MAP(TTTMainDialog)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
END_MSG_MAP()
TTTField fld;
LRESULT OnInitDialog(UINT nMessage, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
fld.SubclassWindow(GetDlgItem(IDC_BTN));
return 0;
}
};
Edit, for initialization
class TTTField : public CWindowImpl<TTTField , CButton>
{
public:
void Create(CWindow *wnd, int id)
{
SubclassWindow(wnd->GetDlgItem(id));
//add initialization here
}
...
}
Then to create the button:
//fld.SubclassWindow(GetDlgItem(IDC_BTN));
fld.Create(this, IDC_BTN); //<== use this instead
Perhaps the best example, or at least one of, of subclassing a button is right in the sources of WTL, at the top of atlctrlx.h:
template <class T, class TBase = CButton, class TWinTraits = ATL::CControlWinTraits>
class ATL_NO_VTABLE CBitmapButtonImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >
{
public:
DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
...
You will also file external resources on this class: Using WTL's CBitmapButton.
That's not to mention WTL's comment on doing the controls:
// These are wrapper classes for Windows standard and common controls.
// To implement a window based on a control, use following:
// Example: Implementing a window based on a list box
//
// class CMyListBox : CWindowImpl<CMyListBox, CListBox>
// {
// public:
// BEGIN_MSG_MAP(CMyListBox)
// // put your message handler entries here
// END_MSG_MAP()
// };
More examples of simple and sophisticated custom WTL controls can be found at viksoe.dk.
A confusing thing about WTL control extension is that basic classes like CButton, CComboBox are thin wrappers over standard controls. They mostly translate methods into messages to be sent. You can often easily cast instances of such classes to HWND and back.
Standard controls themselves offer a level of customization through support of notification messages.
When you subclass a control, you are adding functionality on your side which somehow needs to interoperate with stock implementation, and control classes are no longer thin wrappers. Hence, you inherit from CWindowImpl and not CButton directly. Next challenge is to specifically subclass: you need to have original window created and after that, having a HWND handle, you modify it to route the messages through your message map. This is where you need SubclassWindow method. That is, you have the control created, you look it up its handle, e.g. with GetDlgItem and then you subclass the window using your class instance SubclassWindow call. Or, alternatively you can create the control using your new class Create method in which case CreateWindow and association with your message map will be done for you.
Some, more complicated, implementations of custom controls will also want you to reflect notification messages from parent window to the controls, so that they could handle them within the same custom control class. This will typically require that you add a line REFLECT_NOTIFICATIONS in your dialog class message map (see this related question on this).

Using singleton with proxy pattern together and losing both?

I am passing a callback function to a library. What the callback essentially does is receive updates from the dll and send it to GUI to display. The problem is that since the callback is global or static function, it doesn't know about the GUI and who to pass which in my case will be dialog. The approach I have used to accomplish this is to use singleton and a proxy (sort of).
class CDispatcher
{
public:
CDispatcher(void);
~CDispatcher(void);
protected:
static HWND m_hWnd;
public:
static void SetWindow( HWND hWnd );
static void Dispatch(int code, char * msg);
};
Later in the code
BOOL CTestDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// I need to set this before I set callback
CDispatcher::SetWindow( m_hWnd );
//now I can set the callback
LibRegisterCallback( CDispatcher::Dispatch );
return TRUE; // return TRUE unless you set the focus to a control
}
While this works but first I don't know if my CDispatcher class is good module. It doesn't seem like a good singleton neither it looks like a good proxy. Maybe I could pass the handle of the window in constructor which would make it better but I don't if that's even possible since I am never instantiating the singleton. Another thing is I never how to instantiate CDispatcher because again its just a all global members.
Is this a case where proxy design pattern can be applied in a better way (I am guessing in conjuction with singleton)? Maybe another pattern solves this problem more elegantly? Or is my implementation fine?

C++ Communicating private data from opaque pointer

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.

Passing User Data with SetTimer

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.

How do I add an edit box to MFC CFolderDialog ("browse for folder" dialog)?

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