Cannot inspect variable inside Indy OnExecute event - debugging

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 ?

Related

How to clear WinInet SSL state programmatically (is there a Windows API call)?

I need to mimic the same behavior as the "Clear SSL State" button in the "Internet Options" dialog ("Contents" tab) using an API function in Delphi.
My intention is to use this with WinInet to make subsequent independent SSL connections. Without this, two WinInet connections share the same SSL state, preventing me from correcting a wrong SSL certificate password, for example.
Without clearing the SSL state between two connection attempts, the first one returns "wrong password", then I correct the password and try again, but the second attempt returns "Secure Channel Support Error".
Finally! I achieved!
I used the excellent API Monitor, to monitor the whole Internet Options dialog and I managed to discover what the "Clear SSL State" button do. It executes only two API calls SslEmptyCache and IncrementUrlCacheHeaderData, in that order.
After discover this I was able to implement the following code, executed BEFORE my request:
type
TSslEmptyCache = function (pszTargetName: LPSTR; dwFlags: DWORD): BOOL; WINAPI;
TIncrementUrlCacheHeaderData = function (nIdx: DWORD; lpdwData: LPDWORD): BOOL; WINAPI;
var
SchannelDLLHandle, WinInetHandle: HMODULE;
SslEmptyCache: TSslEmptyCache;
IncrementUrlCacheHeaderData: TIncrementUrlCacheHeaderData;
SchannelDLLHandle := LoadLibrary('schannel.dll');
WinInetHandle := LoadLibrary('wininet.dll');
if (SchannelDLLHandle > 0) and (WinInetHandle > 0) then
try
SslEmptyCache := GetProcAddress(SchannelDLLHandle,'SslEmptyCacheW');
IncrementUrlCacheHeaderData := GetProcAddress(WinInetHandle,'IncrementUrlCacheHeaderData');
if Assigned(SslEmptyCache) and Assigned(IncrementUrlCacheHeaderData) then
begin
SslEmptyCache(nil,0);
IncrementUrlCacheHeaderData(14,#buffer);
end;
finally
FreeLibrary(SchannelDLLHandle);
FreeLibrary(WinInetHandle);
end;
Of course, this is a pseudo code, but It is complete ;)
The SslEmptyCache function has documentation at MSDN, but the IncrementUrlCacheHeaderData function not, so I had to research a little more to discover that the second paramenter must be a PDWORD, wich receives, when the function returns, an increment number, wich is persistent between calls at different processes (different applications).
For more information you can access this article where I explain all my saga. The text is in portuguese, but the site have a good translatin tool.
I wish to thank you all for the help
The "Clear SSL State" button simply executes the following undocumented command-line command:
"C:\Windows\system32\rundll32.exe" "C:\Windows\system32\WININET.dll",DispatchAPICall 3
Use CreateProcess() to execute the same command in your Delphi code.
You're right: if rundll can do it, you can do it programmatically:
//somewhere in an interface section:
procedure DispatchAPICall(h: HWND; hinst: HINST; lpszCmdLine: PAnsiChar; nCmdShow: integer); stdcall;
//somewhere in the implementation section:
function DispatchAPICall; external 'wininet.dll';
//somewhere in your code:
DispatchAPICall(GetDesktopWindow(), GetModuleHandle('wininet.dll'), '3', SW_NORMAL);

disable indy TIdTCPClient connect retries in firemonkey

i have this code to check connection to my server
so code is like this:
function CheckInternet(ssip:string): boolean;
begin
result:=false;
with form1.IdTCPClient1 do
try
ReadTimeout:=2000;
ConnectTimeout:=1000;
Port:=80;
Host:=ssip;
Connect;
Disconnect;
result:=true;
except
on E:EIdSocketError do
result:=false;
end;
end;
after running:
if server is online every thing is ok
but if server is online i got a lot of this error:
there is not difference in debug or release mode! both have error
also in android this cause two app crash and dont handling remain code!!..
how can i avoid this error?
What you see can happen only if you are calling CheckInternet() in a loop in the main UI thread and not catching raised exceptions. The popup messages are being displayed by a default exception handler within FMX when it catches an uncaught exception.
EIdSocketError is not the only type of exception that Connect() can raise. There are several other possible types, which you are not catching. You should remove the filter from your except block:
function CheckInternet(ssip:string): boolean;
begin
result:=false;
with form1.IdTCPClient1 do
try
ConnectTimeout:=1000;
Port:=80;
Host:=ssip;
Connect;
Disconnect;
result:=true;
except
result:=false;
end;
end;

