INDY 10 TCP Server - Combine with non thread safe VCL Code - indy

VCL is not thread safe. Therefore I guess it is not a good idea to write information to the gui in the INDY 10 TCP server.execute(...) function .
How to send information from the server execute to the VCL ?
I need to modify a TBitmap inside a tcpserver.execute function. How to make that thread safe ?

Write stuff to the VCL thread from Indy the same way to write stuff to the VCL thread from anywhere else. Common options include TThread.Synchronize and TThread.Queue.
Modifying a standalone TBitmap should not require synchronization with the main thread. You can modify it from any thread you want, as long as you do it from only one thread at a time. You can use the standard synchronization objects like critical sections and events to make sure only one thread uses it at a time.

the best way to synch is by creating and using a TidNotify descendant.
define a tidnotify descendant and vcl proc like this with the appropriate private fields.
TVclProc= procedure(aBMP: TBitmap) of object;
TBmpNotify = class(TIdNotify)
protected
FBMP: TBitmap;
FProc: TVclProc;
procedure DoNotify; override;
public
constructor Create(aBMP: TBitmap; aProc: TVclProc); reintroduce;
class procedure NewBMP(aBMP: TBitmap; aProc: TVclProc);
end;
then implement it like this
{ TBmpNotify }
constructor TBmpNotify.Create(aBMP: TBitmap; aProc: TVclProc);
begin
inherited Create;
FBMP:= aBMP;
FProc:= aProc;
end;
procedure TBmpNotify.DoNotify;
begin
inherited;
FProc(FBMP);
end;
class procedure TBmpNotify.NewBMP(aBMP: TBitmap; aProc: TVclProc);
begin
with Create(aBMP, aProc) do
begin
Notify;
end;
end;
then from the
server.execute(...)
call it like this
procedure TTCPServer.DoExecute(aContext: TIdContext);
var
NewBMP: TBitmap;
begin
TBmpNotify.NewBMP(NewBMP, FVclBmpProc);
end;
Where the FVclBmpProcis a private field pointing to a procedure on the form that matches the parameter signature of TVclProc. This field should be set via a property on the server object just after creation and before starting the server.
the method on the form will be free to use the bitmap it receives without fear of thread contention, deadlock and other nasties created by accessing the VCL controls without synchronisation.

One simple PostMessage (inside the thread) and handling message (outside the thread) was necessary to make UI updates...

Related

Initialize shared variables in a message flow with esql

I'm using IBM Integration Bus Version 10.0.0.15 and I'm looking for an option to intialize shared variables during the startup of a message flow, for example uing the command mqsistartmsgflow. Is there a special procedure or function one can implement with ESQL which is guranteed to be excuted during start up?
In the ESQL documentation it is stated that shared variables are intialized when the first message is routed through the flow which means you have to wait for the first message.
Actually you need to initialise them this typically looks something like.
-- Shared row variable for caching config data. Declared at Global scope.
DECLARE S_ConfigSharedRow SHARED ROW;
CREATE COMPUTE MODULE TheFirstComputeNode
CREATE FUNCTION Main() RETURNS BOOLEAN
BEGIN
CFGDATA_CACHE_LOCK: BEGIN ATOMIC
-- If the configuration data is not available in the cache then load it from the CONFIG table
DECLARE CfgDataRef REFERENCE TO S_ConfigSharedRow.CfgDataCache;
IF NOT LASTMOVE(CfgDataRef) THEN
-- Select all the relevant content from the actual database in one go.
DECLARE DBResults ROW;
DECLARE RetryCount INTEGER 5;
SET DBResults.Row[] = PASSTHRU('SELECT * FROM CONFIG');
-- Typically you would post process the content from the DB into a more amenable
-- structure but the following will get the data into the shared variable
CREATE LASTCHILD OF S_ConfigSharedRow.CfgDataCache FROM DBResults;
END IF;
END CFGDATA_CACHE_LOCK;
-- Config data is now available for use
RETURN TRUE;
END;
END MODULE;
I think the best way is to have a dedicated flow for initializing shared variables.
That flow should have an input queue separate from the normal input queue, just for sending in messages to trigger the initialization.
Then you should make a startup script, which sends a message to this init flow after starting up the main processing flow.
And use only that script for startup.
If you want another option, you could include a JavaCompute node and add some once-only initialisation into its class using a static initialization block. You would only be able to initialize Java data structures this way, though.

Cannot inspect variable inside Indy OnExecute event

