In general, mCtrl follows Win32API conventions in error handling. On error, the mCtrl functions set the error code with
SetLastError() and then typically return a value indicating an error has occurred. In most cases this error indicator is 0, -1,
NULL, depending on the function and type it returns.
If a function fails, any output parameters are undefined and you cannot rely on their value.
Also note that for the category of caller's programmatic errors (e.g. when application specifies an invalid value in a function parameter or invalid combination of multiple parameters; or when calling any function without having the particular mCtrl module initialized), mCtrl uses very pragmatic approach: Such error conditions are only checked if it is reasonably easy to do so. Some more checks can be enabled in debug builds of mCtrl.
MCTRL.DLL supports Unicode and strings held internally in the library are encoded in Unicode.
However on interface level,
MCTRL.DLL supports both Unicode and ANSI strings as well. If a function, message of a control or a structure uses string, there are usually two flavors of the entity: one for Unicode and one for the ANSI string. When calling a function or sending a message, ANSI strings in parameters and structure members are converted to Unicode on input and Unicode to ANSI on output.
Identifiers of the Unicode flavor then have the
"W" suffix and ANSI have
"A" suffix, in the same way as Win32API does. The public headers also provide preprocessor macros without the suffix, as an alias for the one of the two depending whether
UNICODE is defined or not.
In case of notifications sent by control to the application, the mCtrl also follows the Windows custom practice: Controls which may need to send a notification with string data send
WM_NOTIFYFORMAT message to its parent during creation and then respect the parent's desire.
This means you may use
MCTRL.DLL easily in Unicode-enabled application as well as in ANSI applications.
mCtrl functionality is divided into several modules, each having its own public header file. Almost every module corresponds to an implementation of one GUI control. With few trivial exceptions, each module has its own initialization and termination function.
Before you may use any functionality of the module you have to initialize it and after you stop using it you should terminate it to free any resources the module uses.
For controls, the initialization routine typically registers the control's window class with
RegisterClass(), and the termination function unregisters it with
Note that for performance reasons mCtrl functions do not test whether the module is properly initialized, so the function can fail in any means if the module is not initialized, or can work if the function does not currently rely on the initialization. But note that in the latter case there is no guaranty the behavior does not change in future versions of mCtrl.
The initialization function can be always called multiple times (even concurrently for multiple threads). Each module has its own initialization counter, incremented in the initialization function and decremented in the termination function. The module is really uninitialized only after the counter drops back down to zero.
MCTRL.DLLfrom your dynamic library, you may not call the initialization and termination functions in context of
DllMain(). Windows severly limits what can be done safely in the
DllMain()context. Even if it would be safe for some modules currently there is no guaranty that future version of mCtrl won't use anything problematic in this regard.
mCtrl makes this promise (valid also for future versions of
MCTRL.DLL): All mCtrl controls only implement private messages in the range 0x0401 (
WM_USER + 1) to 0x1299 (
WM_USER + 0x0eff).
Beside that mCtrl controls support some common control general messages (
CCM_xxxx which start at 0x2000; e.g.
I.e., if an application implements some custom control as a subclass of mCtrl control, it should acquire its private message from the range 0x1300 to 0x1fff.
mCtrl is designed to be multi-threading friendly. In general, all functions are reentrant. I.e. you can call the same
MCTRL.DLL function concurrently from multiple threads.
However remember that access to data visible externally through
MCTRL.DLL interface is not synchronized: If you have such data (e.g. MC_HTABLE) and then want to manipulate with the data concurrently in context of multiple threads,
MCTRL.DLL does not synchronize for you: It's application developer's responsibility to do so in order to avoid race conditions.
Also note that some mCtrl modules may include yet another limitations. Any such limitations are described in documentation of such the particular modules. (The MC_WC_HTML control is a prominent example of such limitation.)
Furthermore, some care is also needed if your application is multi-threaded and if it relies on any COM interface in any thread which may call into
MCTRL.DLL. See Compatibility with COM for mroe information about this.
Internally, implementation of some mCtrl features and modules is based on COM (Component Object Model). The COM uses the not so widely understood concept of thread apartments.
Each thread which wants to use COM, needs first to initialize the COM subsystem with function
CoInitializeEx() or any function wrapping it (e.g.
OleInitialize()). The function (or a parameter passed to it) then determines the thread's apartment. Once set, the thread apartment then cannot be changed.
This design may mean a problem when designing any DLL. The DLL can safely set COM apartment model for worker threads private to the DLL where the application has no chance to initialize it on its own. But in the usual case of an application thread which just calls arbitrary DLL function, calling
CoInitialize() inside the DLL brings a risk: If both the DLL as well as the application want to use COM and they do not agree on common apartment model, the application will be subject of subtle and hard-to-debug bugs (the thread may live in other apartment then DLL or application thinks, the
CoInitialize() may fail etc.)
This section therefore describes how
MCTRL.DLL initializes and mananges COM and we recommend two ways how to deal with COM in application linking against
Actually, the rules are very simple:
MCTRL.DLLimplementation of any module or feature may or may not use COM as it sees fit. Even modules which do not yet do so today, may start to do so in any future version of mCtrl.
MCTRL.DLLuses COM in a way which is compatible both with single-threaded apartments as well as multi-threaded apartments.
MCTRL.DLLneeds to use COM, it detects whether the calling thread has COM subsystem already initialized or not. The result of this test then determines whether
MCTRL.DLLdoes all COM initialization on its own or if it leaves it on the application. I.e. if the test says the COM is (for the current thread) already initialized, it tells
MCTRL.DLLto never ever attempt to initialize COM anymore, in any thread, for the lifetime of the process (or until
MCTRL.DLLis unloaded) as
MCTRL.DLLconsiders the application to be COM-aware. However if the test detects that COM in the given thread is not yet initialized, the
MCTRL.DLLassumes he application does not use COM at all, and it shall initialize COM as it sees fit for its own purposes to deal with it.
MCTRL.DLLmanages the COM initialization, application must not rely when it does so, and how it does so (i.e. what apartment
MCTRL.DLLuses.) In other words, there should be no other COM usage but in
Hence, any application which links with
MCTRL.DLL, should strictly follow one of two use patterns as of COM initialization:
MCTRL.DLLmanages COM. Application must never perform COM initialization of any thread which may call into
MCTRL.DLL. This is perfectly usable for applications which (on their own or through any 3rd party DLL) never use COM.
The policy for mCtrl is to make hard dependencies only on DLLs available on on all supported Windows versions. This includes libraries like
However some mCtrl features may depend on additional DLLs, which are loaded in runtime. In such cases, mCtrl tries to behave in a reasonable manner even if those libraries or are not available.
UXTHEME.DLLis used on Windows XP and newer to paint the mCtrl controls using the current theme. Note mCtrl does so only if the application uses
COMMCTRL32.DLLversion 6 or newer.
D2D1.DLL) & DirectWrite (
DWRITE.DLL), or if Direct2D/DirectWrite is not available, it loads GDI+ (
GDIPLUS.DLL). Note that Direct2D is only available since MS Vista (with some service pack or other updates) and newer Windows versions. GDI+ is available since Windows XP. Windows 2000 does not provide system version of GDI+ but redistributable version of GDI+ v. 1.0 can be obtained from Microsoft.