The primary purpose of OWLNext is to support maintenance of legacy OWL applications. See Features for some advice on who should and shouldn't use OWLNext. Also note License issues.
Over the years, there have been many common queries in the mailing list and discussion forums. You can search the archives for answers to your question. If no answer is found, ask the question in our Open Discussion forum. Also, make sure that you browse our wiki, especially the Knowledge Base, for in-depth information.
Yes, but you need to be logged in, and you need editor rights. Then just click the "edit" icon at the top of this page. If you do not already have editor rights, then ask the administrators to be promoted, e.g. on the forums. However, please do not add unanswered questions, only topics that you have regularly answered yourself or issues that you are familiar with. Good places to ask questions are the forum and the mailing list. You can also comment on this FAQ at the bottom of the page.
If you run into a problem, then try to categorise the issue before reporting it. Is it a OWLNext installation problem? Is it a compiler or tools issue? Is it a OWLNext bug? Or is it an issue particular to your application?
For OWLNext installation and compiler issues make sure you read our installation guide thoroughly, including the sections on how to set up your development environment, and test the installation using the provided examples. Read the trouble-shooting section in this FAQ to identify other problems.
If you have clearly identified an OWLNext bug, you can report it directly in our bug tracker. Make sure you read our guidelines for Submitting Bugs and Feature Requests. When submitting a bug, you may also attach a patch to fix the issue.
If the issue is particular to your application, or you remain unsure about the nature of the problem, then use our Open Discussion forum to request help. Please include as much information as possible, including the versions of OWLNext and compiler tools you are using, as well as all relevant details about the problem. It is especially helpful if you tell us what resolutions you have already tried and the information you've already read (such as this FAQ), so that we do not need to respond with redundant advice.
Whenever possible, try to reproduce the problem in a minimal test case, and include the complete code in your post (alternatively, provide a download link).
The wiki Main Page contains links to the latest releases and their change lists on the right. These link to the page OWLNext Stable Releases where you'll find sections for all the releases and their revisions. These sections just give a summary of the most interesting changes, but have links to the relevant tickets and milestones in the issue trackers; Bugs and Feature Requests. For overview, see the Bugs Milestones and Feature Requests Milestones. For the full details, you can follow links from the wiki and trackers to the Code repository, which gives you the detailed Code Log for any branch.
Yes. Currently, we have three LTS versions: 6.30, 6.36 and 6.44.
In the 6.30 series, OWLNext 6.30 and 6.36 are the last versions that support Borland C++ 5.02 and 5.5, respectively, and these LTS versions are maintained as stepping stones for users upgrading to OWLNext from Borland C++ and OWL 5. In particular, OWLNext 6.36 has support for the latest compilers added regularly (see Supported Compilers), so that users can easily transition to modern tools, and then upgrade from 6.36 to the latest version of OWLNext. See Upgrading from OWL → Recommended step-by-step approach.
In the 6.40-series, OWLNext 6.44 is currently maintained as an LTS version with extensive backwards compatibility and support for older compilers, for those unable or unwilling to make the jump to later versions of OWLNext based on modern C++.
See License on the main wiki page. There should also be a license text in your full installation of OWLNext.
No, unfortunately, you can not. OWLNext is built on top of OWL which requires its own license.
The simplest way to get an OWL license is to buy a copy of some product that includes OWL, i.e. Borland C++ or C++Builder. Otherwise, you may try to contact the copyright holder and ask for a license. See Prerequisites in the installation guide.
Any conditions set by the copyright holder should be respected. This is both the courteous and legal approach.
We require all contributors to only submit work under terms compatible with our overall open source license. However, our library consists of some very old code, some of which contains additional terms that we now consider to be archaic and outdated. Unfortunately, we have not been able to get in contact with all of the original authors to obtain permission to remove these additional terms from the source code.
For further discussion of these licensing issues, see [bugs:#527].
No, it is not. OWLNext depends on OWL which has a proprietary license.
But that is not the whole story. If you just want to choose a GPL license for your own work, you can do so, even if your work depends on OWLNext. You just have to add an exception for OWLNext in the license text. Although that is fine, the Free Software Foundation discourages you from doing so.
See: Can I write free software that uses non-free libraries?
It gets more complicated if you want to use other GPL work, e.g. a library, in your OWLNext application; or if you want to extend other GPL work by adding functionality dependent on OWLNext. The GPL for that other work will restrict you from creating a "combined work" that depends on non-GPL components. You will then have to get an exception for OWLNext from the copyright holders of that work.
See: What legal issues come up if I use GPL-incompatible libraries with GPL software?
Finally, note that the license for the OWLNext patches is fully GPL compatible. Of course, they are rarely useful on their own.
If you are new to OWLNext, then you should first read the article Upgrading from OWL. This article will give you some insight into what changes are required to your legacy OWL code to use OWLNext. If after reading this article you feel ready to upgrade, then you should proceed to install OWLNext. Our installation guide contains detailed step-by-step instructions. Follow them closely. When you have OWLNext properly set up, then return to the article Upgrading from OWL as you adapt your code. You may also want to study the Knowledge Base and browse the other questions and answers in this FAQ. Should you run into problems you cannot find the answer to, you can ask for help in our Open Discussion forum. Hopefully, someone will come to your rescue.
Finally, when you are up and running with OWLNext, feel free to write a review of your experiences.
We use the Subversion system for source code version control. All our code is stored in a Subversion code repository (data base). The code repository contains a history of the changes to the source code. Every change to the repository, big or small, is recorded as a "revision" and given a unique number. A revision number hence marks the state of the repository at some point in history.
The structure of the code repository follows the standard Subversion convention with three main directories: "trunk", "branches" and "tags". The trunk contains the main code under development, while the branches and tags contain different versions. Branches contain the currently maintained releases (e.g. "branches/7"), also known as release branches, as well as development branches (e.g. "branches/owlet"). Release branches are considered stable and are usually only updated for fixing bugs or adding build support for new compiler versions. Development branches may be temporary or experimental, and are usually used for big feature development that deviate from the main code on the trunk. Tags simply contain static copies of every release made.
The code repository can be accessed in the Code section. You can here inspect its contents and revision history. You can make a snapshot and download a copy of any version. You can also use a Subversion client to create a local "working copy" of any directory in the repository and keep it up to date. Developers can submit revisions to the code using the Subversion client.
For more information about version control and the associated terminology and conventions, see the Subversion documentation, as well as tutorials and articles on the web.
See the installation guide.
The installation guide has a section on setting up your IDE.
If you follow the installation guide closely, then the installation should normally be swift and painless. Test your installation by building and running some of the provided examples.
If OWLMaker or the build scripts fail, then check that your compiler tools are set up correctly, that the drive volume supports short filenames (legacy 8.3 filename aliases are required by some legacy toolsets, and Windows now only enables this for the system drive by default), and that you do not have interference from other tools that you use. Also, make sure you use the latest version of OWLMaker. Old versions may not be able to build the latest source correctly, or may have bugs that have since been fixed. The installation guide has a link to the latest version.
If the problem persists then ask for help in the forum.
When a major new version of OWLNext is released, it may be released with a "beta" designation. The main reason for the beta designation is to signal to users that the release is fresh and not thoroughly field-tested. Whether or not to use a beta in production depends on your assessment of the risk of deployment. Study the release notes and evaluate the changes to make a decision for your circumstance. And, as always, run your own thorough tests.
The beta designation also allows us the freedom to ship a binary incompatible update, should it be necessary to fix any unknown regressions that affect the ABI. Technically, we allow this by keeping the OWL_PRERELEASE flag set for beta releases. This causes the build process to generate library files with three-part version numbers in their naming, thus allowing differentiation between bug-fix releases. Conversely, when the OWL_PRERELEASE flag is cleared, the build process generates file names with two-part version numbers, providing naming stability and allowing DLL replacement for bug-fix releases. This of course restricts us to making only ABI-compatible changes between releases.
ABI-compatibility is only an issue for dynamic linking and DLL updates. We now generally recommend using static linking, for which ABI-compatibility is a non-issue (see "Should I use static or dynamic linking (DLL)?").
For in-depth information about upgrading, see Upgrading from OWL.
OWLNext supports compatibility build modes that revert some of the changes that we have made to improve the API.
You should only use the compatibility modes as a stepping stone for porting legacy applications to OWLNext. When your application is working with OWLNext, you should turn the compatibility modes off, adapt your code, rebuild and test your application.
For more information about the compatibility modes, see OWL Compatibility Modes.
In the latest OWLNext, a lot of function signatures have been updated to be const-correct, i.e. reference parameters have now become const-reference parameters where mutation is not intended. For example, the event handler signature for WM_LBUTTONDOWN is now void T::EvLButtonDown (uint modKeys, const TPoint&). In OWL 5, the last parameter did not have const and was hence mutable, i.e. it was an output parameter. There was no reason for it to be an output parameter, other than the fact that const was a new thing back then. Const-correctness is now conventional C++ wisdom, and parameters should only be output parameters if that is really the intention — which is not the case here, hence the change of the function signature.
Note that adding const for the TPoint reference here was not done to prevent modification of the argument (LPARAM) sent by the message sender. The point is sent by value in the Windows message, so modifying the temporary TPoint created by OWLNext would be harmless. However, unexpected modification could happen when forwarding from handler to handler (e.g. from derived class to base, as is often the case), and this could (and actually did) lead to bugs.
NOTE: Never use const_cast to override const-correctness!
If you need to use a const-reference variable or parameter as an argument to a function that has an output parameter, then create a temporary instead of using const_cast. For example:
void T::EvLButtonDown(uint modKeys, const TPoint& p)
{
auto ps = p; // ClientToScreen output argument.
ClientToScreen(ps);
//...
}
Do not write ClientToScreen ((TPoint&) p)
or ClientToScreen (const_cast <TPoint&> (p))
. Casting away const defeats the purpose of making the parameter const-correct in the first place, and leads to the brittle code that introducing const was intended to prevent.
Tip: OWLNext has added functional-style overloads and alternatives to many functions that have output parameters. For example, you can use MapClientToScreen instead of ClientToScreen.
void T::EvLButtonDown(uint modKeys, const TPoint& p)
{
const auto ps = MapClientToScreen(p);
//...
}
In 6.32, TGauge was deprecated and replaced by the new class TProgressBar. TGauge was simplified and retained for supporting legacy code until OWLNext 8, in which it was moved to OWLExt (see [feature-requests:#202] and [r5913]). TGauge is now a pure custom OWL control, while TProgressBar encapsulates the Windows common control (Progress Bar).
Note that you need to be careful to use the correct progress bar control class in your resource files. For TProgressBar, you should use "msctls_progress32", and for TGauge you should use "OWL_Gauge".
This obsolete feature for Win16 was removed in 6.32. See Upgrading from OWL → Removal of obsolete features.
These simulated parts of the Borland C++ Class Libraries are incomplete, unreliable and no longer maintained. In particular, beware that detailed requirements for element copy construction and assignment etc. are not 100% compatible, and this may introduce bugs in your code that are hard to pinpoint. Ideally, you should rewrite your code to use the standard C++ library or other alternatives instead.
See Upgrading from OWL for more information.
The TRegexp class has known issues, some of which we have fixed in version 6.44.10. This may have changed your search results. See [bugs:#454]. Note that TRegexp is deprecated, and it is recommended to use standard C++ regular expressions instead. See Replacing the Borland C++ Class Libraries.
string
class, and I now get a lot of errors. How do I resolve them?The Borland 'string' class, part of the Borland C++ Class Libraries, has been replaced by owl::tstring, which is an alias for std::string or std::wstring, depending on the UNICODE build mode. See Replacing the Borland C++ Class Libraries → Strings (string, TSubString) for more information and tips about how to rewrite your code.
OWLNext versions prior to 6.32 defined the owl_string alias, usually mapping to std::string or std::wstring depending on the Windows Unicode build mode. OWLNext 6.32 renamed owl_string to owl::tstring, so that it is now properly encapsulated within the OWLNext namespace.
Version 6.32 also introduced owl::tchar, owl::tstringstream, etc. The 't' prefix indicates compatibility with the Windows Unicode build mode. Read more about these changes in the knowledge base article Strings in OWLNext.
Since version 6.32, namespaces are now mandatory, and OWLNext has strict namespace hygiene, i.e. no injection of symbols is done into the global namespace.
We recommend you use explicit qualification in your headers (yes, put all those "owl::" prefixes on names), while you may be a little more lax in your implementation files (.cpp), where you may use a namespace directive at the global scope below header include directives.
// C++ implementation file (.cpp)
//
// ...header include directives...
//
using namespace owl;
For your headers, clever use of search-and-replace with regular expressions can simplify the task quite a bit. E.g. the Visual Studio 2012 regular expression "\b(T[A-Z]\w+|uint|int16|uint16|uint32)" will find OWLNext class names and some of the common integer types defined by OWLNext. The "\b" part of the expression means start-of-a-word. The "T[A-Z]\w+" part means the letter "T" followed by an upper-case letter, followed by one or more alphanumeric characters; the bar "|" means "or", and the parentheses mark the expression so that you can refer to it by "$" and index in the replace expression. The replace expression would be "owl::$1" ("$1" refers to the matched sub-expression).
In Visual Studio 2010, the equivalent regular expression would be "<{T:Lu:i|uint|int16|uint16|uint32}" and the replace expression would be "owl::\1". For more information about regular expressions, see the documentation for your IDE.
You can perform such a replace command across all your headers in one go. Even if it replaces some false matches, Visual Studio will list all the replacements in the Find window, so it may be faster and easier just to correct any false matches afterwards. And you can undo if it goes horribly wrong. Alternatively, you can step through and check each replace using the "Replace in files" dialog. For other IDEs, see the documentation.
The OWLNext namespace changed name from "OWL" to "owl" in version 6.32, to comply with general naming conventions and not be mistaken for a macro. The use of the old "OWL" name is only allowed in OWL5_COMPAT mode.
Simply rename all occurrences of "OWL::" to "owl::" in your code. Or, if you want to write code that works with previous versions as well, then add the following conditional statement in a global header (e.g. your precompiled header):
#if OWLVersion >= 0x0632
namespace OWL = owl;
#endif
The opposite also works, i.e. create an "owl" namespace alias for "OWL" for code compiled with older versions.
Over the years we have made numerous corrections to the event handler signatures, so this may cause the errors you are getting. In particular, OWLNext 6.40 introduced a major overhaul of the message dispatch machinery, and many event handler signatures were updated in the process.
To resolve signature errors, see "What is the correct signature for my event handler?".
In addition, OWLNext 6.40 now requires that the event handler for a response table entry is declared in the class owning the table. The new requirement prevents mistakes such as forgetting to declare and implement the handler for a response table entry. If you rely on handlers in parent classes, then you need to define a forwarder. For example:
void EvPaint() {TParentClass::EvPaint();}
However, note that the parent class should ideally have its own response table entry for its handler, making the entry in the child class' response table unnecessary.
See Windows Message Dispatch in OWLNext for more information about the new dispatch solution and about dispatch in general.
The Windows message dispatch machinery was thoroughly overhauled for OWLNext 6.40, and this affects the way you define custom DocView notifications. In particular, the third parameter for the VN_DEFINE macro is now a function template responsible for decoding the message and forwarding the call to a handler of your specified signature. For example, for a notification event vnUpdate
with the handler signature "bool T::VnUpdate(long)
", the decode function template and response table macro will look something like this:
template <class T, bool (T::*M)(long)> // <== Your handler signature goes here.
owl::TResult DecodeVnUpdate(void* i, owl::TParam1, owl::TParam2 p2) // <== Fixed signature.
{
return (static_cast<T*>(i)->*M)(static_cast<long>(p2)) ? TRUE : FALSE;
}
const int vnUpdate = owl::vnCustomBase + 1;
#define EV_VN_UPDATE VN_DEFINE(vnUpdate, VnUpdate, DecodeVnUpdate)
However, you may write more forward-looking code by following the same conventions as OWLNext, in which the decode function template is defined within a dispatch template, allowing compile-time lookup of functions for encoding and decoding a given message or notification.
See Windows Message Dispatch in OWLNext → Defining DocView notifications.
For the nitty-gritty detail, see the source code; "owl/docview.h" and "owl/dispatch.h".
xmsg
go, and what changes have you made to exception handling?Originally, OWL used the old exception class xmsg
as the base class for TXBase, which in turn is the base class for TXOwl and the derived exception classes, TXWindow etc. OWLNext now uses std::exception as the base class for TXBase. For more information about the changes to exception handling, internal details about exception handling within the OWLNext source code, as well as guidelines on how to write exception-safe OWLNext client code, see Exceptions and OWLNext.
We have made numerous changes and improvements to the OWLNext API. Is some rare cases, this may have involved a change in virtual function signatures (for example, see Strings in OWLNext). If your overriding virtual function uses the old signature, the mismatch may go undetected, and your function is never called.
To mitigate this problem, use the C++11 keyword override
on all your overriding virtual functions. This keyword will report a signature mismatch with a compilation error.
OWLNext 7 has been upgraded to support version 6 of the Windows API (see 7 series → Major new features). This causes changes in some common controls structures (such as LVITEM and its wrapper TLvItem), due to new members and flags having been introduced to support new features. This may cause old client code to no longer work as intended. For example, see [discussion:d6b4718451]. Make sure that sizes and flags in common control structures are set appropriately for version 6 of the Windows API (Vista and later).
In OWLNext 7, we replaced the old protected virtual function TWindow::GetClassName by TWindow::GetWindowClassName. Make sure that you update your code accordingly for any custom control classes you may have that override GetClassName.
See: Upgrading from OWL → Replacement of the protected TWindow::GetClassName overload
If this is not it, browse the rest of this FAQ for other potential problems. If you remain stuck, ask for help in our Open Discussion forum.
Integers such as palette indexes (int) and color references (long) are no longer implicitly converted to TColor. We made this change in version 6.34, after we ran into problems with unintended conversions to TColor and constructor selection. As a solution, we removed the converting constructor TColor (int) and replaced it by TColor::CreateFromPaletteIndex . This change means that you now also need to be explicit if you pass COLORREF arguments for TColor parameters.
void Foo(TColor);
Foo(42); // ERROR: No implicit conversion from int (palette index) to TColor.
Foo(TColor::CreateFromPaletteIndex(42)); // OK
Foo(PALETTEINDEX(42)); // OK
Foo(0x102030L); // ERROR: No implicit conversion from long to COLORREF to TColor.
Foo(static_cast<COLORREF>(0x102030)); // OK
Foo(TColor{0x30, 0x20, 0x10}); // OK
See [discussion:0cb40903], [bugs:#237] and the fix in [r1800].
The signature of TDialog::DialogFunction was changed in OWLNext 6.32 to be compliant with the Windows SDK DialogProc function and support 64-bit compilation. Prior to version 6.42, you can use the OWL5_COMPAT build mode to get the old 32-bit signature. However, the signature was permanently changed in 6.42 to support 64-bit even in OWL5_COMPAT mode. See "TDialog::DialogFunction has non-compliant return type" [bugs:#199].
For more information about 64-bit changes, see 64-bit OWLNext.
The signature of TWindow::PerformCreate has been changed to support 64-bit compilation. Prior to version OWLNext 6.42, you can use the OWL5_COMPAT build mode to get the old 32-bit signature. However, the signature was permanently changed in 6.42 to support 64-bit even in OWL5_COMPAT mode.
For more information about 64-bit changes, see 64-bit OWLNext.
Note that OWL transfer buffers require byte packing of the buffer definition. Ensure that your buffers are properly packed by using compiler pragma packing directives around the structure definition. You can use ready-made headers for this purpose, e.g.
#include <pshpack1.h>
struct TMyTransferBuffer
{
// ...
};
#include <poppack.h>
Also check that your field types are correct and that array fields are of the correct type and size. See Defining the Transfer Buffer in the OWLNext Reference Documentation for the correct field types for the standard controls.
Never mix transfer data and application data. The transfer buffer should only contain control data fields for dialog data transfer. If needed, use aggregation to collect the transfer buffer and any additional non-transfer data into an enclosing structure.
Starting with OWLNext 6.32 you can make your transfer buffers safe by using the new class template TTransferBufferWindow. See Safe Transfer Buffers for more information about these new features, as well as an in-depth analysis of the inherent issues with transfer buffers.
If you are porting legacy code that uses a custom dialog template for the old-style print dialog, you must set the flag TPrintDialog::TData::UseOldDialog.
Also note that a regression in 6.32 meant that you could no longer pass integer resource identifiers (e.g. created by MAKEINTRESOURCE) to the TPrintDialog constructor. This issue was fixed in 6.36 and 6.44. See [bugs:#335] for more information and workarounds for older versions.
In general, the printing machinery requires that some resources are included in the executable, otherwise your application may crash at runtime. In particular, it requires resources for the TPrinterAbortDlg and the printing-related message strings. To ensure that your application has these resources, include "owl/printer.rc" in your project (not necessary if you include"owl/all.rc", since it is then already included).
To investigate printing issues, you may find it helpful to experiment with a small working example, e.g. "examples/richeditor", in which you can try to recreate and solve the problem you are seeing.
If you remain stuck, search bugs and forums for printing related issues. Then try asking for help in the forum.
You should not link "...\BC5\LIB\OWLW*.LIB" when you build for OWLNext. Remove the dependency from your project configuration. Note that you do not need to explicitly specify the OWLNext library file to the linker, since OWLNext uses auto-linking controlled by pragma statements in the library headers. See "include/owl/private/owllink.h".
If you are using the Borland C++ IDE, make sure that OWL is turned off in TargetExpert, or show hidden nodes (Environment Options → Project View → Project display settings → Show run-time nodes) and explicitly delete "OWLW*.LIB" from the project dependencies.
The global Module variable is an OWL 5 feature referring to the current module. It now resides in the OWL namespace (owl::Module) and has an initializing accessor function, owl::GetGlobalModule.
Instead of using GetGlobalModule, you should use an explicit reference to the intended module. For example, if you write code inside a TWindow derived object, you should use TWindow::GetModule or TWindow::GetApplication. GetModule gives you the module for which the window was created, and GetApplication gives you the singleton application module (EXE). In a dynamically linked application, owl::OWLGetModule gives you the OWL DLL module. If referring to another module (DLL) then encapsulate it in a singleton class derived from TModule.
If you write DLL code, you should pay particular attention to which module you mean to refer to; the client application module, the OWLNext module, or your DLL module.
The variable "_hInstance" is an undocumented OWL 5 feature to get a reference to the application module instance (HINSTANCE handle) before the application has created a TApplication object. It is no longer supported in OWLNext. You should replace all uses of the symbol "_hInstance" by one of the documented ways to refer to the application instance. See the previous question about "Module".
This usually happens when you have more than one resource (".rc") file in your solution, and you have STRINGTABLE resources with the same identifiers.
In particular, it happens if you include the same OWL resources from more than one resource file, or in addition to adding the resource file as a separate item in your project. To solve the problem, make sure that any of OWLNext's resource files (like "owl\docview.rc" and "owl\mdi.rc") are included only once in your project.
Note that you can use "owl\all.rc" to simply include all OWLNext resources, if you link OWLNext statically. If you link dynamically, the OWLNext DLL will already include "owl\all.rc" in the DLL, so you do not need to add the OWL resources to your project, unless you want to override them.
See CVT1100 Error for a more in-depth examination of the problem.
Make sure that you pass the application pointer as the second argument to the TDocManager constructor.
void TMyApp::TMyApp()
{
//...
auto docManager = std::make_unique<TDocManager>(dmSDI | dmMenu, this); // Second argument needed!
SetDocManager(docManager.get());
docManager.release(); // TApplication took ownership.
}
A now obsolete constructor from OWL 2 allowed you to pass only the first argument, but this overload is no longer supported. If the second argument is missing, it will cause Borland C++ 5.02 to select the wrong constructor, leading to a crash at run-time. Note that Borland C++ 5.5 and newer, as well as the Microsoft compiler, will report a compilation error, if the second argument is missing.
See the OWLNext Naming Convention for details.
In some cases, the Next button on the page "Select modules and build modes" may refuse to enable, whatever selections you make in the list. If this is the case, then try to circumvent the issue by selecting "Select default" from the context menu (right-click) in the list. This should reset the state of the page and enable the Next button. You should now be able to make the selections you want.
This problem should only affect older versions of OWLMaker, such as 7.0.0.3175. If you see this problem in the latest version, let us know in the discussion forum.
Until OWLNext 8, the Unicode configuration has not been supported for CoolPrj.
See "Unicode support in CoolPrj" [feature-requests:#54].
The OWLMaker wizard notes the lack of support on page 3 ("Select modules and build modes"), if you select Modules | CoolPrj:
Note that this library is in a somewhat unfinished state. In particular, until version 8 it does not support Unicode, so Unicode build configurations will not be generated for earlier versions.
It is also mentioned in the OWLMaker online documentation:
However, note that for version 7 and earlier the CoolPrj module does not support Unicode, so Unicode build configurations will not be generated for this module, even if the CoolPrj module and the Unicode character set mode are both selected.
And in the OWLNext modules description on our wiki:
Also note that until version 8 the library did not support the UNICODE build mode.
For more information on the latest work on CoolPrj, see CoolPrj feature-requests and bugs.
You need to do build setup by following our installation guide, after which "incluce/owl/version.h" should be present.
The file "include/owl/version.h" is not actually part of the source; it is generated from the template file "source/owlcore/version.h". This is done by the make-files by calling "source/update_version_header.bat", which itself calls SubWCRev to generate an updated header based on the version number in the template and the revision number etc. of the working directory.
If SubWCRev is not installed on your system, or the OWLNext root is not a Subversion working copy, OWLNext will generate a rudimentary version header lacking detailed revision information. If, for some reason, automatic generation fails for you, see the installation guide for information on how to create the version header by hand.
Note: OWLMaker may fail to properly perform build setup, leading to error messages about missing "version.h" [bugs:#534]. This issue is triggered by the "Stop build" command. After having used this command, subsequent build commands may fail in various ways. To circumvent this issue, restart OWLMaker and try again.
Some versions of OWLNext require the Boost library to compile with Embarcadero C++Builder/RAD Studio, and Boost may not be installed by default. If it is not, go to the GetIn Plugin Manager within the IDE and install it. Make sure that the installation path agrees with CG_BOOST_ROOT in the OWLNext make-files, otherwise you will get build errors (see [bugs:#549]).
Also, for your own OWLNext projects, make sure that you have configured the include paths correctly. Note that Embarcadero uses different versions of Boost for the classic compiler (BCC32) and the new Clang-based compilers (BCC32C/BCC64). You need to include the correct version. Do not include both (they don't mix). See Boost in the Embarcadero documentation.
Usually, response table errors are caused by mismatching event handler signatures. To resolve such errors, see "What is the correct signature for my event handler?".
Some legacy toolsets, such as Borland C++ and Embarcadero's legacy toolset (BCC32), may require that support for short filenames (8.3 format aliases) is enabled for the disk volume on which the toolset is installed. This issue is mentioned in our Installation Guide → Prepare your build tools.
This is a known issue with the Borland C++ and classic Embarcadero compiler (BCC32). Pass tstring
to resolve the ambiguity.
Unfortunately, OWLNext versions 6 and earlier are not compatible with Windows Sockets 2 ("Winsock2"), due to the way OWLNext includes the main Windows header "windows.h". The issue has been resolved in version 7. See [feature-requests:#133].
A workaround for OWLNext 6 and earlier is to use compartmentalisation. Create a separate compilation unit (CPP-file) in which you implement your Winsock2-dependent functionality. This unit will include Windows Sockets 2, but not OWLNext. Then create a header that contains a declaration of your function (or functions), which you can use in your OWLNext code. The header can not include any Windows Sockets 2 headers.
For example:
// Header (.h)
// No Winsock2 stuff included here. Only OWLNext compatible stuff.
//
void DoWinsock2Stuff();
---
// Implementation file (.cpp)
// NO OWLS ALLOWED!
//
#include <winsock2.h>
void DoWinsock2Stuff()
{
// ...
}
Replace "winres.h" include directives by "owl/winres.rh". The "winres.h" file is not a standard part of the Windows SDK, but comes with some compilers as part of the ATL and MFC libraries (atlmfc/winres.h). It just contains definitions for IDC_STATIC and a few other symbols and includes the SDK file "winresrc.h". The file "owl/winres.rh" serves the same purpose.
Since the resource format differs somewhat between Borland C++ and Visual C++, we keep the resource files in a common format, usable for both compilers. Hence, you cannot directly edit the resource files in a visual editor. Instead, we recommend you copy the example, and then create your own new resource files by copying individual resources from the original file.
By leaving the original example intact you will also avoid issues when trying to patch the source, as new updates for OWLNext become available.
Check that the library file is present in the "%OWLROOT%\lib" folder. If it is, check that "%OWLROOT%\lib" is included in the library paths submitted to the linker. If you use an IDE you will have to add the path to the directories section in the project settings. See Set up your IDE in the installation guide.
If the library file is not present in the "%OWLROOT%\lib" folder, you need to build it. We recommend that you download and use the latest version of OWLMaker to build the libraries. Alternatively, use the batch and makefiles provided in the OWLNext source folders. See our Installation Guide for more details.
To decode the library name and figure out what build options the name corresponds to, see OWLNext Naming Convention.
When linking your application dynamically with the OWLNext DLL, make sure you are also linking your application with the dynamic RTL. For example, in the Embarcadero IDE, set "C++ Linker → Link with Dynamic RTL" to "true".
If you get this error while trying to build a Unicode application, you will have to change the entry point to "wWinMainCRTStartup". See Visual Studio documentation for /ENTRY.
OWLMaker may fail to build OWLNext with Embarcadero's classic toolset (BCC32), giving this error message.
See [bugs:#503] for more information and a workaround.
Borland C++ is now a very old and unsupported product with some longstanding issues. Search the web for the bugs and workarounds in this product. If you are using version 5.02 or earlier, note that there is a free upgrade available to Borland C++ 5.5. This version has better C++98 standard compliance and may have fixed bugs that you are experiencing.
Regarding link problems, if an OWLNext project fails to link in debug mode, and the linker reports a fatal internal error, try to turn off the generation of browser reference information (Options → Compiler → Debugging → Browser reference information in OBJs). If you are using Borland C++ 5.02 and have link problems, you can try replacing the linker (tlink32.exe) by the newer version in the Borland C++ 5.5 free upgrade mentioned above. That said, you should ideally upgrade to the whole 5.5 toolset.
In general, ensure that the compiler and linker options are the same or compatible with the options used to build OWLNext (you may have to inspect the makefiles for the details). Also, have a look at the provided examples and experiment with the options until you figure out what works. If you find examples that will not build and run, let us know in the discussion forum.
We recommend that Borland C++ is only used as a starting point for upgrading to OWLNext, and that you move to more modern tools in the long run (see Supported Compilers).
On modern Windows, you may have to run Borland C++ as an administrator. See "Setting up the Borland C++ IDE → Install the Tools55 add-on"" for more information.
TWindow::GetWindowFont and TWindow::SetWindowFont are simple wrappers around WM_GETFONT and WM_SETFONT, which are not handled in plain TWindow. These messages only work for native dialogs and controls, unless the TWindow subclass handles them explicitly (by adding EV_WM_GETFONT and EV_WM_SETFONT to the response table).
This issue has particular significance for TLayoutWindow. Although this class offers the programmer the use of font-relative measurement units in the layout of its children (see TMeasurementUnits), the implementation relies on WM_GETFONT, which is not implemented in TLayoutWindow. Since WM_GETFONT returns NULL, TLayoutWindow falls back on using the obsolete SYSTEM_FONT. For more information about this issue, see [bugs:#326].
You need to add the SS_NOTIFY style to static controls to enable tool tips. If you load the control from a resource file, add SS_NOTIFY to the styles in the control statement. Use ModifyStyle to set the style for a dynamically created control, for example:
const auto c = new TStatic{parent, id, _T("Static"), 0, 0, 100, 20};
c->ModifyStyle(0, SS_NOTIFY);
This problem occurs for Unicode builds without a manifest for Common Controls version 6 (or later). In this case, the classic non-themed version of Common Controls is used (5.x), and this version expects the old size of the TOOLTIP structure. Unfortunately, in OWLNext versions prior to 6.40.6, the new size of TOOLTIP is used to initialize TOOLINFO::cbSize, which will cause tool tips to not show. See [bugs:#303].
To circumvent this issue in OWLNext 6.40.5 and earlier, you need to override TOOLINFO::cbSize (TToolInfo::cbSize) explicitly before passing it to TTooltip::AddTool. For example:
const auto t = dlg->GetTooltip();
auto ti = TToolInfo{dlg.GetHandle(), ctrl.GetHandle(), _T("Tip")};
ti.cbSize = TTTOOLINFO_V1_SIZE;
t->AddTool(ti);
These tool tips are only present in debug builds. It is a diagnostic feature added in early versions of OWLNext. They are generated in TWindow::EvNotify as part of handling the TTN_NEEDTEXT notification message. This notification is handled by creating a TTooltipEnabler, which is dispatched using the custom WM_COMMAND_ENABLE message. In debug builds, the default text is set to "Tip for ID not found" (or "Text for ID not found", in case the ID is a HWND). Note that this handling of TTN_NEEDTEXT is an OWLNext invention, and it was not present in OWL.
In short, the tool tip text only means that the TTN_NEEDTEXT notification was not handled and no command enabler was found to provide a text.
Note: These diagnostic tool tips were removed in version 6.44.6. A diagnostic warning on level 1 for group OwlWin is generated instead (see Built-in OWLNext Diagnostic Window). For more information, see [bugs:#439] and [discussion:2457c06992].
An often overlooked issue with the WM_HSCROLL and WM_VSCROLL messages is that they only pass a 16-bit scroll position. When you use larger ranges you have to call GetScrollInfo (or the old GetScrollPos) to get the full 32-bit scroll position. This is a limitation of the Windows API. See MSDN.
Before OWLNext 6.32.6, the TScrollBar class was limited to 16-bit scroll ranges due to this issue. Version 6.32.6 and later support 32-bit ranges. A similar issue with the TScroller class was fixed in 6.32.5 (see bugs:#227).
The TRegexp class is not compliant with standard regular expressions, and the implementation has known issues. For example, it does not support characters beyond the 7-bit ASCII character set. See [bugs:#454]. The class is deprecated, and it is recommended to use standard C++ regular expressions instead. See Replacing the Borland C++ Class Libraries.
With Windows 10 version 1607 (Anniversary Update), Microsoft removed the undocumented function DeviceCapabilitiesExW from "gdi32.dll". This function is used within older versions of OWLNext in Unicode mode, in the implementation of TPrintDC::DeviceCapabilities. So, if your OWLNext application is built in Unicode mode it may fail at start-up with a System Error message saying "The program can't start because ext-ms-win-gdi-desktop-l1-1-0.DLL is missing from your computer".
This issue was fixed in OWLNext 6.35 and 6.43. See [bugs:#342] for more information.
When you link OWLNext statically, you have to link in all the resources that the library depends upon. See the answer to the next question.
A statically built OWL application does not automatically include the OWLNext resources. In particular, if an application lacks the string table for the exception messages, you will get this generic message instead of the message contained in the string table.
You must add "include/owl/except.rc" to your project and rebuild to add the string table for the exception messages. But, be careful to add all the other resource files from OWLNext that your application needs as well; or add "include/owl/all.rc", which includes them all. Note that the core OWLNext DLL contains all the OWLNext resources, so you do not need to include these resources if you link with the dynamic OWLNext library.
It might be that your application is missing some vital resources. If you link with the static OWLNext library, you need to include the OWLNext resources in your project. See the answer to the previous question about "except.rc".
If you create DLLs in your project, and these modules use OWLNext, pay particular attention to where resources are located. For example, TWindow and derived classes take a TModule pointer in the constructor, which tells the window where to find resources. If not set, and the window has a parent, the window will look in the parent's module. Otherwise, the window will look for resources in the application module (see GetApplicationObject). Similarly, the TMenuDescr constructors, TFrameWindow::SetIcon and other functions take a module pointer for the same purpose. Make sure that you set these parameters correctly, or that the default (if any) is appropriate. Otherwise, the application may not find needed resources and crash.
In particular, there is a resource issue with TInputDialog, TPrinterAbortDlg and TPickListDialog when you link OWLNext dynamically. These classes all fail to specify that their dialog resource is located in the OWLNext module [bugs:#561]. To explicitly specify the location of resources in the OWLNext module, you can use OWLGetModule.
For more advice on how to refer to modules, see "How do I resolve errors referring to Module" in this FAQ.
If the issue is not related to resources, you may have run into a problem with a build option mismatch. Check that the OWLNext installation is working by building the projects in the "examples" folder. Then check that the build options used by your application exactly match those used to build the libraries, in particular all code generation settings, such as alignment/packing and enum-related options. Some older compilers may have bugs or issues with some settings and build modes. See the section "Set up your IDE" in the installation guide for advice on correct settings.
In particular, beware library mismatches if you use dynamic linking. If you dynamically link the RTL, you have to also link OWLNext dynamically, i.e. you need to define _OWLDLL
in your project configuration. In general, we recommend you use static linking to keep things simple. See "Should I use static or dynamic linking?".
If your application uses DLLs, you may also run into DLL load order and initialisation problems. For example, DLL load order may be an issue if one of your modules depends on the .NET framework [discussion:d9c10601a1].
For other possible explanations of crashes, see the sections in this FAQ on "windows.h" inclusion (which may cause ODR issues), transfer buffers and the Windows DEP feature. These are issues that may cause your application to crash in certain circumstances.
If you remain stuck, then report the problem in the Open Discussion forum.
Tip: If the crash is related to an exception, here is a debugging tip for Visual Studio: Go to Debug → Exceptions and then turn on the debugger break when "C++ Exceptions" are thrown. Then debug your program again. It should now break at the program line where the exception is thrown, making it easier to find out what caused it.
See the installation guide. If you find the documentation incomplete, outdated or erroneous then let us know in the Open Discussion forum.
You have to let OWL include "windows.h". This is an unwritten rule — now written!
The OWL headers will include "windows.h" (indirectly, usually by including "owl/defs.h" directly or indirectly, which in turn includes "owl/wsysinc.h", which includes "owl/private/wsysinc.h", which includes "windows.h"). OWL defines a few Windows macros that affect how "windows.h" is included. It also enforces 8-byte packing.
Including "windows.h" explicitly in an OWL application may cause ODR violation and crashes.
Tip: If some parts of your application need "windows.h", but do not need OWL, you can include "owl/defs.h" instead. If you really do not want these parts of your application to depend on OWL at all, then you either have to ensure you include "windows.h" in the exact same way (which is brittle), or use compartmentalisation to fully insulate your OWL code from the code not using OWL. For the latter solution, e.g. see item "How do I use Windows Sockets 2 and OWLNext together".
From a modern C++ programming standpoint nearly everything is wrong with the old dialog transfer buffer mechanism, and OWLNext has deprecated its use. Read more about the issues with transfer buffers and the efforts to make them safer in Safe Transfer Buffers. OWLNext 6.32 introduced a new and improved framework called Dialog Data Transfer to replace the transfer buffer mechanism.
The design and implementation of the OWLNext core assumes single-threading and is simply not thread-safe. See the article "Multi-threading and OWLNext" for advice on how to use multi-threading safely in your OWLNext programs.
For documentation about the required event handler signatures for the response table macros, see the OWLNext API Documentation. A link to the online version is available on our wiki [Main_Page]. Alternatively, you can download an offline version in the Files area.
Unfortunately, much of the documentation of the macros is currently poor and may lack the information about the required event handler signature. If so, look up the documentation for the TDispatch specialisation for the message, for example TDispatch <WM_SIZE>. The template parameter for the nested Decode function gives you the correct signature.
Tip: Bing works well for look-ups in the online documentation; e.g. the search query "TDispatch WM_SIZE" (in quotes) shows the relevant link at the top.
TDispatch was introduced in OWLNext 6.40 as part of a major overhaul of the dispatch machinery. See Windows Message Dispatch in OWLNext for details about the changes. If you rather want to go to the source, the specialisations are located in "owl/dispatch.h" for the system messages, and "owl/commctrl.h" for the common controls.
If you use an older version of OWLNext, which uses the old signature templates, you will need to look up the definition of the response table macro in "owl/windowev.h", identify which signature template it uses, and then look up the definition of the signature template in "owl/signatur.h".
First read the answer to the next question to determine if you really need dynamic linking. Static linking is simpler to deal with, and static linking is hence our general recommendation.
Enabling dynamic linking to the OWLNext library is very simple: Just define the preprocessor symbol _OWLDLL
in your project. The OWLNext headers will detect this and automatically link your application to the import library for the correct OWLNext DLL (see "include/owl/private/owllink.h"). At runtime, this DLL must be available to the application. See Dynamic-Link Libraries in the Microsoft Windows documentation for details about DLL search order and deployment. See our naming convention to learn how we determine the name of the import library and DLL. See our installation guide and OWLMaker for details on how to build the OWLNext DLL.
Note: Your application and the OWLNext library must use the same C++ runtime library. This means that you need to turn on dynamic linking of the C++ runtime library as well, if you enable dynamic linking of OWLNext. Also, as always, make sure that the compiler settings for your application are compatible with the settings used to build OWLNext, so that your application and OWLNext agree on all implementation details, such as structure sizes, member pointer representation, alignment, etc. See Set up your IDE in our installation guide for more information on how to configure your development tools.
We now generally recommend static linking.
For a regular OWLNext application there is today only one good argument for using dynamic linking with the OWLNext library, and that is to enable modular deployment of bug-fix and security patches. We do support this by keeping the library name constant for our stable releases, i.e. by omitting the patch number and using only the major and minor version numbers in the library name, e.g. "owl-6.32-v10-x86-t.dll". For releases within a stable branch, we aim to provide binary compatibility. Ideally, this means you can ship an updated OWLNext DLL to your customers without rebuilding your whole application. Since the OWLNext DLL also uses dynamic linking to the compiler's run-time library (RTL) you may also enjoy the benefit of updates to these DLL files from the library vendor.
Note however that this requires a good understanding of the Windows deployment protocols. For instance, any irregular changes to binary files in the program folders may not be accepted by the operating system for security reasons, and your program installation may be tagged as needing repair. Also, for the side-by-side deployment model, your application will keep a separate copy of the DLL files anyway, i.e. not share, and thus not benefit from vendor updates. For more details about deployment protocols, refer to the Windows documentation.
Due to these complicating factors, using static linking may simplify your deployment procedures. In this case, you simply rebuild your application and ship an update for your application as a whole, whenever you see fit. And you are guaranteed that DLL updates will not break your application.
In general, prefer static linking unless you really know why you require dynamic linking. The essential keyword here is dynamic. Why do you need a dynamic link? A dynamic link gives you the opportunity to swap out the binary code on either side of the link without rebuilding the other. Do you need this feature?
No, currently it does not. The "VCL Styles" feature works by installing hooks to intercept windows VCL and Windows API functions, changing the way the windows and window elements are drawn. This interferes with OWLNext, leading to run-time errors such as window creation and destruction failures.
No. OWLNext is based on standard C++. OWLNext is not compatible with Microsoft's extensions of the language for the Common Language Runtime (CLR) platform called Managed Extensions for C++ (now deprecated), nor the later C++/CLI, nor the language extensions for the Windows Runtime platform called C++/CX.
If you need to interoperate with C++/CLI or C++/CX code, use compartmentalisation, as discussed in the next answer. See Using Windows Forms from OWLNext applications for an example.
No, not without a deep understanding of each library and the necessary workarounds. These application frameworks are generally not compatible, and we do not support mixed code. This means that even if you manage to get it to work (which some clever owls admittedly have succeeded to do), your solution may not be stable and may break in our next release.
However, one solution to this problem is to use compartmentalisation. By this we mean making use of MFC and OWLNext in completely separate modules with a well-defined binary interface (ABI) between them, e.g. an OWLNext application using a DLL written in MFC. In this case, the interface provided by the DLL must not depend on MFC, as not to bring MFC headers into the OWLNext application. An example of such compartmentalisation would be to write a wizard in MFC and call it from your OWLNext application.
This advice also applies in general to any other mixing of application frameworks; such as .NET, ATL/WTL, wxWidgets and Qt. However, beware of DLL load order and initialisation issues. For example, DLL load order may be crucial if one of your modules depends on the .NET framework [discussion:d9c10601a1].
Yes, just use compartmentalisation, as discussed in the previous answer.
For example, create a DLL for the OWLNext dialog, and add a C interface that will create and execute the dialog. Be careful not to include any OWLNext headers in the API for your DLL. Also, do not let any exceptions escape your DLL. For example:
// API header (include this in your non-OWLNext application)
#include <windows.h>
extern "C" int __import CallDialog(HWND parentHWnd, /*...args...*/);
// OWLNext dialog implementation file:
extern "C" int __export CallDialog(HWND parentHWnd, /*...args...*/)
{
try
{
// Create an alias OWL application object when called from a non-OWL program,
// so that TDialog is happy.
//
TModule* appModule;
TApplication dummyApp("My Name", appModule);
TWindow parentAlias(parentHWnd, &GetGlobalModule());
return TMyDialog(&parentAlias, /*...args...*/).Execute();
}
catch (...)
{
return /*...failure code...*/;
}
}
You can then call this function from any application that has the ability to link with C libraries.
For a complete example, see the provided example DLLModule. Also see Using Windows Forms from OWLNext applications for an C++/CLI example.
Create a combo box and encapsulate it within a control gadget. For example:
// Use std::unique_ptr for exception safety.
//
auto comboBox = std::make_unique<TComboBox>(...);
auto ctrlGadget = std::make_unique<TControlGadget>(*comboBox);
comboBox.release(); // TControlGadget took ownership.
toolbar->Insert(*ctrlGadget);
ctrlGadget.release(); // TGadgetWindow took ownership.
With recent versions of OWLNext, setting the text and background colors of a control is usually simple: just call member functions SetTextColor and SetBkgndColor, respectively.
Note: These functions may not work with custom or themed controls. In particular, for more about the limitations when using SetTextColor with check boxes and radio buttons, see [discussion:51f1e281bd].
The standard Windows API idiom for changing the colors of standard controls in a dialog is to handle the WM_CTLCOLORSTATIC and similar messages sent to the parent of the control (this is what OWLNext does behind the scenes). For example:
class TMyDialog : public TDialog
{
public:
TMyDialog(TWindow* parent, TModule* module = nullptr)
: TDialog{parent, IDD_MYDIALOG, module},
Static{this, IDC_MYSTATIC},
StaticBackground{TColor::LtRed}
{}
protected:
TStatic Static;
TBrush StaticBackground;
auto EvCtlColorStatic(HDC hDC, HWND hWndChild, uint ctlType) -> HBRUSH
{
const auto r = TDialog::EvCtlColor(hDC, hWndChild, ctlType);
if (hWndChild == Static.GetHandle())
return StaticBackground.GetHandle();
else
return r;
}
DECLARE_RESPONSE_TABLE(TMyDialog);
};
DEFINE_RESPONSE_TABLE1(TMyDialog, TDialog)
EV_WM_CTLCOLORSTATIC(EvCtlColorStatic),
END_RESPONSE_TABLE;
However, note that these messages are only sent for certain standard controls (or custom controls subclassed from these controls). A custom control with its own painting logic may not send these messages. Even in such circumstances, you may still be able to modify the background by creating a derived control class. In your derived class, you can override TWindow::GetWindowClass to set the window class background brush, and/or you can handle the WM_ERASEBKGND message to fully control the clearing of the control background. For example:
class TMyUrlLink : public TUrlLink
{
public:
TMyUrlLink(TWindow* parent, int resourceId, uint textLimit = 0, TModule* module = nullptr)
: TUrlLink{parent, resourceId, textLimit, module}
{}
protected:
auto GetWindowClassName() -> TWindowClassName override
{
return _T("TMyUrlLink");
}
void GetWindowClass(WNDCLASS& wndClass) override
{
TUrlLink::GetWindowClass(wndClass);
wndClass.hbrBackground = reinterpret_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
}
auto EvEraseBkgnd(HDC hdc) -> bool
{
if (GetVisited())
{
auto dc = TDC{hdc};
dc.FillRect(GetClientRect(), TBrush{TColor::LtGray});
return true;
}
else
return TUrlLink::EvEraseBkgnd(hdc);
}
DECLARE_RESPONSE_TABLE(TMyUrlLink);
};
DEFINE_RESPONSE_TABLE1(TMyUrlLink, TUrlLink)
EV_WM_ERASEBKGND,
END_RESPONSE_TABLE;
For more information about the improvements made in OWLNext for text and background color handling, see [feature-requests:#112] "TWindow::SetTextColor and GetTextColor", revision [r3283] and the updated documentation and implementation of TWindow::SetBkgndColor, TWindow::EvEraseBkgnd and TWindow::EvCtlColor.
To change the font for a particular window, you can call TWindow::SetWindowFont. If you do this, bear in mind that (1) the font you feed SetWindowFont must live for as long as it is being used (so you might want to include a TFont member in your window), and that (2) you cannot call SetWindowFont until the Windows element has been created, i.e. in SetupWindow or later.
Note that in OWLNext 7 we have extended TWindow with an overload of SetWindowFont for TFont. This overload keeps the font alive as long as the window is alive (or until replaced by a font change), provided the passed TFont owns the font handle (i.e. TFont::ShouldDelete is true). This means that, in most cases, you no longer need to manage fonts passed to SetWindowFont. See [feature-requests:#113].
For example, with OWLNext 7 we can now simply do as follows:
const auto f = TFont{"Arial", -9};
Label1.SetWindowFont(f); // Font handle ownership transfer (sharing).
Label1.SetWindowFont(TFont{f}); // Same as above; font handle ownership transfer.
Label1.SetWindowFont(TFont{"Arial", -9}); // Same as above; font handle ownership transfer.
Label1.SetWindowFont({"Arial", -9}); // Same as above; TFont is inferred.
const auto alias = TFont{GetWindowFont()}; // Aliasing; the TFont instance does not own the handle.
Label2.SetWindowFont(alias); // Non-owning TFont instance; no font handle ownership transfer.
Label2.SetWindowFont(alias.GetHandle()); // Equivalent to above; no ownership transfer.
Note that, in the latter examples for Label2, there is no transfer of ownership of the font handle, so in these cases you still need to ensure that the font handle lives as long as it is needed, and that it is deleted when it no longer is.
You can get multiple lines of text by specifying the BS_MULTILINE style for your button.
void SetMultiLineStyle(TButton& b)
{b.ModifyStyle(0, BS_MULTILINE);}
To create a modeless dialogbox, use the TWindow::Create function instead of Execute.
void CreateModelessDialog(TDialog& d)
{d.Create();}
In SetupWindow for your first property page, after calling the base class SetupWindow, do:
ModifyExStyle(WS_EX_CONTEXTHELP, 0);
Include an EV_COMMAND_ENABLE entry in the response table for the application or frame window. The specified callback function will get a reference to a TCommandEnabler. You then just call that TCommandEnabler's SetText member to set the hint text. For example:
...
EV_COMMAND_ENABLE(CM_BUTTONCOMMAND, CeButtonCommand),
...
void TMyApplication::CeButtonCommand(TCommandEnabler& c)
{
c.SetText(_T("This is a hint"));
c.Enable(true); // or false, if you have a need to disable the button
}
Use TFrameWindow::SetIconSm.
If you do not want the close button at all for your class, then you can override the function GetWindowClass and set the CS_NOCLOSE class style as follows:
void MyWindow::GetWindowClass(WNDCLASS& wndClass)
{
TWindow::GetWindowClass(wndClass);
wndClass.style |= CS_NOCLOSE;
}
However, to dynamically disable the close button for a window that already has it, you need to disable the CS_CLOSE item on the system menu:
EnableMenuItem(GetSystemMenu(), SC_CLOSE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
See OldNewThing.
Create a TrueType font with the escapement and orientation set to 900.
auto CreateVerticalFont(const tstring& faceName, int height) -> TFont
{
return TFont{faceName, height, 0, 900, 900}; // width 0 is default.
}
Handle the WM_CUT, WM_COPY and WM_PASTE messages in the edit control. For example:
class TMyEdit : public TEdit
{
public:
TMyEdit(TWindow *parent, int id, int len) : TEdit(parent, id, len) {}
protected:
LRESULT EvCut(WPARAM, LPARAM) {return 0;}
LRESULT EvCopy(WPARAM, LPARAM) {return 0;}
LRESULT EvPaste(WPARAM, LPARAM) {return 0;}
DECLARE_RESPONSE_TABLE(TMyEdit);
};
DEFINE_RESPONSE_TABLE1(TMyEdit, TEdit)
EV_MESSAGE(WM_CUT, EvCut),
EV_MESSAGE(WM_COPY, EvCopy),
EV_MESSAGE(WM_PASTE, EvPaste),
END_RESPONSE_TABLE;
You have to add an application manifest file to your project. An application manifest is an XML file that describes the libraries that an application should bind to at run-time. To enable visual styles in Windows XP and later you have to specify the correct version of the common controls library (ComCtl32.dll) in your manifest file. See Enabling Visual Styles at Windows Dev Center for the details. Also, see the XP Themes example that comes with OWLNext.
Up to and including OWLNext 6.32, TGlyphButton was rendered in the classic UI style, even if you enabled themes in your application (see the own Q&A on enabling themes). Support for themed glyph buttons was introduced in OWLNext 6.34. See feature-requests:#7.
Direct support for icons was added in OWLNext 7. See "Support for TIcon in TGlyphButton" [feature-requests:#63].
In older versions of OWLNext, to set the glyph displayed on the button, TGlyphButton::SetGlyph only has overloads that accept a TBitmap, a bitmap resource (by TResId) or a raw HBITMAP handle.
To use an icon resource with TGlyphButton in older versions of OWLNext, create a TIcon separately and then access its bitmap by calling TIcon::GetIconInfo. The hbmColor member of the ICONINFO structure can then be passed to TGlyphButton::SetGlyph. However, note that TGlyphButton treats all pixels equal to TColor::LtGray as transparent. If the icon does not follow this convention, then to get correct transparency , you will have to render the icon into a bitmap, setting all transparent pixels to TColor::LtGray, using the icon's transparency mask (part of the ICONINFO structure). Then pass the resulting bitmap to TGlyphButton::SetGlyph.
Microsoft has deprecated MDI, and the look of the MDI Child Window has not been updated since the classic theme in Vista. E.g. see this post at ClarionHub:
MDI Child Window vs Non MDI Child Windows 10 appearance
However, you can write your own skinning code, painting the non-client area of the window.
In the long term, consider rewriting your code to use better workspace management.
See UI design for multiple views in the Knowledge Base.
Your instinct may be to override SetupWindow in the derived class:
void TMyDialog::SetupWindow()
{
TDialog::SetupWindow();
SetControlFocus(MyControl); // Will not work! (Neither will SetFocus.)
}
However, this will not work, as SetupWindow is called from EvInitDialog, which receives as a parameter the HWND of the control that will receive the focus unless it returns FALSE. See Initializing a Dialog Box.
So the correct way to solve this problem is to override the EvInitDialog function:
bool TMyDialog::EvInitDialog(HWND hWndFocus)
{
TDialog::EvInitDialog(hWndFocus); // Perform the initialization.
SetControlFocus(MyControl); // Use SetControlFocus rather than SetFocus to get proper default-button update.
return false; // Tell Windows not to set the focus to the default.
}
NOTE: This does not work within a TPropertyPage. Apparently, the proper way to set initial focus in property sheets and wizards is to handle the notification PSN_QUERYINITIALFOCUS. Unfortunately, dispatch for this notification is not implemented in OWLNext (as of version 7). Also note that not all stylesheet styles support this notification (see documentation link above). A simple workaround is to post the WM_SETFOCUS message from an override of TPropertyPage::SetActive. This will put WM_SETFOCUS in the message queue to be processed after the property page activation logic has completed. For example, see OWLMaker → TTitlePage::SetActive.
The header of a List View (TListViewCtrl) is a child window of the control, and has its own ID, which by default is set to 0. For use in the response table, 0 is not a valid ID. Hence you need to explicitly set an ID for the Header control. You can do this in SetupWindow. With that, you can add entries for the Header control in the response table:
void TMyDialog::SetupWindow()
{
TDialog::SetupWindow();
const auto header = ListView.GetHeaderCtrl(); CHECK(header);
::SetWindowLong(header, GWL_ID, IDC_LISTVIEWHEADER);
// To receive click notifications from the header, also add:
//
const auto style = ::GetWindowLong(header, GWL_STYLE) | HDS_BUTTONS;
::SetWindowLong(header, GWL_STYLE, style);
}
DEFINE_RESPONSE_TABLE1(TMyDialog, TDialog)
EV_HDN_ITEMCHANGED(IDC_LISTVIEWHEADER, EvHdnItemChanged),
EV_HDN_ITEMCLICK(IDC_LISTVIEWHEADER, EvHeaderNotification), // Requires header with HDS_BUTTONS style.
END_RESPONSE_TABLE;
Alternatively, you can override virtual function TWindow::EvNotify and filter out the notifications from the Header control. Tip: Use TListViewCtrl::GetHeaderCtrl to get the Header control handle and compare it against parameter TNotify::hwndFrom.
See "ID for TListViewCtrl Header" [feature-requests:#220] for a proposed extension for OWLNext 8.
To enable mouse wheel scrolling in the MDI client area, derive a subclass from TMDIClient with event handlers for WM_MOUSEWHEEL (vertical scrolling) and WM_MOUSEHWHEEL (horizontal scrolling). In you handler, you simply forward WM_VSCROLL or WM_HSCROLL to the base class, as appropriate.
Note: You also need to properly update the MDI children's window frames after the scroll. Otherwise, the GUI gets confused about the location of the various frame elements.
void EvMouseWheel([[maybe_unused]] uint modKeys, int zDelta, const TPoint&)
{
if (GetScrollRange(SB_VERT) == TScrollRange{}) return;
const auto sbLine = (zDelta < 0) ? SB_LINEDOWN : SB_LINEUP;
SendMessage(WM_VSCROLL, sbLine);
for (auto& c : GetChildren())
c.SetWindowPos(nullptr, {}, SWP_FRAMECHANGED |
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
}
As an alternative to SetWindowPos, you can send WM_NCACTIVATE to the children instead. However, in this case, you have to properly determine if the frame of the child should be drawn in the active style or not:
const auto isActive = GetApplication()->GetMainWindow()->GetHandle() == GetActiveWindow();
const auto a = GetActiveMDIChild(); CHECK(a);
for (const auto& c : GetChildren())
c.SendMessage(WM_NCACTIVATE, &c == a && isActive ? TRUE : FALSE);
For full example code, see "examples/classes".
By default, when the user TABs to an edit control in a dialog box, the entire contents of the edit control are autoselected. This occurs because the edit control responds with the DLGC_HASSETSEL flag in response to the WM_GETDLGCODE message. To prevent it from happening, remove that flag.
In OWLNext, create a class derived from TEdit and handle the WM_GETDLGCODE message:
class TEditWithNoDefaultSelection : public TEdit
{
public:
TEditWithNoDefaultSelection(TWindow* parent, int resourceId, uint textLimit = 0, TModule* m = nullptr) : TEdit(parent, resourceId, textLimit, m) {}
...
protected:
uint EvGetDlgCode(const MSG* msg)
{
return TEdit::EvGetDlgCode(msg) & ~DLGC_HASSETSEL;
}
DECLARE_RESPONSE_TABLE(TEditWithNoDefaultSelection);
};
DEFINE_RESPONSE_TABLE1(TEditWithNoDefaultSelection, TEdit)
EV_WM_GETDLGCODE,
END_RESPONSE_TABLE;
See also Preventing edit control text from being autoselected in a dialog box
For full example code, see "examples/foldersize".
When we considered the changes needed to support 64-bit, we found the old Borland implementation of message dispatch messy and hard to work with. This prompted us to rewrite the implementation using modern C++. The new implementation (in 6.40 and later) puts the functions for encoding and decoding a Windows message inside a class template specialization for that particular message. The functions (Encode and Decode, respectively) are themselves templates that are specialized for the message-passing function (encoding) and the handler function (decoding).
Read more about the changes in Window Message Dispatch in OWLNext.
In addition to adding a new build mode, support for 64-bit required us to replace 32-bit specific function calls and signatures by versions compatible with 64-bit. We also decided to fully rewrite the Windows message dispatch (see previous question).
Read more about the changes in 64-bit OWLNext.
OWLNext now uses the standard exception class std::exception as the base class for TXBase. We have also replaced the diagnostic exceptions produced by the CHECK and PRECONDITION macros. Internally, we have reinstated exception transport across the Windows API boundary, since the solution introduced in OWL 5 (i.e. relying on Windows Structured Exception Handling) proved unreliable in modern Windows.
Read more about the changes in Exceptions and OWLNext.
See the history of the file in our code repository to research changes.
Tip: Add the "limit" variable to the URL to get more of the history in one page. For example, to see 100 entries of the most recent revision history for the source file "include/owl/private/borlandc.h", use the following URL:
The code log page can also show changes between revision (generate diffs). Use the checkboxes and the Compare button. For example, here is the URL to show the changes in revision 3644 for the example file above:
If you have a Subversion client installed (such as TortoiseSVN), it has powerful functions to inspect the code log. In particular, the Blame command is great for tracing the revision history of code sections. See your Subversion client documentation for details.
Unfortunately, the code log in the early era of the project has poor log messages, if any at all, and revisions in this era often include a lot of unrelated changes. If the code log does not help you explain the reasons behind a revision, ask about it in our discussion forum. The code log should at least give you the author of the revision.
Yes. Support for DEP was introduced in OWLNext 6.20. See OWLNext and Data Execution Prevention for more details.
Note that applications in Windows 95/98/ME compatibility mode may not run with DEP. OWLNext has had support for DEP since version 6.20, but there are issues if you run your application in compatibility modes for older platforms than Windows NT 4. In this case you may have to make an exception for your application in the DEP settings.
Thunks are small chunks of run-time generated code. Thunks are part of the mechanism OWL uses to dispatch Windows messages. Instead of using a look-up table to associate a user interface element with the OWL object handling it, OWL generates a thunk for each object. Each thunk embeds a pointer to the object that owns it. By calling the thunk and passing the message, the thunk will forward it to the object. A thunk is installed as the window procedure for the interface element the object manages. This enables the Windows C API to dispatch messages to C++ object-oriented code very efficiently.
Read more about thunks and alternative mechanisms in Window Message Dispatch in OWLNext.
It is a technique used to split up a compilation unit into smaller parts by using the preprocessor. This is advantageous for linkers that are inept at eliminating unused code, allowing them to produce smaller target files. See OWL Static Library Sectioning for more details.
OWLNext 6.34 and later do not use sectioning.
Bugs: #199
Bugs: #237
Bugs: #303
Bugs: #326
Bugs: #335
Bugs: #342
Bugs: #439
Bugs: #454
Bugs: #503
Bugs: #527
Bugs: #534
Bugs: #549
Bugs: #561
Code: code
Commit: [r1800]
Commit: [r3283]
Commit: [r5913]
Discussion: 97175
Discussion: EV_WM_LBUTTONDOWN, EV_WM_SIZE and some others cause errors in VS 2013
Discussion: 0cb40903
Discussion: 2457c06992
Discussion: Controls loosing window handle after upgrading owlnext
Discussion: OwlMaker build Fail with Visual Studio 2022
Discussion: Upgrade From OWLNext 6 To OWLNext 7
Discussion: 51f1e281bd
Discussion: Using PROJ library in Borland C++ 5.02/OWL
Discussion: Upgrade to OWLNext with ease (documentation, tips, FAQ, etc.)
Discussion: 7a18b047f4
Discussion: OWLMaker problem with OWLInternalVersion
Discussion: Porting from 6.36 to 6.44 (some help needed)
Discussion: Unsupported Compiler Version fatal error C1189 when switching to OWLNEXT 7
Discussion: owl-630-v10-tu.lib Build Errors
Discussion: d6b4718451
Discussion: d9c10601a1
Discussion: OWLNext 7 and Windows 7
Discussion: Porting my codes to OWLNext 6.42
Feature Requests: #112
Feature Requests: #113
Feature Requests: #133
Feature Requests: #202
Feature Requests: #220
Feature Requests: #54
Feature Requests: #63
News: 2019/09/state-of-owlnext--10-years-since-630
Wiki: 64-bit_OWLNext
Wiki: Built-in_OWLNext_diagnostic_window
Wiki: CVT1100 Error
Wiki: Contributing
Wiki: Dialog_Data_Transfer
Wiki: Examples
Wiki: Exceptions_and_OWLNext
Wiki: Features
Wiki: Frequently_Asked_Questions
Wiki: Installing_OWLNext
Wiki: Knowledge_Base
Wiki: Main_Page
Wiki: Multi-threading_and_OWLNext
Wiki: OWLMaker
Wiki: OWLNext_Stable_Releases
Wiki: OWLNext_and_Data_Execution_Prevention
Wiki: OWLNext_naming_convention
Wiki: OWL_Compatibility_modes
Wiki: OWL_Static_Library_Sectioning
Wiki: Safe_Transfer_Buffers
Wiki: Strings_in_OWLNext
Wiki: Submitting_bugs_and_feature_requests
Wiki: Supported_Compilers
Wiki: Tools
Wiki: UI_design_for_multiple_views
Wiki: Upgrading_from_OWL
Wiki: Using Windows Forms from OWLNext applications
Wiki: Windows_Message_Dispatch_in_OWLNext
I can also put here some of items from Kent Reisdorph's old site which I hosted on my site: http://personal.sirma.bg/Jogy/Reisdorph/bc50faq.htm and some of the items from the older OWLNext site: http://owlnext.sourceforge.net/old/owlfaq.html --[[User:Jogybl|Jogybl]] 09:06, 6 March 2010 (UTC)