EM_UNDO does not work after programmatically writing to rich edit - winapi

Working in C++ Builder 10 Seattle on Win7-64.
I have a TRichEdit control into which I can write from a button click event:
MyRichEdit->SelText = t_string;
I want to be able to undo that change, so I have a menu item with shortcut Ctrl+Z that does this:
SendMessage(MyRichEdit->Handle, EM_UNDO, 0, 0);
The Undo works as expected if I have typed into the rich edit, but not to undo the programmatically assigned "paste".
I had similar code in an old application that was built with Borland C++ Builder v6, and it works there.
My question then is: Should the above code undo the write-to-SelText? Or is there something else I need to do?

The implementation of the SelText setter looks like this:
procedure TCustomEdit.SetSelText(const Value: string);
begin
SendTextMessage(Handle, EM_REPLACESEL, 0, Value);
end;
The documentation for EM_REPLACESEL says:
Parameters
wParam
Specifies whether the replacement operation can be undone. If this is
TRUE, the operation can be undone. If this is FALSE , the operation
cannot be undone.
lParam
A pointer to a null-terminated string containing the replacement text.
The VCL is sending 0 which is FALSE and so the operation cannot be undone. You will need to avoid using SelText and instead send the EM_REPLACESEL directly, passing TRUE as wParam.
I examined the source code for the Delphi 6 VCL and it too always passes 0 for wParam when sending this message, so I would have expected the old versions of the VCL to behave in the same way. All the same, you now know how to resolve the issue.
As an aside, you can replace sending of EM_UNDO with a call to MyRichEdit->Undo() which does exactly the same thing.

Related

aborting Windows IME composition / clearing composition string

I'm having trouble aborting IME composition on Windows.
I'm handling WM_IME_STARTCOMPOSITION and positioning my candidate window, and WM_IME_COMPOSITION as I press a key to start composing as you'd expect. I'm then handling WM_IME_ENDCOMPOSITION at the end and normal use cases are fine.
However, my problem is when I change focus inside of the application. I don't receive WM_IME_ENDCOMPOSITION so I have to deal with this situation manually. What I am doing is this:
ImmNotifyIME( himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0 );
ImmNotifyIME( himc, NI_CLOSECANDIDATE, 0, 0 );
The candidate list correctly disappears, but the composition string isn't cleared. If I then call ImmGetCompositionString with GCS_COMPSTR, it's still there. Therefore if I give focus back, receive WM_IME_STARTCOMPOSITION and the first WM_IME_COMPOSITION - I end up inheriting the previous composition string, which I don't want. I want to start afresh.
ImmSetCompositionString() looks also like it would work but I can't figure out how to get it to clear the string.
Does anyone have any suggestions? MSDN seems to suggest that the calls to ImmNotifyIME() would do the job, but I must be missing something.
You may clear composition with this:
ImmSetCompositionStringW(himc, SCS_SETSTR, L"", sizeof(wchar_t), L"", sizeof(wchar_t));
In addition, in my application, when input loses focus I release input context:
ImmReleaseContext(hwnd, himc);
And get it again when focus gained:
ImmGetContext(hwnd);

What is the maximum length of a window title passed to SetWindowText?

The SetWindowText function's documentation does not set a limit on the length of the string that may be used as a window title.
In the documentation for WM_SETTEXT (the message sent by calling SetWindowText), it is noted that the return value of this message's processing may be:
FALSE (for an edit control), LB_ERRSPACE (for a list box), or CB_ERRSPACE (for a combo box) if insufficient space is available to set the text in the edit control.
However, it says nothing about the case when a window's title is being set. Is a strict limit set, or is it up to the programmer to use common sense to provide their own title length limit?
I have posted this because I am developing a graphics engine which allows the user to supply their own title for the main window. The idea is that I would define a constant such as
const static int MAX_APP_TITLE_LENGTH = /* ??? */;
within my application class, and check the length of the user-provided title string against this.
If the title string is too long, I can throw a warning message and truncate it, rather than passing it straight into SetWindowText with unintended consequences.
EDIT: After some discussion in the comments, it seems that Windows will not complain even if a string of length 100,000 is used as a window title, so this issue is not worth worrying about (beyond the basic sanitization of input, of course)!
There is technically no limit to the title size, but the lpClassName field has a strict limit of 256 chars (i didnt want you to think you could have an infinite class name and your code crash.)
SOURCE: https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw

Determine if Control key was used to generate character in WM_CHAR

When receiving character input, is there a way to know whether the character code in wParam was generated as a result of the keyboard state we get back from GetKeyboardState()? For example, if you hit Ctrl+A then the character 'a' would not be a result of the control key but if you're using a Swedish keyboard and type Ctrl+Alt+7 the result would be {. In that case, is there any way of knowing that the keyboard state (Ctrl and Alt) were necessary to generate that character code?
(To be honest, as an English speaker who has really only ever used a US keyboard layout, I have no definite idea that this will work, but...) I believe that the VkKeyScan function (or VkKeyScanEx) might do what you want.
As input, it takes a character, not a scan code or a virtual key, so this is the wParam value that you get from WM_CHAR.
Its return is a value that provides both the virtual-key code (which I guess you can ignore) in the low-byte, and the (mis-named) "shift state" in the high-byte, which is actually a set of flags representing the qualifier keys needed to produce that character.
So if you get a WM_CHAR message and wanted to tell if the control key was needed in order to generate it, in theory you could do:
case WM_CHAR:
if (HIBYTE(VkKeyScan((TCHAR)wParam)) & 2) {
// control pressed!
}
break;
If you are only looking at the data provided by the WM_CHAR message, then no. You would likely have to look at the WM_KEY... messages to keep track of what the surrounding keystrokes where doing at the time, if Get(Async)KeyboardState() does not provide what you need.

How to programmatically trigger Flip 3D on Windows?

How do I programmatically trigger Flip 3D on Windows Vista and 7?
Is there an API for this and if so, what is it called and where can I find the relevant functions? (I need a specific answer, eg a web link to the actual functions, not something generic like "Oh, it's in DirectX.")
On a related node, I have a Logitech mouse that has a "Document Flip" button that invokes Flip 3D (and then I can press up/down keys to page through the results.) I am curious if they are using an official Windows API or if there is some low level hackery going on.
you need to run a function from dwmapi
Sadly there is no proper funktion name only the ord-number 105
You can try this by executing %WinDir%\System32\rundll32.exe dwmapi #105 from Run-dialog or cmd.
edit
ive found out the Windows' API GetProcAddress Function accepts ord-numbers (the 105) as second parameter as well as proper name
lpProcName [in]
The function or variable name, or the function's ordinal value. If this parameter is an ordinal value, it must be in the low-order word; the high-order word must be zero.
so use this code
typedef vois (__cdecl *FlipProc)();
HINSTANCE hDwmApi = LoadLibrary(TEXT("dwmapi.dll"));
FlipProcAdd = (FlipProc) GetProcAddress(hDwmApi, (LPCSTR)105);
(FlipProcAdd)();

What's so bad about using button captions as variables in VB6?

