Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 106 additions & 75 deletions Demo/RxMain.dfm
Original file line number Diff line number Diff line change
@@ -1,75 +1,106 @@
object RXForm: TRXForm
Left = 0
Top = 0
BorderWidth = 4
Caption = 'Receiver'
ClientHeight = 347
ClientWidth = 440
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OnDestroy = FormDestroy
TextHeight = 13
object Memo: TMemo
Left = 0
Top = 32
Width = 440
Height = 315
Align = alClient
ReadOnly = True
ScrollBars = ssVertical
TabOrder = 0
end
object TopPanel: TPanel
Left = 0
Top = 0
Width = 440
Height = 32
Align = alTop
BevelOuter = bvNone
BorderWidth = 4
TabOrder = 1
DesignSize = (
440
32)
object ReceiverEdit: TEdit
Left = 4
Top = 4
Width = 121
Height = 24
Align = alLeft
TabOrder = 0
Text = 'ReceiverWindow'
ExplicitHeight = 21
end
object btnStart: TButton
Left = 284
Top = 2
Width = 75
Height = 24
Anchors = [akTop, akRight]
Caption = 'Start'
TabOrder = 1
OnClick = btnStartClick
end
object btnStop: TButton
Left = 365
Top = 2
Width = 75
Height = 24
Anchors = [akTop, akRight, akBottom]
Caption = 'Stop'
TabOrder = 2
OnClick = btnStopClick
end
end
object WMsgReceiver: TWMsgReceiver
WindowName = 'DefaultWindow'
OnMessageReceived = WMsgReceiverMessageReceived
Left = 312
Top = 184
end
end
object RXForm: TRXForm
Left = 0
Top = 0
BorderWidth = 4
Caption = 'Receiver'
ClientHeight = 347
ClientWidth = 440
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OnCreate = FormCreate
OnDestroy = FormDestroy
TextHeight = 13
object Memo: TMemo
Left = 0
Top = 64
Width = 440
Height = 283
Align = alClient
ReadOnly = True
ScrollBars = ssVertical
TabOrder = 0
ExplicitTop = 32
ExplicitHeight = 315
end
object TopPanel: TPanel
Left = 0
Top = 0
Width = 440
Height = 32
Align = alTop
BevelOuter = bvNone
BorderWidth = 4
TabOrder = 1
DesignSize = (
440
32)
object ReceiverEdit: TEdit
Left = 4
Top = 4
Width = 121
Height = 24
Align = alLeft
TabOrder = 0
Text = 'ReceiverWindow'
OnChange = ReceiverEditChange
ExplicitHeight = 21
end
object btnStart: TButton
Left = 284
Top = 2
Width = 75
Height = 24
Anchors = [akTop, akRight, akBottom]
Caption = 'Start'
TabOrder = 1
OnClick = btnStartClick
end
object btnStop: TButton
Left = 365
Top = 2
Width = 75
Height = 24
Anchors = [akTop, akRight, akBottom]
Caption = 'Stop'
Enabled = False
TabOrder = 2
OnClick = btnStopClick
end
end
object SubPanel: TPanel
Left = 0
Top = 32
Width = 440
Height = 32
Align = alTop
BevelOuter = bvNone
BorderWidth = 4
TabOrder = 2
ExplicitTop = 8
DesignSize = (
440
32)
object chkUIPI: TCheckBox
Left = 4
Top = 6
Width = 436
Height = 17
Anchors = [akLeft, akTop, akRight]
Caption = 'Enable messages from processes with lower user execution level'
TabOrder = 0
OnClick = chkUIPIClick
end
end
object WMsgReceiver: TWMsgReceiver
Active = False
LowProcessMessages = False
WindowName = 'DefaultWindow'
OnMessageReceived = WMsgReceiverMessageReceived
Left = 312
Top = 184
end
end
85 changes: 55 additions & 30 deletions Demo/RxMain.pas
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@
interface

uses
Winapi.Windows, Winapi.Messages,
System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,Vcl.ExtCtrls,

WMsgReceiver;
Forms, Classes, Controls, StdCtrls, ExtCtrls, WMsgReceiver;

type
TRXForm = class(TForm)
Expand All @@ -17,16 +13,18 @@ TRXForm = class(TForm)
btnStart: TButton;
btnStop: TButton;
WMsgReceiver: TWMsgReceiver;
SubPanel: TPanel;
chkUIPI: TCheckBox;