how to upload to kinvey only once

i made a program in delphi that upload picture to kinvey provider, first the program saves the image from TImage component in a specific Dir then upload it to kinvey, the issue is every time i open the program it uploads to kinvey, now how to make sure that it only upload one time even if i opened the program multiple times
Image1.Repaint;
Image1.Bitmap.SaveToFile('some dir');
procedure TTabbedwithNavigationForm.Timer2Timer(Sender: TObject);
var
fn : string;
Lstream : TFileStream;
Lfile : TBackendEntityValue;
begin
fn := 'the file dir';
try
Lstream := TFileStream.Create(fn, fmOpenRead);
BackendFiles1.Files.UploadFile(fn,Lstream, 'image/png',Lfile);
finally
Lstream.Free;
BackendFiles1.Free;
end;
end;
end.
The name of the method "Timer2Timer" suggests that this code is triggered... by a Timer component named Timer2. ;-)
Check where this timer is activated. If it is already enabled at design time, the event will be called as soon as the defined time has elapsed, independently from any user interaction.
BTW: It is good to use a try/finally-block for streams, but the stream creation should be directly before "try" (else you would trigger the finally block if the creation of the stream fails, and then you are getting an access violation because the stream variable is not initialized).
The call of "BackendFiles1.Files;" inside the finally-block seems obsolete to me, what should that do?

how do I get windows SCM to restart my service when it fails

I have some windows services that i have written in delphi and they generally work very well, however on occasion i do get an exception thrown that can be considered fatal. When this happens the service is designed to stop.
My question is how do i exit the service in such a way that the SCM will automatically try to restart the service. (I have already set the recovery options for the service in the service manager)
MSDN states
A service is considered failed when it terminates without reporting a status of SERVICE_STOPPED to the service controller.
i have read this blog post Using the Automatic Recovery Features of Windows Services but i am not sure how to implement this in delphi.
i have allready tried the following
Setting the ErrCode Property of the TService to a non zero value.
Setting the stopped Parameter of the ServiceStop Event to false.
Raising an exception in the servicestop event handler.
EDIT 2013-08-06 added code example
Code Now Updated to show working example
Here is the code im using,
procedure TTestService.ServiceExecute(Sender: TService);
begin
while not (Terminated or FFatalError) do
begin
ServiceThread.ProcessRequests(False);
ReportStatus;
Sleep(100);
end;
if FFatalError then
Halt(1);
end;
FFatalError is a private boolean field on the TTestService class and is initialized to false on startup, it is only set to true if the worker thread (started in the TTestService.ServiceStart event) terminates with a fatal exception.
here is the OnTerminate event handler for the worker thread.
procedure TTestService.ThdTerm(Sender: Tobject);
var
E : Exception;
Thread : TThread;
begin
Thread := TThread(Sender);
if (Thread.FatalException <> nil) then
begin
E := Exception(Thread.FatalException);
GetExcCallStack(E);
EventLog.LogError(Thread.ClassName + ': ID:'+ IntToStr(Thread.ThreadID) +
' Stopped Unexpectedly!, '+ NEWLINE + E.ClassName +': ' + E.Message);
FFatalError := True;
end;
end;
The SCM will restart your service if it fails. But all the normal termination modes from a Delphi service do not count as failure. If you could raise an exception from the main service thread that was unhandled, then that would count as a failure.
However, I think the simplest way for you to force a process termination that is treated as a failure is to call ExitProcess. You could equally well call the Delphi RTL function Halt which will ultimately call ExitProcess. However, since your process is probably in a bad state I'd be inclined to go straight to ExitProcess.
As has already been commented, avoiding the exception in the first place would be the ideal solution.

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

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...

Resources