Why EM_SETMARGINS does not work under Windows 7? - windows

I have a compound visual control which consists of edit box and a drop down button. The drop down button is not a windowed control and is drawn over edit box. I limit edit's width with following call:
SendMessage(Handle, EM_SETMARGINS, EC_RIGHTMARGIN,
(DropDownButtonWidth + 2) shl 16);
It works fine under Windows XP but doesn't work under Windows 7. In latter case, when focused edit box overlap dropdown button and erases its image.
What would be correct way of limiting edit box rect under both operation systems?
PS: I also tried another approach:
SendMessage(Handle, EM_GETRECT, 0, LongInt(#Loc));
Loc.Bottom := ClientHeight + 1;
Loc.Right := ClientWidth - FButton.Width - 2;
Loc.Top := 0;
Loc.Left := 0;
SendMessage(Handle, EM_SETRECTNP, 0, LongInt(#Loc));
But it doesn't work for Windows 7 either.

Your first code to set the margins is correct.
Things get tricky however because of the way the VCL works, the underlying window created for a given VCL control may be recreated in response to changes made to VCL properties at runtime (some property changes can only be applied at the Windows API level by destroying and recreating the window). Although the order of messages is (usually) not changed in different Windows versions, there can be additional messages introduced, some of which may alter the order in which the VCL code wrapped around those windows may fire, or interfere with the behaviour of that code.
It is also possible that a behaviour was introduced in the underlying Windows API windows that the VCL does not cater for (again, most likely to occur when mixing low level API calls as in this case).
This is especially the case when mixing VCL behaviours with lower level, direct API calls - as in this case.
There are also other things that can interfere with certain settings once applied, which require that you yourself destroy and recreate the window and re-apply your own settings.
I have seen other reports of problems in this area with the same code (not Delphi) on different versions of XP - there seems to have been a change introduced in SP2 that had some impact in this area.
In the case of EM_SETMARGINS I had the same problem you did and fixed it by looking at how the TButtonEdit control managed to apply the margins it required (which was working at least on my Windows 7 installation).
Things were perhaps made easier for me by the fact that I was implementing a custom control of my own, rather than trying to apply margins to some existing edit control. In the code snippets below, TCustomPickEdit is my custom control class, which incorporates an fButton object which holds all the settings relevant to the picker button. You will need to make suitable adjustments to apply this code in your particular situation.
What I found was the following:
Margins needed to be applied in at least 3 places. First, whenever the settings that might affect the margin were changed, second whenever the edit control window handle was created, and finally whenever the font on the edit control is changed:
Even with margins correctly set, the clipping rectangle of the control needed to be adjusted to ensure correct drawing. This required overriding the WndProc of the edit control and intercepting a couple of messages. This WndProc also needed to respond to a font change notification to reapply the margins in the event that the edit control font was changed.
The code for dealing with each of these in my case is shown below:
procedure TCustomPickEdit.ConfigureButton;
// 1. Apply margins when button settings are changed
begin
fButton.Caption := Button.Caption;
fButton.Flat := Button.Flat;
fButton.Glyph := Button.Glyph;
fButton.NumGlyphs := Button.NumGlyphs;
fButton.Visible := Button.Visible;
ApplyMargins;
end;
procedure TCustomPickEdit.CreateHandle;
// 2. Apply margins when underlying window handle is created
begin
inherited;
ApplyMargins;
end;
procedure TCustomPickEdit.WndProc(var aMessage: TMessage);
// 3. Adjust clipping rectangle for correct drawing
// 4. Apply margins when font is changed
var
top: Integer;
begin
case aMessage.Msg of
CN_CTLCOLORSTATIC,
CN_CTLCOLOREDIT : if Button.Visible then
begin
top := fButton.Top;
if ThemeServices.ThemesEnabled and Ctl3D then
Inc(top);
ExcludeClipRect(aMessage.WParam, fButton.Left,
top + 1,
fButton.Left + fButton.Width,
fButton.Height);
end;
end;
inherited;
case aMessage.Msg of
CM_FONTCHANGED : if NOT (csLoading in ComponentState) then
ApplyMargins;
end;
end;

I suspect you may need to read further into the documentation on EM_SETMARGINS. It states:
The HIWORD specifies the new width of
the right margin, in pixels. This
value is ignored if wParam does not
include EC_RIGHTMARGIN.
Edit controls and Rich Edit 3.0 and
later: The HIWORD can specify the
EC_USEFONTINFO value to set the right
margin to a narrow width calculated
using the text metrics of the
control's current font. If no font has
been set for the control, the margin
is set to zero.
Note the second paragraph regarding EC_USEFONTINFO to set a narrow width. This may be implying that this is the ONLY way to set a narrow width. I don't know for sure as I haven't tried it, but it may help.
Note also that Rich Edit Controls and regular Edit Boxes have different behaviour, so check which one you're using.

Related

Change header font on vbalGrid

I'm maintaining a VB6 application that makes extensive use of the old VBAccelerator SGrid 2.0 (vbalGrid, using another Grid control isn't really an option). I need to change the grids font at run-time, and nothing I seem to do works to change the header font, only changing the grid controls Font property at design time seems to actually change the font.
Here is the code I've tried, which I would have thought would work:
Dim Fnt As New StdFont
Set Fnt = vbalGrid.Font
Fnt.Name = "MS Sans Serif"
Set vbalGrid.Font = Fnt
This sets the font for the body of the grid just fine, but you do have to clear and repopulate the grid if it already has data. However the header doesn't change, even if you clear all the columns and recreate them.
It looks like there is a bug in the Property Set Font routine -- it does not call BuildMemDC to invalidate its buffered output DC.
Try RowHeight(1) = RowHeight(1) + 1 or similar nudge to force BuildMemDC getting called. You'll have to increase the height of some row above its internal m_lMaxRowHeight variable for the rebuild to kick in.

Can I improve upon window redraw and if so how can I?

Some years ago (2008) I wrote an online Child Support Calculator using PHP/Javascript/Ajax/css Advanced Child Support Calculator - May help to explain what I am replicating.
Some time after (2009 I think) I started writing an equivalent for Windows and am now revisiting this. The fundamentals of this version are working.
However, I have an issue with the window noticeably flickering/changing when controls are dynamically added and the window is redrawn/rebuilt.
Note! This calculator is specific to Australia.
In short I'm looking for a way, if possible, to only refresh/re-display/redraw the window after all components have been added.
Basically, the windows controls need to be dynamically added/removed depending upon the scenario (number of adults and children involved).
Adding or removing a child or adult or performing the calculation, results in a complete rebuild of the window. That is, all existing controls are destroyed and then all valid controls are added (this could perhaps be minimised via complex logic).
The issue is that controls are removed but briefly reappear (in an ordered fashion) causing the display to flicker (for want of a better description).
The following screen shots demonstrate the complexity factor (such as a child has a drop down for each defined adult), but not the flicckering(sic).
Here's a screen shot of the Initial display (OK pretty ugly at present) :-
And then if an Adult is added (note that the child now has an extra dropdown for Adult 3, the new adult):-
And now, an Adult (as above) and a Child:-
Coding wise, there is a RebuildAll function. This has two main stages. (1) The removal of the controls. (2) The rebuild (recreation) of the appropriate of the controls (Create Window, SendMessage's and then ShowWindow)
At a minimum there are 61 controls. The number of controls is
23 + ((#children * 12) - 2) + (#children * (#Adults * 8 )) + ((#adults * 10) -4). It's likely suffice to say that the number of controls increases rapidly/exponentially.
I suspect that it might be possible to postpone the ShowWindow untill after all of the builds have been done. Is the solution, as simple (theoretically) as this, assuming that this is feasible or is there another way that would circumvent the need to change all the code to remove the 'ShowWindow' and add a ShowWindow at the end of the builds?
Note replacing the individual ShowWindow's with one significantly reduced the "flicker" but didn't eliminate it. (as per Update below).
As an endnote I'm pretty sure that something should be feasible as the
windows program I have to date is a very poor reflection of the speed
of the browser/javascript version, which basically does the same thing
on windows (albeit 64bit).
Update
I went through and commented out the ShowWindows in all the AddItem???? functions and added a ShowWindows to the function that calls all the functions. This has improved matters. However, the numerous DestroyWindow calls still causes flickering when removing all of the controls. So now I guess that I'm looking for something that can disable them apparently doing an equivalent of ShowWindow.
Update 2
I have found SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); (TRUE to turn drawing back on). However, this appears to supress the DestroyWindow in that the display aspect of the control remains (the controls themselves don't appear to respond though).
By a process of elimination I have cured the flicker with a combination of ShowWindow's and WM_SETREDRAW's at pertinent points.
To briefly re-describe the issue. When adding a child or adult, or performing a calculation. The entire display is rebuilt. The rebuild basically consists of 2 phases. First, destroying the existing control windows and then adding the new/replacement set of window's controls.
The resolution was to :-
Issue a ShowWindow(hwnd,SW_SHOW); (for the main/containing
window) after all the pre-existing windows control's had been
destroyed.
Issue a WM_SETREDRAW FALSE message as per SendMessage(hwnd,
WM_SETREDRAW, FALSE, 0); before rebuilding the windows controls.
Without any ShowWindow's being used.
Build the windows controls via the various functions.
Finally, when all the windows controls have been built, issue a
ShowWindow(hwnd,SW_SHOW); (for the main/containing window).
Rather than seeing the controls appear and then disappear, "the flickering". The window is blank for a while and then the controls are displayed all at once.
I'm still confused about what is actually going on though, due to:-
After some thought I decided to use a MessageBox after all the destroys. When the message was displayed the window was blank. However, when the button was clicked and processing resumed then, in situations when the number of controls was relatively high, controls would appear and then disappear in an orderly fashion, albeit it momentarily.
My guess, is that creating a control in an area where an existing
control had been, was causing that previous control to momentarily
display.

How to ungroup popup window from the application on the taskbar?

Is it possible to instruct the shell taskbar to exclude a certain hwnd popup window from the main application's button "group"?
I have a "stopwatch" popup window. On my machine, with taskbar button combining disabled, the windows appears exactly as i'd like it: a separate item on the taskbar:
But if the user uses (the default, and most corporations prevent users from altering their personal preferences), the separate window is not visible:
Now, i am using ITaskbarList3.SetOverlayIcon to specify an overlay icon for my popup window:
list: ITaskbarList3;
list := CoTaskbarList3.Create;
list.SetOverlayIcon(windowHandle, ico, '');
so Windows will at least do me the favour of picking the most recent overlay icon, and applying it to the combined visual group - which is nice.
But i'd still prefer to have this separate action in a separate item on the taskbar.
One horrible workaround would be to ship another executable with my application; one just to fool the grouper into putting this other hwnd in its own group. But that's not something i want to do.
Why would i think i'm allowed to do this?
I was surprised to learn that you are allowed to prevent the user from pinning an application to the taskbar.
And while the MSDN page on shell programming doesn't give an example specifically for what i want, that doesn't mean it's not out there. It just might mean that it's all poorly documented.
In my case, the "operator" has a stopwatch. When they start the stopwatch, i pop out the form of the application group by giving it a different User Model Application ID:
SetWindowAppModelUserID('Contoso.Frobber.Stopwatch');
and immediately the form pops out:
When the user stops (or pauses) the stopwatch, i let the window coalesce back into the application:
SetWindowAppModelUserID('');
Caveats
You don't actually set the AppModelUserID to an empty string; that is not a valid application identifer. Instead you set it to VT_EMPTY. My helpful wrapper function checks for '', and converts it into a VT_EMPTY value.
Another warning comes from the SDK:
A window's properties must be removed before the window is closed. If this is not done, the resources used by those properties are not returned to the system. A property is removed by setting it to the PROPVARIANT type VT_EMPTY.
This means that care needs to be taken to remove a custom property applied to an HWND before i destroy it. A somewhat daunting task; one that i will almost certainly screw up.
The Code
function TFormEx.SetWindowAppModelUserID(const AppModelUserID: WideString): HRESULT;
var
ps: IPropertyStore;
value: OleVariant;
const
PKEY_AppUserModel_ID: TPropertyKey = ( fmtid: '{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}'; pid: 5);
begin
Result := SHGetPropertyStoreForWindow(Self.Handle, IPropertyStore, {out}ps);
if Failed(Result) then Exit;
if (ps = nil) then
begin
Result := E_FAIL;
Exit;
end;
if AppModelUserID <> '' then
begin
value := AppModelUserID;
Result := ps.SetValue(PKEY_AppUserModel_ID, PROPVARIANT(value));
end
else
begin
{
A window's properties must be removed before the window is closed.
If this is not done, the resources used by those properties are not returned to the system.
A property is removed by setting it to the PROPVARIANT type VT_EMPTY.
}
value := Unassigned; //the VT_EMPTY type
Result := ps.SetValue(PKEY_AppUserModel_ID, PROPVARIANT(value));
end;
end;
Bonus Reading
What if my application is really two applications bundled into a single file, and I want them collected into two groups on the taskbar in Windows 7?
How do I prevent users from pinning my program to the taskbar?
SHGetPropertyStoreForWindow function
Note: Any code released into public domain. No attribution required.

Borderless TForm with drop shadow

I have made a TForm derivative that acts like the drop down part of a combo, or a hint window, or a popup menu - a temporary thing. It has no caption - its BorderStyle is set to bsNone. The form is displayed non-modally using Show, having set its position.
To make it stand out, it needs a drop shadow around its border. However, a consequence of setting its border to bsNone is that the drop shadow disappears.
Various Google sources suggest variations of this:
procedure TdlgEditServiceTask.CreateParams(var Params: TCreateParams);
const
CS_DROPSHADOW = $00020000;
begin
inherited;
{ Enable drop shadow effect on Windows XP and later }
if (Win32Platform = VER_PLATFORM_WIN32_NT) and
((Win32MajorVersion > 5) or
((Win32MajorVersion = 5) and (Win32MinorVersion >= 1))) then
Params.WindowClass.Style := Params.WindowClass.Style or
CS_DROPSHADOW;
end;
but it doesn't work - the shadow is not displayed (unless I also set a resizable border with WS_THICKFRAME set, which looks terrible). This is a popup window, not a child window, so I don't see why it should fail.
Suggestions please?
NB: this is a similar question to this question, which remains unanswered.
NB2: There is an obscure VCL component called TShadowWindow that looks like it will do the right thing, but turns out to be too crudely written to be practical.
Update: Following Andreas' comments below, I have investigated this further, and found some niceties.
Under Windows 7, I discovered that the shadow does not appear when the popup window if it is over another window from the same application.
Here is a simple Delphi app, which uses CreateParams on a popup window to request a shadow as described above.
See how the drop shadow appears where it extends beyond the main window?
But I want to use the borderless window as a popup over the main window. The drop shadow distinguishes the popup from the window underneath. All my description up above refers to this circumstance. Obviously some Windows mechanism is interfering here.
I have also tried the same application under Windows XP. Here is how it looks.
This works correctly with shadow everywhere*. Gah!
So it would seem to be a Vista/W7 thing, as Andreas suggests.
(*An earlier version of this text and screendump suggested that no shadow appeared. However, this turned out to be because I had the Windows XP display option 'Shadows under menus' turned off. Duh.)
Found it! Here is the proof:
As you can see, the drop shadow now shows properly over the form.
The problem was one of Z-order. It turns out that the shadow is itself a separate window maintained by Windows itself. In Windows 7, it seems to show the shadow underneath the main window. In order to get it to display properly, one needs to move it up.
A genius called Łukasz Płomiński explained this in a thread in the Embarcadero newsgroup. Here is his code to sort it out:
procedure TForm1.FixSysShadowOrder;
function FindSysShadowOrderProc(WindowHandle: HWND; // handle to window
Form: TForm1 // application-defined value, 32-bit
): BOOL; stdcall;
var
Buffer: array [0 .. 255] of char;
Rect: TRect;
begin
Result := True;
if IsWindowVisible(WindowHandle) then
begin
// this code search for SysShadow window created for this window.
GetClassName(WindowHandle, Buffer, 255);
if 0 <> AnsiStrComp(Buffer, PChar('SysShadow')) then
Exit;
GetWindowRect(WindowHandle, Rect);
if (Rect.Left <> Form.Left) or (Rect.Top <> Form.Top) then
Exit;
Form.FSysShadowHandle := WindowHandle;
// stop enumeration
Result := False;
end;
end;
begin
if not(csDesigning in ComponentState) and
((GetClassLong(Handle, GCL_STYLE) and CS_DROPSHADOW) = CS_DROPSHADOW)
and IsWindowVisible(Handle) then
begin
// for speed, proper SysShadow handle is cached
if FSysShadowHandle = 0 then
EnumThreadWindows(GetCurrentThreadID(), #FindSysShadowOrderProc,
lParam(Self));
// if SysShadow exists, change its z-order, and place it directly below this window
if FSysShadowHandle <> 0 then
SetWindowPos(FSysShadowHandle, Handle, 0, 0, 0, 0,
SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOOWNERZORDER or SWP_NOSIZE);
end;
end;
You have to work out when to call FixSysShadowOrder(), because Z orders change, and it won't stay right. Łukasz suggested calling it in an idle routine (for example when updating an Action), and on receipt of WM_WINDOWPOSCHANGED message.
For making drop shadow to work we have to invoke SystemParametersInfo win32 API with SPI_SETDROPSHADOW parameter, to turn on the entire system's drop shadow effect, for more information, please refer to:
SystemParametersInfo
"It works on my computer."
(High-res)
But it is quite funny, for I have a faint memory of making the same conclusion as you make, that is, that CS_DROPSHADOW does not work without the thick, resizable, frame. Are you still running Windows Vista, perhaps?

Win32: How to custom draw an Edit control?

i need to implement the functionality of EM_SETCUEBANNER, where a text hint appears inside an Edit control:
The catch is that i cannot use version 6 of the Common Controls, which is what is required to get the Microsoft supplied implementation of a cue banner.
i've looked into simply changing the text of the edit control, and the font format to
Dark Gray Italic Text
but it will throw Change events (component wrapper provided by higher component library) that i can't find a way to avoid.
So i was instead going to custom draw the text, drawing the Cue Banner text when the control is unfocused and empty, and rely on default painting otherwise.
The Edit control doesn't nicely expose a custom drawing mechanism, like ListView, TreeView and others provide.
Other people have looked into it, but it seems to be an nearly impossible task:
From the way things are looking, I'll
have to handle the following
messages:
WM_ERASEBKGND, WM_PAINT (for obvious reasons)
WM_SETFOCUS, WM_KILLFOCUS (to prevent
the white bar from displaying --
described above)
WM_CHAR (to process and update the
text in the control)
And I also need to find a way to
display the caret in the control,
since I haven't found a way to allow
Windows to do that for me without also
painting the white bar I mentioned.
This is going to be fun. :rolleyes:
Given that the Windows Edit control was never meant to be custom drawn: does anyone know how to custom draw a Windows Edit control?
Note: i will also accept answers that solve my problem, rather than answering my question. But anyone else wanting to custom draw an Edit control, coming across this question, would probably like an answer.
Custom drawing an Edit control is essentially impossible. There are a few specialized cases were you are doing so little that can get away with it, but you risk breaking badly in the next revision of windows (or when someone runs your app on an older version, or via terminal services, etc).
Just taking over WM_PAINT and WM_ERASEBKGROUND aren't good enough, because the control will sometimes paint on other messages as well.
You are better off just writing your own edit control. I know that's a huge amount of work, but in the long run it will be less work than trying to hack your way into taking over all of the Edit controls' drawing code.
I remember back in the good old days when everyone use to subclass the button control to add color and graphics, etc. The thing is, one day I sat down and just wrote my own button window class. and it was LESS CODE than what we had in our source tree to subclass and custom draw the Windows button.
Create a window class of your own that looks like and empty edit control, that draws the cue text and shows a caret and has focus. Create the edit control also, but position it behind your window. (or leave it hidden)
Then when you get the first WM_CHAR message (or WM_KEYDOWN?). You put your window behind the edit conrol, give focus to the edit, and pass the WM_CHAR message on. From then on the edit control will take over.
You can listen to EN_CHANGE notifications from the edit control if you need to go back to showing your cue text when the edit gets empty. But I'd think that it would be fine to go back to the cue text only when the edit looses focus AND is empty.
Subclassing the EDIT control worked well for me - needed to display some formatting information to the user when editing object attributes (and some attributes could be multiple lines). The important thing, like Adrian said in his answer too, is to call the EDIT control's procedure before your own drawing. Calling it afterward or issuing your own BeginPaint/EndPaint (with return 0 or DefWindowProc) caused issues for me from the text not displaying at all, to it displaying only when resizing but not after editing, to leaving screen litter of the leftover caret. With that, I haven't had any issues regardless of the EDIT control's other repaint times.
Some setup:
SetWindowSubclass(attributeValuesEdit, &AttributeValueEditProcedure, 0, reinterpret_cast<DWORD_PTR>(this));
// Not only do multiline edit controls fail to display the cue banner text,
// but they also ignore the Edit_SetCueBannerText call, meaning we can't
// just call GetCueBannerText in the subclassed function. So store it as
// a window property instead.
SetProp(attributeValuesEdit, L"CueBannerText", L"<attribute value>");
The callback:
LRESULT CALLBACK AttributeValueEditProcedure(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam,
UINT_PTR subclassId,
DWORD_PTR data
)
{
...
case WM_PRINTCLIENT:
case WM_PAINT:
{
auto textLength = GetWindowTextLength(hwnd);
if (textLength == 0 && GetFocus() != hwnd)
{
// Get the needed DC with DCX_INTERSECTUPDATE before the EDIT
// control's WM_PAINT handler calls BeginPaint/EndPaint, which
// validates the update rect and would otherwise lead to drawing
// nothing later because the region is empty. Also, grab it from
// the cache so we don't mess with the EDIT's DC.
HDC hdc = (message == WM_PRINTCLIENT)
? reinterpret_cast<HDC>(wParam)
: GetDCEx(hwnd, nullptr, DCX_INTERSECTUPDATE|DCX_CACHE|DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS);
// Call the EDIT control so that the caret is properly handled,
// no caret litter left on the screen after tabbing away.
auto result = DefSubclassProc(hwnd, message, wParam, lParam);
// Get the font and margin so the cue banner text has a
// consistent appearance and placement with existing text.
HFONT font = GetWindowFont(hwnd);
RECT editRect;
Edit_GetRect(hwnd, OUT &editRect);
// Ideally we would call Edit_GetCueBannerText, but since that message
// returns nothing when ES_MULTILINE, use a window property instead.
auto* cueBannerText = reinterpret_cast<wchar_t*>(GetProp(hwnd, L"CueBannerText"));
HFONT previousFont = SelectFont(hdc, font);
SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
SetBkMode(hdc, TRANSPARENT);
DrawText(hdc, cueBannerText, int(wcslen(cueBannerText)), &editRect, DT_TOP|DT_LEFT|DT_NOPREFIX|DT_NOCLIP);
SelectFont(hdc, previousFont);
ReleaseDC(hwnd, hdc);
// Return the EDIT's result (could probably safely just return zero here,
// but seems safer to relay whatever value came from the edit).
return result;
}
}
break;
Writing your own EDIT control (which I've actually done more than once, to partial degrees of completeness compared to the built-in one) is not much work if you do the bare minimum (maybe English only with basic caret support), but it's a LOT of work to get correct if you want caret navigation over complex scripts with variable sized clusters, selection over ranges, IME support, context menus with copy and paste, high contrast modes, and accessibility features such as text to speech. So unlike so many other answers, I recommend not implementing your own EDIT control merely for cue banner text.
Subclass the edit control. Handle WM_PAINT by first calling the original window procedure and then, if it's empty and not in focus, draw the cue text. Pass every other message to the original window procedure.
I've done this--it works. The problem the CodeGuru person had doesn't seem to apply to your situation. I believe he's trying to do more to the appearance. For performance, it looks like the edit control is doing some updates outside of WM_PAINT processing (probably for performance). That's going to make it nearly impossible to take complete control of the appearance. But you CAN draw the cue prompt.
And I also need to find a way to display the caret in the control,
since I haven't found a way to allow Windows to do that for me without
also painting the white bar I mentioned.
If you want to handle WM_PAINT by yourself without forwarding the message to the original windowproc of your superclass, you should not forget to call DefWindowProc. So that the caret will be drawn.
To avoid the white bar you should remove class brush with SetClassLongPtr.
And somehow keep your DC's clipping region to clip Edit controt's ExtTextOut outputs.
The white bar may be the result of OPAQUE option passed to ExtTextOut by Edit control.
Conclusion: Write your own control. No pain, no gain.

Resources