I am reading about prototype pattern by GoF book. Here is the text snippet
Configuring an application with classes dynamically: Some runtime
environments let you load classes into an application dynamically. The
prototype pattern is the key to exploiting such facilities in a
language like C++.
An application that wants to create instances of a dynamically loaded
classes won't be able to reference its constructor statically.
Instead, runtime environment creates an instance of each class
automatically when it's loaded, and registers with a prototype
manager. Then the application can ask the prototype manager for newly
loaded classes, classes that weren't ;omled with the program orginally
My questions on above
What does author mean by "An application that wants to create instances of a dynamically loaded classes won't be able to reference its constructor statically" ? For example if we use dynamic link library I can still create object using new so what does author mean by we won't be able to reference constructor statically?
Request to give an example how prototype pattern is used to exploit load classes application dynamically.
My 50 cents on this :
I believe the author is referring to situations where you don't have the class definitions in the symbols library, however you want to instantiate objects, and pass them to the library consumer functions (so you are the memory owner, the shared library is the consumer , but you don't have access to the concrete classes inside the library )
Example ( I will write one from the top of my head to underline a scenario where it would be useful then I will write another one that I actually bumped into)
Having a dynamic library TextEditorWidgets.dll and your main application , the TextEditorWidget exposes an abstract prototype TEWPrototype , and a factory method of getting certain prototypes according to let's say a string identifier.
Having the factory method exposed from the dll defined as :
TEWPrototype* TEWPrototype::getPrototypeFor(string identifier)
{
TEWPrototype* result;
if (identifier == "SomeWidget")
{
result = ConcreteSomeWidgetPrototype;
} else if ...
return result;
}
Inside your application you can use the following code :
{
vector<TEWPrototype*> allocatedWidgets;
...
TEWPrototype* SomeWidget = TEWPrototype::getPrototypeFor("SomeWidget").clone();// you are now the memory owner
allocatedWidgets.push_back(SomeWidget); // keep for deletion
TextEditorWidgetsHandle->doSomethingWithTheWidget(SomeWidget);// pass the instantiation to the consumer who knows the widget full definition
}
In the example above you have the following pros as the app develoer :
you will control what the dll allocates , when and how
you will control if the widgets get deleted or not through the lifetime of the application
The pros as the dll developer :
you will be able to add new Widgets while providing backwards functionality
you have the guarantee that nobody will use your internal widgets functionality outside the .dll
Practical example :
While working on a game , new entities were created by the game development team, and we needed a fast way to give the Designers the new objects for them to add into the game scene. We had our own in house editor, so we had control over the design tool.
The approach was to have the World Editor load .dlls , then expose in the editor menus what objects were loaded in the dlls. The editor didn't know what classes were inside the dlls, it only knew about them having a draw and a setPosition function (and some other things).
When the dll was loaded , inside the editor, the name of the object was added into an object prototype manager (basically we had a static function getAvailableObjects and after dll load, we would query that in order to get the strings).
When a Designer was choosing from a menu an object (let's say for example Crate), then a new instance of that object was created that was drawn inside the editor , and the designer could move it around.
The editor couldn't instantiate the object by itself because he knew nothing about the size of the object nor about his constructor. However we had pre-instantiated objects for each type, that were getting cloned each time the Artist chosed to create a "new" Crate.
The preinstantiated objects were also used in the preview .
When the development team released a new set of entities , we just provided the new dll to the Designers, and they would only need to "refresh" the editor an BOOM : magic happened : new objects in the menu .
As an alternative, an abstract factory can provide kind of the same functionality.
Related
I have a dialog-based MFC application that hosts CPropertySheet.
The idea is to scan some folder for DLLs, load each of them dynamically (using LoadLibrary()), acquire a pointer to a function that would work like a CPropertyPage factory, use that function to create per-DLL CPropertyPage instances and insert them to CPropertySheet.
In other words, scan a folder for plugins, acquire the per-plugin property pages and insert them to CPropertySheet of the main application so each plugin would have it's own options GUI.
Plugins are implemented in a form of regular MFC dlls (not extension dlls). I'm aware that AFX_MANAGE_STATE(AfxGetStaticModuleState()) is to be employed.
Each CPropertyPage being created must be derived from an abstract interface (say, IPluginOptionsPropPage) so it would be possible to cast the pointer that factory function returns to IPluginOptionsPropPage.
This task is supposed to be a routine one, however, I could not found any sound examples.
Yes it can be done. You can try these steps
Load the property page library using ::LoadLibrary. The return handle is the handle for the resource.
m_hResInstance = ::LoadLibrary(strFile);
Before creating the instance of the property page, set the instance of the resource handle to the library's handle.
m_hCurrent = AfxGetResourceHandle();
AfxSetResourceHandle(hResInstance);
//Create your property sheet here.
Then reset the resource handle to the current process resource.
//Reset the previous
AfxSetResourceHandle(m_hCurrent);
This will enable you to load the resource of the property page, others like header and library or function pointer can be used as intended.
I'm using a QJSEngine to make an application scriptable. I'd like the JavaScript side to be able to modify the user interface. My main issue right now is accessing the Qt API from JavaScript.
To create widgets, I added a createWidget() wrapper that uses QUILoader:
// JavaScript
var w = helpers.createWidget("QPushButton");
// C++
QJSValue helpers::createWidget(QString type)
{
QUILoader ld;
return engine.newQObject(ld.createWidget(type));
}
I've also registered all the enums from qt_getQtMetaObject(), which seems to take care of all the namespace-level enums from qnamespace.h. It doesn't look like it's part of the public API though.
Am I really supposed to this stuff manually or am I missing something? Isn't there a registerAllTheThings() function that creates a global Qt object through which the Qt API available?
If there isn't, then I have a problem. I can create QWidgets with a QUILoader, but I couldn't find a way of creating other objects, such as a QStandardItemModel. I thought all Qt classes would already be registered through qRegisterMetaType(), but they're not: QMetaType::type("QStandardItemModel") fails by returning UnknownType. Again, am I missing some initialization function call that registers everything?
I would recommend using a QQmlEngine instead of the QJSEngine.
Is is derived from QJSEngine so it can do the same things, in the same module so no extra dependencies.
It provides an easy way to register types for instantiation in QML, has a plugin loading mechanism (imports), etc.
I presented that as part of my talk at Qt World Summit 2015: https://www.youtube.com/watch?v=7LsKoVrb8C8
I understand there are functions that can easily write windows registry, however I found out that in new MFC project created with wizard, some information (like split bar position, visibility of controls) gets stored automatically (or at least I found no CWinApp::Write* calls in the project). Since I have also older projects that don't have this behaviour I need to figure out how to make this without help of project wizard. Would anyone please know how does this work?
The MFC control state saving magic happens in the 'New' MFC Feature Pack, specifically in the SaveState methods, for example CMFCToolBar::SaveState.
To take advantage of this you'll therefore need to upgrade your Toolbars and Menus to use the newer controls and upgrade your application to inherit from CWinAppEx. I recommend that you use a New MFC Wizard based app as a guide on how to upgrade your old MFC app.
Most of the information is saved in CPane::SaveState(), thus if you want state of some component saved, you need to use classes derived from CPane. (for more info here is the class hierarchy).
The process of saving window states is initiated through CFrameImpl::OnClosingMainFrame(). This function in turn calls CWinAppEx::SaveState() which saves some application settings and then ALL instances of CMFCToolBar (they add themselves to global list of CMFCToolBars in call to OnCreate). In a similar way all dockable panes are saved but the list belongs to your main frame. Then positioin and size of your main frame is saved.
CViews and CFrameWnds are somewhat less favored, for what I found and tried out, the only information saved was visibility.
I used that loooong time ago. If I correctly reminds it, you should save the informations you want in a overridden CWinApp::ExitInstance() before calling base class method, and you load them in CWinApp::InitInstance. Be sure to allow for default values, because at first run, there will be nothing to load, and do not forget to call (or copy) base class.
I have successfully made a resource only DLL, and placed some dialogs, that were in the main exe. So I have Test.exe, and TestENU.dll. It works fine, but I am trying to find a way to only override some dialogs, instead of being required to have all exactly the same dialogs, and instead pull some from the base exe, as my real project has around 40 dialogs, and I only want to have to translate some, slowly over time.
(I used this link to do satellite/resource dll)
http://msdn.microsoft.com/en-us/library/8fkteez0(v=vs.90).aspx
Default resources (including dialogs) are governed by the current setting of the resource handle. You can set the resource handle at any time using AfxSetResourceHandle to point to a resource only dll, or, your executable. You'll need to be prudent in making sure that the handle is pointing to the correct resource location before instantiating a dialog, so, you'll need to save the current handle before changing it to a new resource handle, and, changing it back when you are done.
Pass a template ID to the constructor of your dialogs.
Constructor:
CTestDlg::CTestDlg(int Template, CWnd* pParent = NULL) : CDialog(Template)
{
...
Call:
int idd;
if (bTestDialogTranslationExists)
idd = IDD_TESTDIALOG_FROM_DLL;
else
idd = IDD_TESTDIALOG;
CTestDialog dlg(idd);
dlg.DoModal();
This code is for demonstration only. You might want to derive a new class from CDialog that handles localized dialog templates automatically, depending on, for example, if the Template exists in a replacement map.
// have this as a global variable or in your CWinApp class
CMap <int, int, int, int> translatedDialogsMap;
// put this maybe in you CWinApp::InitInstance before any dialog could possibly be displayed
translatedDialogsMap[IDD_TESTDIALOG] = IDD_TESTDIALOG_FROM_DLL;
translatedDialogsMap[IDD_TESTDIALOG2] = IDD_TESTDIALOG2_FROM_DLL;
translatedDialogsMap[IDD_TESTDIALOG3] = IDD_TESTDIALOG3_FROM_DLL;
...
// check in your dialog subclass constructor code, if a mapped dll dialog exists
int idd_replaced;
if (translatedDialogsMap.Lookup(Template, &idd_replaced))
Template = idd_replaced;
In 2022 I am in the process of doing the same thing - trying to localize only some resources. Like the author, I am having a very hard time, and the solution has not been found yet. Here's what I can say after reading countless articles on the subject, some making careless statements that cost hours of work just to see that they don't work.
Given : you have an EXE with "default" resources and an extension DLL that replaces only some of then (I specifically tested it on strings so far).
The resource handle (AfxGetResourceHandle()) points to the EXE
If the DLL is properly loaded, it's placed in the search list for resources
The search process is as follows:
a. The resource handle module (EXE) is searched
b. If not found, the extension DLL resources are searched
Given this order, if the EXE has the needed resource, it wins. In our task it always does, so the DLL is as good as not loaded - useless.
Some people suggest setting the DLL module as the resource handle (AfxSetResourceHandle), claming it will reverse the order. DO NOT do it. It will not reverse the order, and here's why.
Doing so will replace the EXE's handle by the DLLs, that's all. It's a one liner in the MFC source. Now the search process will go as follows:
The resource handle (AfxGetResourceHandle()) now points to the DLL
The DLL is searched
If not found, the extention DLL resources are searched again!
This is because extension DLLs are added to a search linked list when loaded, but the EXE (I should say the resource handle that defaults to the EXE) is not! It is handled separately upfront. Replacing the resource handle does nothing to the linked list.
Setting the resource handle to the DLL makes EXE-based resources unavailable, so you end up with only localized resources, and now your program will most likely not start up.
I don't see a way (yet) to add the EXE to this list. The type required is (roughly) "extension DLL", you can't just do a new CDynLinkLibrary call.
What I am thinking is separating out even the default resources into a DLL. That way both DLLs become equal and get added to the search list. The precedence will, I suppose, be governed by the LoadLirary call order, so if you first load the localized DLL and then the "main", you should be OK.
P.S. Creating resources in two languages inside the EXE, while doable, has proven to be a nightmare - it has never worked the way you'd want: first the selected UI language (see SetThreadUILanguage) then, if not found, the main in any language available. Comments on StackOverflow say "make DLLs, it's the only way" without going into details why.
In my C++ code, I create an instance of a Java class through JNI. That Java class's job is to create a WebView dynamically that should go on top of the application's views.
My current strategy is to retrieve the application's main activity, dynamically create a WebView and attach it to the main activity's list of views. Is this possible? Is it better to create an activity?
This functionality is meant for a standalone library that clients can use. So unfortunately it can't be part of the main application's activity.
At minimum, is it possible to retrieve the application's main activity from an unrelated Java class?
In the end, my Java class has a static method Init that is called by my activity to store the reference to the activity. Later, when my C++ code creates an instance of the Java class it retrieves that reference and uses it.