using Indy with Delphi XE8 for a Tcp Server application I had necessity to inspect some local variables inside OnExecute event.
But setting a Breakpoint I do not understand why I get error "E2003 undeclared identifier"
trying to inspect or watch such local variables, as frame.
procedure TformMain.IdTCPServer1Execute(AContext: TIdContext);
var
frame, answer: string;
begin
...
frame := ReadLn(cETX, 50, 1024);
...
Thread.Queue(nil, procedure
begin
mmLog.Lines.Add(AContext.Binding.IP +'Bad Frame: '+ frame);
end
...
end;
Instead, in the thread queue I use to send info to the GUI, I can inspect correctly the Binding.IP, dispite to local strings...
Any idea if I am using the Delphi debugger in the right/wrong way ?

Delphi, message handler and global variables thread-safety

I have one messagehandler in the form like this:
procedure TMain_Form.form_message_handler(var MSG: TMessage);
begin
case MSG.WParam of
0: global_variable:=10;
1: global_variable:=global_variable+100;
end;
end;
Several threads will send to it asynchronous messages - PostMessage. Is manipulation of global variables (within such a handler) safe - I mean that access to these variables is safe? I will plan to manipulate this global variables only inside this handler. I assume it is safe because the messages handled by the handler waiting for execution in the queue. Is my assumption is correct?
Not really, no. If you are going to send asynchronous messages via. PostMessage, (not that it's a bad idea - hugely better than the apalling TThread.Synchronize), try very hard to post ALL of the data required by the message-handler, ie. do not use globals. If you have to communicate a lot of stuff, post a struct or object pointer in wParam/lParam.
Do not use globals unless... nothing really.
Oh, and another thing - do not use globals.

Win32 Mutex not waiting

I am creating an application that implements inter process communication.
For this purpose I have set up a shared buffer, which seems to work fine.
Now, I need a way for the data generating application (written in c++)
to tell the data receiving application (written in freepascal/lazarus)
when it should read the data.
I was trying to use a mutex for this purpose. I do not have much experience with windows api programming.
So, my problem is, in the FreePascal code below, the mutex won't wait. I can call the TMutex.Wait() function, it doesn't return an error or anything, but it simply won't wait.
constructor TMutex.Create(sName: AnsiString);
begin
sName := 'Local\Mutex'+sName;
hMutex := CreateMutexA(
nil, // default access
True, // initially not owned
PChar(sName)); // named mutex
if hMutex = 0 then
begin
raise Exception.Create('mutex creation failed');
end;
end;
destructor TMutex.Destroy;
begin
CloseHandle(hMutex);
end;
procedure TMutex.Wait;
begin
if (WaitForSingleObject(hMutex, INFINITE) <> 0) then ShowMessage('debug: wait returned something');
end;
procedure TMutex.Post;
begin
ReleaseMutex(hMutex);
end;
It looks like your problem is at:
True, // initially not owned
You have things backwards -- true means it initially IS owned, so waiting on it will return immediately.
you don't show us the code that calls the Wait, method of TMutex. however, you have to know that a mutex is reentrant: if a thread owns a mutex, it will always be granted access to it, thus a wait will never block. this is built into the mutex to avoid deadlocks.
try acquiring the mutex from another thread, the wait should block.

How Can I Monitor Which Window Currently Has Keyboard Focus

Is there a way to track which window currently has keyboard focus. I could handle WM_SETFOCUS for every window but I'm wondering if there's an alternative, simpler method (i.e. a single message handler somewhere).
I could use OnIdle() in MFC and call GetFocus() but that seems a little hacky.
So from the way you worded the question I'm inferring that you want to have an event handler which is invoked whenever focus switches between windows. You want to be notified, rather than having to poll.
I actually don't think calling GetFocus from OnIdle is that much of a hack - sure it's polling, but it's low-overhead polling without side effects - but if you really want to track this, Windows Hooks are probably your best choice. Specifically you can install a CBT hook (WH_CBT) and listen for the HCBT_SETFOCUS notification.
Windows calls the WH_CBT hook with this hook code when Windows is about to set the focus to any window. In the case of thread-specific hooks, the window must belong to the thread. If the filter function returns TRUE, the focus does not change.
You could also do with with a WH_CALLWNDPROC hook and listen for the WM_SETFOCUS message.
Depending on whether you make it a global hook, or app-local, you can track focus across all windows on the system, or only the windows owned by your process.
There is an easy way using .Net Framework 3.5 : the library UI Automation provides an event focus changed that fires every time the focus change to a new control.
Page on MSDN
Sample:
public void SubscribeToFocusChange()
{
AutomationFocusChangedEventHandler focusHandler
= new AutomationFocusChangedEventHandler(OnFocusChanged);
Automation.AddAutomationFocusChangedEventHandler(focusHandler);
}
private void OnFocusChanged(object sender, AutomationFocusChangedEventArgs e)
{
AutomationElement focusedElement = sender as AutomationElement;
//...
}
This api in fact use windows hook behind the scenes to do that. However you have to use the .Net Framework...
How about the Win32 GetForegroundWindow?
If you're programming in .net 3.5, the Automation package olorin mentions is by far the easiest, but beware of using it in a program that itself has a UI, at least if the UI is done in WPF -- the focus tracking hooks get confused by events in its own app, and quickly lock up the UI. I sent MS a bug report on it. I have not observed the same problem using a traditional Windows Forms UI. You could, of course, put the tracking code in a separate console app and use some kind of ipc to transmit the info you need.
The tempting alternative of using Interop to access the WH_CBT Windows Hook from C# won't work -- the only global hooks you can get at from C# are the mouse and keyboard.
Well, this may not be very graceful... but you can retrieve the current focused control pretty easily. So you might consider setting up a timer that asks every 1/2 second or so "Where is the current focus?"... Then you can observe changes. Example Delphi code is below; it should be pretty easy to adapt, since the real work is in the Windows API calls.
<snip>
function TForm1.GetCurrentHandle: integer;
var
activeWinHandle: HWND;
focusedThreadID : DWORD;
begin
//return the Windows handle of the currently focused control
Result := 0;
activeWinHandle := GetForegroundWindow;
focusedThreadID := GetWindowThreadProcessID(activeWinHandle,nil);
if AttachThreadInput(GetCurrentThreadID,focusedThreadID,true) then begin
try
Result := GetFocus;
finally
AttachThreadInput(GetCurrentThreadID, focusedThreadID, false);
end;
end; //if attached
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
//give notification if the handle changed
//(this code gets fired by a timer)
CurrentHandle := GetCurrentHandle;
if CurrentHandle <> PreviousHandle then begin
Label1.Caption := 'Last focus change occurred # ' + DateTimeToStr(Now);
end;
PreviousHandle := CurrentHandle;
end;
<snip>
http://msdn.microsoft.com/en-us/library/ms771428.aspx
Has a window focus tracker sample.
You could monitor messages for the WM_ACTIVATE event.
ref

Resources