I placed a RichTextBox control on a new form and launched the project. So the RichTextBox.Text = "";
Each time I press Up or Down keys I heard the annoying BEEP sound! How to get rid of this issue?
Using "e.SuppressKeyPress = true" in the KeyDown method locks the Cursor position.
first we need send EM_GETOLEINTERFACE
message to rich edit window - this is Retrieves an IRichEditOle object that a client can use to access a rich edit control's Component Object Model (COM) functionality.
then for retrieve an ITextServices
pointer, call QueryInterface
on the private IUnknown
pointer returned by EM_GETOLEINTERFACE
.
here exist interesting point - the IID_ITextServices
not well known but need get in runtime from Msftedit.dll
from About Windowless Rich Edit Controls
Msftedit.dll exports an interface identifier (IID) called IID_ITextServices that you can use to query the IUnknown pointer for the ITextServices interface.
after we got ITextServices
pointer - we simply can call OnTxPropertyBitsChange(TXTBIT_ALLOWBEEP, 0)
code example:
if (HMODULE hmodRichEdit = LoadLibrary(L"Msftedit.dll"))
{
// create richedit window
if (HWND hwndRich = CreateWindowExW(0, MSFTEDIT_CLASS, ...))
{
if (IID* pIID_ITS = (IID*) GetProcAddress(hmodRichEdit, "IID_ITextServices"))
{
IUnknown* pUnk;
if (SendMessageW(hwndRich, EM_GETOLEINTERFACE, 0, (LPARAM)&pUnk))
{
ITextServices* pTxtSrv;
HRESULT hr = pUnk->QueryInterface(*pIID_ITS, (void**)&pTxtSrv);
pUnk->Release();
if (0 <= hr)
{
pTxtSrv->OnTxPropertyBitsChange(TXTBIT_ALLOWBEEP, 0);
pTxtSrv->Release();
}
}
}
}
}
The following is a .Net implementation of using the ITextServices interface method described in @RbMm's answer. If you find this useful, please consider upvoting that answer.
This implementation exposes two extension methods (EnableBeep
and DisableBeep
) for the Winform RichTextBox. Both a C# and Vb.Net version are provided.
As we are only interested in using the OnTxPropertyBitsChange
function defined in the ITextServices interface, an abbreviated implementation of the interface is used similar to those created when "Embed Interop Types" is used for a COM reference. If you have installed the Windows SDK, you should find the "TextServ.h" file at a path similar to "C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\um\TextServ.h". This file defines the full ITextServices class interface.
C# version
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
//----
public static class RTBBeepExtensions
{
public static void EnableBeep(this RichTextBox rtb)
{
SetBeepInternal(rtb, true);
}
public static void DisableBeep(this RichTextBox rtb)
{
SetBeepInternal(rtb, false);
}
private static void SetBeepInternal(RichTextBox rtb, bool beepOn)
{
const Int32 WM_USER = 0x400;
const Int32 EM_GETOLEINTERFACE = WM_USER + 60;
const Int32 COMFalse = 0;
const Int32 COMTrue = ~COMFalse; // -1
ITextServices textServices = null;
// retrieve the rtb's OLEINTERFACE using the Interop Marshaller to cast it as an ITextServices
// The control calls the AddRef method for the object before returning, so the calling application must call the Release method when it is done with the object.
SendMessage(new HandleRef(rtb, rtb.Handle), EM_GETOLEINTERFACE, IntPtr.Zero, ref textServices);
textServices.OnTxPropertyBitsChange(TXTBIT.ALLOWBEEP, beepOn ? COMTrue : COMFalse));
Marshal.ReleaseComObject(textServices);
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private extern static IntPtr SendMessage(HandleRef hWnd, Int32 msg, IntPtr wParam, ref ITextServices lParam);
#region ITextServices // From TextServ.h
[ComImport(), Guid("8d33f740-cf58-11ce-a89d-00aa006cadc5"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface ITextServices
{
//see: Slots in the V-table
// https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/metadata/imetadataemit-definemethod-method#slots-in-the-v-table
void _VtblGap1_16();
Int32 OnTxPropertyBitsChange(TXTBIT dwMask, Int32 dwBits);
}
private enum TXTBIT : uint
{
/// <summary>If TRUE, beeping is enabled.</summary>
ALLOWBEEP = 0x800
}
#endregion
}
VB.Net version
Imports System
Imports System.Runtime.InteropServices
Imports System.Runtime.CompilerServices
Imports System.Windows.Forms
' -------
Public Module RTBBeepExtensions
<Extension()>
Public Sub EnableBeep(rtb As RichTextBox)
SetBeepInternal(rtb, True)
End Sub
<Extension()>
Public Sub DisableBeep(rtb As RichTextBox)
SetBeepInternal(rtb, False)
End Sub
Private Sub SetBeepInternal(rtb As RichTextBox, beepOn As Boolean)
Const WM_USER As Int32 = &H400
Const EM_GETOLEINTERFACE As Int32 = WM_USER + 60
Const COMFalse As Int32 = 0
Const COMTrue As Int32 = Not COMFalse ' -1
Dim textServices As ITextServices = Nothing
' retrieve the rtb's OLEINTERFACE using the Interop Marshaller to cast it as an ITextServices
' The control calls the AddRef method for the object before returning, so the calling application must call the Release method when it is done with the object.
SendMessage(New HandleRef(rtb, rtb.Handle), EM_GETOLEINTERFACE, IntPtr.Zero, textServices)
textServices.OnTxPropertyBitsChange(TXTBIT.ALLOWBEEP, If(beepOn, COMTrue, COMFalse))
Marshal.ReleaseComObject(textServices)
End Sub
<DllImport("user32.dll", CharSet:=CharSet.Auto)>
Private Function SendMessage(ByVal hWnd As HandleRef, ByVal msg As Int32, ByVal wParam As IntPtr, ByRef lParam As ITextServices) As IntPtr
End Function
#Region "ITextServices" ' From TextServ.h
<ComImport(), Guid("8d33f740-cf58-11ce-a89d-00aa006cadc5"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
Private Interface ITextServices
'see: Slots in the V-table
' https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/metadata/imetadataemit-definemethod-method#slots-in-the-v-table
Sub _VtblGap1_16()
Function OnTxPropertyBitsChange(ByVal dwMask As TXTBIT, ByVal dwBits As Int32) As Int32
End Interface
Private Enum TXTBIT As UInt32
''' <summary>If TRUE, beeping is enabled.</summary>
ALLOWBEEP = &H800
End Enum
#End Region
End Module
If you are unfamiliar with using extension methods, please refer to the following documentation links.
Extension Methods (C# Programming Guide)
Extension Methods (Visual Basic)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With