procedure FormDestroy(Sender: TObject);
procedure btnStartClick(Sender: TObject);
procedure btnStopClick(Sender: TObject);
procedure WMsgReceiverMessageReceived(aID: Cardinal; aMsg: string);
procedure ReceiverEditChange(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure chkUIPIClick(Sender: TObject);
private
{ Private declarations }
procedure StopTheReceiver;
public
{ Public declarations }
procedure UpdateUI;
end;

var
Expand All @@ -37,42 +35,69 @@ implementation
{$R *.dfm}

uses
WMsgCommon;
SysUtils, Windows, WMsgCommon;

function IsRunAsAdministrator: Boolean;
const
ELEVATION_FULL = 2;
var
hToken: THandle;
dwElevation, dwSize: Cardinal;
begin
Result := False;
if OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, hToken) then try
dwElevation := 0;
Result := (GetTokenInformation(hToken, TokenElevationType, @dwElevation, SizeOf(Cardinal), dwSize)) and (dwElevation = ELEVATION_FULL);
dwElevation := 0;
Result := Result or (((GetTokenInformation(hToken, TokenElevation, @dwElevation, SizeOf(Cardinal), dwSize))) and (dwElevation > 0))
finally
CloseHandle(hToken)
end
end;

procedure TRXForm.btnStartClick(Sender: TObject);
begin
StopTheReceiver;
if Length(Trim(ReceiverEdit.Text)) = 0 then
ReceiverEdit.Text := WMSG_DEFAULT_WINDOW;

WMsgReceiver.OnMessageReceived := WMsgReceiverMessageReceived;
if not (Trim(ReceiverEdit.Text) = '')
then
begin
WMsgReceiver.WindowName := ReceiverEdit.Text
end
else
begin
WMsgReceiver.WindowName := WMSG_DEFAULT_WINDOW;
ReceiverEdit.Text := WMsgReceiver.WindowName;
end;
WMsgReceiver.WindowName := ReceiverEdit.Text;
WMsgReceiver.Start;
UpdateUI
end;

procedure TRXForm.btnStopClick(Sender: TObject);
begin
StopTheReceiver;
WMsgReceiver.Stop;
UpdateUI
end;

procedure TRXForm.chkUIPIClick(Sender: TObject);
begin
WMsgReceiver.LowProcessMessages := chkUIPI.Checked
end;

procedure TRXForm.FormCreate(Sender: TObject);
begin
chkUIPI.Enabled := IsRunAsAdministrator
end;

procedure TRXForm.FormDestroy(Sender: TObject);
begin
StopTheReceiver;
end;

procedure TRXForm.StopTheReceiver;
begin
WMsgReceiver.OnMessageReceived := nil;
WMsgReceiver.Stop;
WMsgReceiver.Stop
end;

procedure TRXForm.ReceiverEditChange(Sender: TObject);
begin
UpdateUI
end;

procedure TRXForm.UpdateUI;
begin
ReceiverEdit.Enabled := not WMsgReceiver.Active;
btnStart.Enabled := not WMsgReceiver.Active and (Length(Trim(ReceiverEdit.Text)) > 0);
btnStop.Enabled := WMsgReceiver.Active
end;

procedure TRXForm.WMsgReceiverMessageReceived(aID: Cardinal; aMsg: string);
begin
Memo.Lines.Add(aID.ToString +', '+ aMsg);
Expand Down
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,24 @@ Window Names: WM_COPYDATA relies on finding the target window handle by name. En

Data Limits: While WM_COPYDATA is efficient, it is intended for small-to-medium data packets. For multi-gigabyte transfers, consider memory-mapped files.

## ⚠️ Limitations

### User Interface Privilege Isolation

Under Windows Vista and later, UIPI prevents by default certain messages, including `WM_COPYDATA` being delivered from lower execution level process to higher execution level processes. APIs have been introduced for a high execution level process to allow these to be delivered to himself. Under Vista the isolation can be turned off for a certain message at process level, this means all windows created by the same process receive the message after being enabled, starting from Windows 7 isolation is at window level, meaning each window can set its own accepted messages.

The code has been written to take advantage from the later and, if not available, from the previous, while maintaining retro compatibility with pre-Vista operating systems.

A new `LowProcessMessages` property has been added to the `TWMsgReceiver` component, setting it to true will allow lower execution level processes' messages to be delivered to the elevated receiver.

Settings this into low execution level processes has no effect.

To test this, execute `TxDemo.exe` normally while running `RxDemo.exe` as Administrator.

### Windows Stations isolation

This component it not designed to be used in case you need IPC for processes running under different windows stations, for example if you need a desktop or console application which is running under the interactive user windows station (`WinSta0`) to communicate with a service (which is running in Session 0).

# 📄 License
This project is licensed under the MIT License - see the LICENSE file for details.

Expand All @@ -66,6 +84,4 @@ If you have questions, find a bug, or want to suggest a feature for the **Window
* **Website:** [latitude53north.co.uk](https://latitude53north.co.uk)

> [!TIP]
> If you encounter an issue with window handle detection, please include your Windows version and Delphi edition in the [Issue Tracker](https://github.com/antonydanby/WindowsMessaging/issues).
>
>
> If you encounter an issue with window handle detection, please include your Windows version and Delphi edition in the [Issue Tracker](https://github.com/antonydanby/WindowsMessaging/issues).
Loading