I received some justified critical feedback on my last question (How to gracefully exit from the middle of a nested subroutine when user cancels?) for using the caption of a command button as a state variable. I did it because it's efficient, serving two or three purposes at once with very little code, but I understand how it could also cause problems, particularly in the slightly sloppy way I originally presented it.
I feel like this deserves its own discussion, so here's the same idea cleaned up a bit and modified to do it "right" (which basically means defining the strings in a single place so your code won't start failing because you simply changed the text of a command button). I know my variable and control naming convention is poor (OK, nonexistent), so apologies in advance. But I'd like to stay focused on the caption as state variable discussion.
So here we go:
' Global variables for this form
Dim DoTheThingCaption(1) As String
Dim UserCancel, FunctionCompleted As Boolean
Private Sub Form_Initialize()
' Define the possible captions (is there a #define equivalent for strings?)
DoTheThingCaption(0) = "Click to Start Doing the Thing"
DoTheThingCaption(1) = "Click to Stop Doing the Thing"
' Set the caption state when form initializes
DoTheThing.Caption = DoTheThingCaption(0)
End Sub
Private Sub DoTheThing_Click() ' Command Button
If DoTheThing.Caption = DoTheThingCaption(0) Then
UserCancel = False ' this is the first time we've entered this sub
Else ' We've re-entered this routine (user clicked on button again
' while this routine was already running), so we want to abort
UserCancel = True ' Set this so we'll see it when we exit this re-entry
DoTheThing.Enabled = False 'Prevent additional clicks
Exit Sub
End If
' Indicate that we're now Doing the Thing and how to cancel
DoTheThing.Caption = DoTheThingCaption(1)
For i = 0 To ReallyBigNumber
Call DoSomethingSomewhatTimeConsuming
If UserCancel = True Then Exit For ' Exit For Loop if requested
DoEvents ' Allows program to see GUI events
Next
' We've either finished or been canceled, either way
' we want to change caption back
DoTheThing.Caption = DoTheThingCaption(0)
If UserCancel = True Then GoTo Cleanup
'If we get to here we've finished successfully
FunctionCompleted = True
Exit Sub '******* We exit sub here if we didn't get canceled *******
Cleanup:
'We can only get to here if user canceled before function completed
FunctionCompleted = False
UserCancel = False ' clear this so we can reenter later
DoTheThing.Enabled = True 'Prevent additional clicks
End Sub '******* We exit sub here if we did get canceled *******
So there it is. Is there still anything really that bad about doing it this way? Is it just a style issue? Is there something else that would give me these four things in a more desirable or maintainable way?
Instant GUI feedback that user's button press has resulted in action
Instant GUI feedback in the location where user's eyes already are on how to CANCEL if action is not desired
A one-button way for users to start/cancel an operation (reducing the amount of clutter on the GUI)
A simple, immediate command button disable to prevent multiple close requests
I can see one concern might be the close coupling (in several ways) between the code and the GUI, so I could see how that could get to be a big problem for large projects (or at least large GUIs). This happens to be a smaller project where there are only 2 or 3 buttons that would receive this sort of "treatment".
The single biggest problem with this technique is that it uses a string as a boolean. By definition, a boolean variable can have only two states, while a string can have any number of states.
Now, you've mitigated the danger inherent in this somewhat by relying on an array of predefined strings to define allowed values for the command button text. This leaves a handful of lesser issues:
Logic is less-than-explicit regarding current and available states (there are actually four possible states for the form: not-started, started, completed, started-but-canceling) - maintenance will require careful observation of the potential interactions between button text and boolean variable states to determine what the current state is / should be. A single enumeration would make these states explicit, making the code easier to read and understand, thereby simplifying maintenance.
You're relying on the behavior of a control property (button text) to remain consistent with that of the exposed property value type (string). This is the sort of assumption that makes migrating old VB6 code to newer languages / platforms absolute hell.
String comparison is much, much slower than a simple test of a boolean variable. In this instance, this won't matter. In general, it's just as easy to avoid it.
You're using DoEvents to simulate multi-threading (not directly relevant to the question... but, ugh).
The biggest issue i've come accross when working on (very old) code like this [button captions as variables] is that globalisation is a nightmare.... I had to move a old vb6 app to use English and German... it took weeks, if not months.
You're using goto's as well..... a bit of refactoring needed perhaps to make the code readable??
**Edit in response to comments
I'd only use a goto in vb6 at the top of each proc;
on error goto myErrorHandler.
then at the very bottom of the proc i'd have a one liner that would pass err to a global handler, to log the error.
Ignoring the general architecture/coupling problems because you are aware of those issues, one problem with your approach is because VB6 controls do magic stuff when you set properties.
You may think you are just setting a property but in many cases you are causing events to fire also. Setting a checkbox value to true fires the click event. Setting the tabindex on a tab control causes a click event. There are many cases.
If I remember correctly I also think there are scenarios where if you set a property, and then read it immediately, you will not see the update. I believe a screen refresh has to occur before you see the new value.
I have seen too much horrible VB6 code that uses control properties as storage. If you ever find this kind of code you will recognize it because it is scattered with redundant calls to Refresh methods, DoEvents and you will frequently see the UI get hung. This is often caused by infinite loops where a property is set, an event is fired and then another property is set and eventually someone writes a line of code that updates the first property again.
If those issues don't scare you enough then think of this. Some of us just are not that smart. I've been coding in VB6 for over 10 years and have personally written probably around 750K LOC and I keep staring at your example above and I find it very difficult to understand what it going on. Assume that all the people that will need to read your code in the future will be really dumb and make us happy by writing really simple looking code.
I think it's better to decouple the caption text from the state of processing. Also the goto's make it hard to read. Here is my refactored version...
Private Const Caption_Start As String = "Click to Start Doing the Thing"
Private Const Caption_Stop As String = "Click to Stop Doing the Thing"
Private Enum eStates
State_Initialized
State_Running
State_Canceled
State_Completed
End Enum
Private Current_State As eStates
Private Sub Form_Initialize()
DoTheThing.Caption = Caption_Start
Current_State = State_Initialized
End Sub
Private Sub DoTheThing_Click()
If Current_State = State_Running Then
'currently running - so set state to canceled, reset caption'
'and disable button until loop can respond to the cancel'
Current_State = State_Canceled
DoTheThing.Caption = Caption_Start
DoTheThing.Enabled = False
Else
'not running - so set state and caption'
Current_State = State_Running
DoTheThing.Caption = Caption_Stop
'do the work'
For i = 0 To ReallyBigNumber
Call DoSomethingSomewhatTimeConsuming
'at intervals check the state for cancel'
If Current_State = State_Canceled Then
're-enable button and bail out of the loop'
DoTheThing.Enabled = True
Exit For
End If
DoEvents
Next
'did we make it to the end without being canceled?'
If Current_State <> State_Canceled Then
Current_State = State_Completed
DoTheThing.Caption = Caption_Start
End If
End If
End Sub
Apart from removing the GOTos as DJ did in his answer, there is nothing really wrong about your approach. The button caption can have only two states, and you use those two states to define the flow in your code.
I have however two reasons why I would do it differently:
Your method creates problems when you want to translate your program into a different language (in my experience you should always plan for that), because the captions would change in another language
It goes against the principle of seperating the user interface from the program flow. This may not be an important thing for you, but when a program gets bigger and more complex, having a clear seperation of the UI from the logic makes things much easier.
To sum it up, for the case at hand your solution certainly works, and there is no reason why it shouldn't. But on the other hand experience has taught us that with more complex programs, this way can cause problems which you can easily avoid by using a slightly different approach.
Also, I think it is safe to assume that everybody who criticised your example did so because they made a simnilar choice at some point, and later realised that it was a mistake.
I know I did.
This ties your underlying algorithm to specific behavior in your UI. Now, if you want to change either one of them, you have to make changes to both. As your app grows in size, if you don't keep your changes local by encapsulating logic, maintenance will become a nightmare.
If anyone for any reason ever needs to work on your code, they won't find practices and conventions they are familiar and comfortable with, so the boundaries of functionality won't exist. In other words, you are headed in the wrong direction on the Coupling/Cohesion trail. Functionally integrating State management with the UI is the classic poster child for this issue.
Do you understand OOP at all? (Not a criticism, but a legitimate question. If you did, this would be a lot clearer to you. Even if it's only VB6 OOP.)
Localization has the biggest impact on the type of logic OP is presenting. As several people mentioned it - what if you need to translate the app into Chinese? And German? And Russian?
You'd have to add additional constants covering those languages too... pure hell. GUI data should remain what it is, a GUI data.
The method OP describes here reminded me what Henry ford said: "Any customer can have a car painted any color that he wants so long as it is black".

Resources