Challenge 9
Forum kuralları
Forum kurallarını okuyup, uyunuz!
Forum kurallarını okuyup, uyunuz!
Challenge 9
Bildiğiniz gibi bir uygulama 5 saniye boyunca mesaj kuyruğunu tüketmez ise; yanıt vermez(Not Responding) durumuna düşer. Hele bu süre daha da uzar ise, kullanıcılar sıkılabilir ve uygulamanın kilitlendiğini düşünüp; uygulamayı sonlandırabilirler.
Bazen bu yanıt vermez görünüm; bizim uzun süreli döngülere girip UI'yi güncellemememizden kaynaklanabileceği gibi; bazen de gerçek kilitlenmelerden de kaynaklanabilir. Velhasıl kullanıcılar sabırsızdır ve her daim cevap veren bir UI isterler. Dolayısı ile uygulamanızı sonlandırabilir kullanıcılar.
Peki ya o arada kritik bir iş yapıyorsanız ! Örneğin; çeşitli nedenlerden ötürü veritabanı ile ilgili yaptığınız işlemleri hafızada yapıyorsunuz. Misal; bir fatura girişi ekranındasınız ve kullanıcı bir alış faturası giriyor. Fatura kalemlerinin de 100 adet olduğunu düşünelim. 60 tanesini girdi ve bir nedenden ötürü uygulamanız yanıt vermez duruma düştü. En iyi ihtimalle; kullanıcı bir müddet bekleyip sonra küfür ederek uygulamayı bir ümit ile kapatıp yeniden açar ve girdiği faturanın sistemde olmasını umar. Ancak, siz işlemlerinizi hafızada (memory dataset) yaptığınız için maalesef sisteme kayıt etme imkanını bulamadınız.
Bu senaryolar elbette fazlası ile çoğaltılabilir. Bu tarz negatif etkiler kullanıcılarınızın karşısına çıkar ise; amiyane tabir ile uygulamanız ağzı ile kuş da tutsa; kısa bir süre sonra değiştirilir ya da iade edilir.
Elbette verilecek cevaplar arasında uzun süren döngüsel işlemlerde ara ara Application.ProcessMessages çağrımını yaparak mesaj kuyruğunu tüketirim diyebilir ya da uzun işlemleri ana thread dışında başka bir thread'in içinde yaparım diyebilirsiniz. Ki bunlar güzel alışkanlıklar. Ancak ben gerçek bir koruma mekanizmasından bahsediyorum. Uygulamanızda thread'de kullansanız bazen deadlock'lar ile karşılaşabilirsiniz. Önceki challange'larımızda dile getirdiğimiz gibi.
Sorunu izah edebilmişimdir umarım. Kullanıcınızın yaptığı kritik bir iş var ve bu işi uygulamanın kilitlenmesi olasılıklarına karşı korumanız gerekiyor. Ne yapardınız, nasıl ? Yaptığınız ya da yapacağınız öneriler lütfen sadece öneride kalmasın; burada paylaşmasanız dahi araştırmanızı somut bir örnek ile destekleyin ki arzuladığımız amaca ulaşabilmiş olalım.
Kurallar: Tek bir kural var; veri kaybetmemek ve bunu merkezi ve esnek bir mekanizma ile sağlamak.
Bazen bu yanıt vermez görünüm; bizim uzun süreli döngülere girip UI'yi güncellemememizden kaynaklanabileceği gibi; bazen de gerçek kilitlenmelerden de kaynaklanabilir. Velhasıl kullanıcılar sabırsızdır ve her daim cevap veren bir UI isterler. Dolayısı ile uygulamanızı sonlandırabilir kullanıcılar.
Peki ya o arada kritik bir iş yapıyorsanız ! Örneğin; çeşitli nedenlerden ötürü veritabanı ile ilgili yaptığınız işlemleri hafızada yapıyorsunuz. Misal; bir fatura girişi ekranındasınız ve kullanıcı bir alış faturası giriyor. Fatura kalemlerinin de 100 adet olduğunu düşünelim. 60 tanesini girdi ve bir nedenden ötürü uygulamanız yanıt vermez duruma düştü. En iyi ihtimalle; kullanıcı bir müddet bekleyip sonra küfür ederek uygulamayı bir ümit ile kapatıp yeniden açar ve girdiği faturanın sistemde olmasını umar. Ancak, siz işlemlerinizi hafızada (memory dataset) yaptığınız için maalesef sisteme kayıt etme imkanını bulamadınız.
Bu senaryolar elbette fazlası ile çoğaltılabilir. Bu tarz negatif etkiler kullanıcılarınızın karşısına çıkar ise; amiyane tabir ile uygulamanız ağzı ile kuş da tutsa; kısa bir süre sonra değiştirilir ya da iade edilir.
Elbette verilecek cevaplar arasında uzun süren döngüsel işlemlerde ara ara Application.ProcessMessages çağrımını yaparak mesaj kuyruğunu tüketirim diyebilir ya da uzun işlemleri ana thread dışında başka bir thread'in içinde yaparım diyebilirsiniz. Ki bunlar güzel alışkanlıklar. Ancak ben gerçek bir koruma mekanizmasından bahsediyorum. Uygulamanızda thread'de kullansanız bazen deadlock'lar ile karşılaşabilirsiniz. Önceki challange'larımızda dile getirdiğimiz gibi.
Sorunu izah edebilmişimdir umarım. Kullanıcınızın yaptığı kritik bir iş var ve bu işi uygulamanın kilitlenmesi olasılıklarına karşı korumanız gerekiyor. Ne yapardınız, nasıl ? Yaptığınız ya da yapacağınız öneriler lütfen sadece öneride kalmasın; burada paylaşmasanız dahi araştırmanızı somut bir örnek ile destekleyin ki arzuladığımız amaca ulaşabilmiş olalım.
Kurallar: Tek bir kural var; veri kaybetmemek ve bunu merkezi ve esnek bir mekanizma ile sağlamak.
Re: Challenge 9
Wallahi hocam aklıma ilk gelen bir arka plan servisi oldu. Yapılan işin ehemmiyetine göre o görevi servise yıkabilirim. En basit örnek Antivirüs yazılımları her şeye kanca atıp duruyorlar gelen geçeni uçanı kaçanı yakalamak için arkada servislerini koşturuyorlar. Her kritik görev için ayrı servis çalışıyor. Ön tarafta kasma esneme gevşeme yok. Yalnız burada yapılacak iş önemli tabii. Her şeye de servis olmaz. Scheduler gibi bir mekanizma yapıp gelen işe göre otomatiğe bağlayabiliriz. (Tabii iş statik ise)
Bir diğer seçenek Dll olabilir. Bu dll yi memory'de çalıştırıp orada iş gördürebiliriz ama bu servisten daha riskli bir durum. Memory hızlıdır ama güvenli değildir. Veri kaybına açıktır. (Örnek Windows / Macintosh) Sen bu seçeneği zaten elemişsin yukarıda
Başka şeylerde geliyor aklıma ama çok hakim değilim onlara biraz araştırayım yazarım.
http://homes.cs.washington.edu/~tom/pubs/thread89.pdf
Bir diğer seçenek Dll olabilir. Bu dll yi memory'de çalıştırıp orada iş gördürebiliriz ama bu servisten daha riskli bir durum. Memory hızlıdır ama güvenli değildir. Veri kaybına açıktır. (Örnek Windows / Macintosh) Sen bu seçeneği zaten elemişsin yukarıda
Başka şeylerde geliyor aklıma ama çok hakim değilim onlara biraz araştırayım yazarım.
http://homes.cs.washington.edu/~tom/pubs/thread89.pdf
Re: Challenge 9
Aslında AV yazılımları, tüm kontrolü driver'lar vasıtası ile yapıyorlar. Önceden SSDT hook yapıyorlardı; şimdi ne yapıyorlar bilmiyorum açıkçası. Userland'de her api'yi hook etmek bir AV için kabul edilemez bir şey olurdu ve aynı zamanda da güvensiz. Hook edilebilen bir API kolaylıkla unhook da edilebilir. Genelde ilgili API'nin ilk byte'ının $e9 olması yada bir jump opcode olmasına bakılarak anlaşılabilir hook edilmiş apiler. Elbette başka yöntemlerde var, hook edilen api bulunduktan sonra ilgili API'nin bulunduğu DLL dosyasından PE header okunup EAT üzerinden orjinal byte'ları okunabilir ve hook bertaraf edilebilir. Velhasıl, AV'lerin kullandığı metodoloji değil hedefimiz. Servislerde değil.
Örneğin senin Crew yazılımından dem vuralım. Bu yazılımında önemli bir iş yapıyorsun; kullanıcı için mühim bazı kodlar çalışıyor ve kodlamadaki bir nedenden ötürü uygulama bir müddet yanıt vermez görünüyor, kullanıcı da o arada beklemekten sıkıldı ve uygulamanı sonlandırdı. Ne olacak kullanıcının girdiği yada arka planda işlediğin datalar ? Programı bir daha açtığında kullanıcı kaldığı yerden nasıl devam edecek ?
Küçücük bir ipucu vereyim; yanlış kaynakları araştırmamanız adına. Bu iş için bir API grubu var ve Vista+ sistemlerde kullanılabiliyor
Örneğin senin Crew yazılımından dem vuralım. Bu yazılımında önemli bir iş yapıyorsun; kullanıcı için mühim bazı kodlar çalışıyor ve kodlamadaki bir nedenden ötürü uygulama bir müddet yanıt vermez görünüyor, kullanıcı da o arada beklemekten sıkıldı ve uygulamanı sonlandırdı. Ne olacak kullanıcının girdiği yada arka planda işlediğin datalar ? Programı bir daha açtığında kullanıcı kaldığı yerden nasıl devam edecek ?
Küçücük bir ipucu vereyim; yanlış kaynakları araştırmamanız adına. Bu iş için bir API grubu var ve Vista+ sistemlerde kullanılabiliyor
Re: Challenge 9
DeğilG.Arkas yazdı:KTM olabilir mi? Kernel Transaction Manager?
-
- Üye
- Mesajlar: 216
- Kayıt: 10 Ara 2013 03:50
Re: Challenge 9
Sanırım söz konusu API'ler bunlar:
ApplicationRecoveryCallback
ApplicationRecoveryFinished
ApplicationRecoveryInProgress
GetApplicationRecoveryCallback
GetApplicationRestartSettings
RegisterApplicationRecoveryCallback
RegisterApplicationRestart
UnregisterApplicationRecoveryCallback
UnregisterApplicationRestart
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
Şahsen bana oldukça ilginç geldi. Delphi ile yapılmış bir kurtarma örneği varsa çok memnun olurum.
Teşekkürler.
ApplicationRecoveryCallback
ApplicationRecoveryFinished
ApplicationRecoveryInProgress
GetApplicationRecoveryCallback
GetApplicationRestartSettings
RegisterApplicationRecoveryCallback
RegisterApplicationRestart
UnregisterApplicationRecoveryCallback
UnregisterApplicationRestart
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
Şahsen bana oldukça ilginç geldi. Delphi ile yapılmış bir kurtarma örneği varsa çok memnun olurum.
Teşekkürler.
Re: Challenge 9
Tebrikler, evet API'ler bunlar. Biraz uğraşın bakalım; maksat yeni bir şeyler öğrenmeye kapı aralamak zaten. Deneyip kendiniz yapar iseniz çok daha kalıcı olacaktır. Ben zaten bir müddet sonra bir örnek proje paylaşacağım.xxxjedixxx yazdı:Sanırım söz konusu API'ler bunlar:
ApplicationRecoveryCallback
ApplicationRecoveryFinished
ApplicationRecoveryInProgress
GetApplicationRecoveryCallback
GetApplicationRestartSettings
RegisterApplicationRecoveryCallback
RegisterApplicationRestart
UnregisterApplicationRecoveryCallback
UnregisterApplicationRestart
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
Şahsen bana oldukça ilginç geldi. Delphi ile yapılmış bir kurtarma örneği varsa çok memnun olurum.
Teşekkürler.
Re: Challenge 9
Küçük bir ipucu: İlgili API'lerin çalışıp görevlerini yerine getirebilmeleri için uygulamanızın en az 1 dakika boyunca çalışıyor olması gerekir
Re: Challenge 9
Şahsen bu işin api ler ile yapılabilieceğini bilmiyordum, gerçi ben sadece veritabanı olarak bakıyorum olaya.
Benim Şahsi çözümüm şu şekilde oluyor,
Kullanıcı username ve şifre ile oturum açtığında yaptığı her işlemde kullanıcı kodunu kaydediyorum, diyelim veritabanında fatura tablosu var, birde fatura_temp adında tablo oluşturuyorum, kullanıcı sürekli olarak bu geçici tabloda işlem yapıyor , ne zamanki kaydet butonuna basıyor, bu tablodaki verileri alıp ana tabloya ekliyorum. Diyelim temp tablosuna 10-20-30 neyse stok girdi, elektrik kesildi başka bişi oldu program kilitlendi vs.vs. kullanıcı yeniden girdiğinde, işlem, fatura, irsaliye, çek, senet vs.vs. her nerde yarım kaldıysa, o menuye girdiği gibi daha önce kaydettiği verileri ekrana döküyorum, devam etmek istermisiniz gibi bir uyarı veriyorum oluyor bitiyor.
Sanırım sizin bahsettiğiniz sadece VT değilde ne bilim mesela excelde bi dosya açık, oldu elektrik gitti, makina yeniden başlayınca excel tablosu ekrana geliyor gibi bişi.
Benim Şahsi çözümüm şu şekilde oluyor,
Kullanıcı username ve şifre ile oturum açtığında yaptığı her işlemde kullanıcı kodunu kaydediyorum, diyelim veritabanında fatura tablosu var, birde fatura_temp adında tablo oluşturuyorum, kullanıcı sürekli olarak bu geçici tabloda işlem yapıyor , ne zamanki kaydet butonuna basıyor, bu tablodaki verileri alıp ana tabloya ekliyorum. Diyelim temp tablosuna 10-20-30 neyse stok girdi, elektrik kesildi başka bişi oldu program kilitlendi vs.vs. kullanıcı yeniden girdiğinde, işlem, fatura, irsaliye, çek, senet vs.vs. her nerde yarım kaldıysa, o menuye girdiği gibi daha önce kaydettiği verileri ekrana döküyorum, devam etmek istermisiniz gibi bir uyarı veriyorum oluyor bitiyor.
Sanırım sizin bahsettiğiniz sadece VT değilde ne bilim mesela excelde bi dosya açık, oldu elektrik gitti, makina yeniden başlayınca excel tablosu ekrana geliyor gibi bişi.
Re: Challenge 9
Temp tablo kullanmadığınızı; bu işi memory dataset'te yaptığınızı bir hayal edin Örnekler elbette çoğaltılabilir.esistem yazdı:Şahsen bu işin api ler ile yapılabilieceğini bilmiyordum, gerçi ben sadece veritabanı olarak bakıyorum olaya.
Benim Şahsi çözümüm şu şekilde oluyor,
Kullanıcı username ve şifre ile oturum açtığında yaptığı her işlemde kullanıcı kodunu kaydediyorum, diyelim veritabanında fatura tablosu var, birde fatura_temp adında tablo oluşturuyorum, kullanıcı sürekli olarak bu geçici tabloda işlem yapıyor , ne zamanki kaydet butonuna basıyor, bu tablodaki verileri alıp ana tabloya ekliyorum. Diyelim temp tablosuna 10-20-30 neyse stok girdi, elektrik kesildi başka bişi oldu program kilitlendi vs.vs. kullanıcı yeniden girdiğinde, işlem, fatura, irsaliye, çek, senet vs.vs. her nerde yarım kaldıysa, o menuye girdiği gibi daha önce kaydettiği verileri ekrana döküyorum, devam etmek istermisiniz gibi bir uyarı veriyorum oluyor bitiyor.
Sanırım sizin bahsettiğiniz sadece VT değilde ne bilim mesela excelde bi dosya açık, oldu elektrik gitti, makina yeniden başlayınca excel tablosu ekrana geliyor gibi bişi.
-
- Üye
- Mesajlar: 239
- Kayıt: 04 Oca 2008 01:53
- Konum: Karşıyaka/İzmir
Re: Challenge 9
Api bilgileri şöyle imiş:
Bunları delphi'ye uyarlayarak şuraya kadar geldim:
Çalışmaya devam ediyorum, ancak "APPLICATION_RECOVERY_CALLBACK" ı nasıl tanımlayacağımı anlayamadım.
Kod: Tümünü seç
WORD WINAPI ApplicationRecoveryCallback(
PVOID pvParameter
);
VOID WINAPI ApplicationRecoveryFinished(
__in BOOL bSuccess
);
HRESULT WINAPI ApplicationRecoveryInProgress(
__out PBOOL pbCanceled
);
HRESULT WINAPI GetApplicationRecoveryCallback(
__in HANDLE hProcess,
__out APPLICATION_RECOVERY_CALLBACK* pRecoveryCallback,
__out PVOID* ppvParameter,
__out DWORD dwPingInterval,
__out DWORD dwFlags
);
HRESULT WINAPI GetApplicationRestartSettings(
__in HANDLE hProcess,
__out_opt PWSTR pwzCommandline,
__in_out PDWORD pcchSize,
__out_opt PDWORD pdwFlags
);
HRESULT WINAPI RegisterApplicationRecoveryCallback(
__in APPLICATION_RECOVERY_CALLBACK pRecoveryCallback,
__in_opt PVOID pvParameter,
__in DWORD dwPingInterval,
__in DWORD dwFlags
);
HRESULT WINAPI RegisterApplicationRestart(
__in_opt PCWSTR pwzCommandline,
__in DWORD dwFlags
);
HRESULT WINAPI UnregisterApplicationRecoveryCallback(void);
HRESULT WINAPI UnregisterApplicationRestart(void);
Kod: Tümünü seç
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
function ApplicationRecoveryCallback(pvParameter:pointer):word; stdcall;
procedure ApplicationRecoveryFinished(bSuccess:boolean);stdcall;
function ApplicationRecoveryInProgress(pbCanceled:boolean):LongInt;stdcall;
function GetApplicationRecoveryCallback
(hProcess:tHANDLE;
pRecoveryCallback:^APPLICATION_RECOVERY_CALLBACK;
ppvParameter:PPointer;
dwPingInterval:cardinal;
dwFlags:cardinal):LongInt;stdcall;
function GetApplicationRestartSettings
(hProcess:tHANDLE;
pwzCommandline : pwidechar;
pcchSize : ^cardinal;
pdwFlags : ^cardinal):LongInt;stdcall;
function RegisterApplicationRecoveryCallback
(pRecoveryCallback : APPLICATION_RECOVERY_CALLBACK;
pvParameter : Pointer;
dwPingInterval : DWORD;
dwFlags : cardinal):LongInt;stdcall;
function RegisterApplicationRestart
(pwzCommandline: PWideChar;
dwFlags: cardinal):LongInt;stdcall;
function UnregisterApplicationRecoveryCallback:LongInt;stdcall;
function UnregisterApplicationRestart:LongInt;stdcall;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function ApplicationRecoveryCallback; external 'kernel32.dll'
name 'ApplicationRecoveryCallback';
procedure ApplicationRecoveryFinished; external 'kernel32.dll'
name 'ApplicationRecoveryFinished';
function ApplicationRecoveryInProgress; external 'kernel32.dll'
name 'ApplicationRecoveryInProgress';
function GetApplicationRecoveryCallback; external 'kernel32.dll'
name 'GetApplicationRecoveryCallback';
function GetApplicationRestartSettings; external 'kernel32.dll'
name 'GetApplicationRestartSettings';
function RegisterApplicationRecoveryCallback; external 'kernel32.dll'
name 'RegisterApplicationRecoveryCallback';
function RegisterApplicationRestart; external 'kernel32.dll'
name 'RegisterApplicationRestart';
function UnregisterApplicationRecoveryCallback; external 'kernel32.dll'
name 'UnregisterApplicationRecoveryCallback';
function UnregisterApplicationRestart; external 'kernel32.dll'
name 'UnregisterApplicationRestart';
procedure TForm1.FormCreate(Sender: TObject);
begin
//
end;
end.
In dubio pro reo...
Şüpheden sanık/özgürlük yararlanır...
Şüpheden sanık/özgürlük yararlanır...
Re: Challenge 9
Tanımlamalar kısmında aşağıdaki gibi bir ipucunu vereyim:
Kod: Tümünü seç
const
RECOVERY_DEFAULT_PING_INTERVAL = 5000;
type
TApplicationRecoveryCallback = function (pvParameter : Pointer) : DWORD; stdcall;
TRegisterApplicationRestart = function (pwzCommandline: PWideChar; dwFlags: DWORD): HRESULT; stdcall;
TUnRegisterApplicationRestart = function : HRESULT; stdcall;
TRegisterApplicationRecoveryCallback = function (
pRecoveryCallback : TApplicationRecoveryCallback;
pvParameter : Pointer;
dwPingInterval : DWORD;
dwFlags : DWORD) : HRESULT; stdcall;
TUnregisterApplicationRecoveryCallback = function : HRESULT; stdcall;
TApplicationRecoveryInProgress = function (out pbCanceled : BOOL) : HRESULT; stdcall;
TApplicationRecoveryFinished = function (bSuccess : BOOL) : HRESULT; stdcall;
Re: Challenge 9
Yok mu hâla bu API'leri kullanıp, örnek uygulama geliştirebilen ?
Re: Challenge 9
Yukarıda verdiğim tanımlara rağmen herhangi bir yerde takılan arkadaşlarım var ise bildirsinler yardımcı olmaya çalışayım. Adı sanı, şekli şemali belli ve son derece faydalı bir API grubuna ilgisiz kaldığınızı düşünmek istemiyorum açıkçası. Acemi arkadaşların yanı sıra, profesyonel arkadaşların da konu ile ilgilenmesini rica ediyorum.
Zorla bir şeyler yaptırmaya çalışıyorum gibi hissettiriyorsunuz arkadaşlar. Lütfen biraz daha ilgili olun.
Zorla bir şeyler yaptırmaya çalışıyorum gibi hissettiriyorsunuz arkadaşlar. Lütfen biraz daha ilgili olun.
Re: Challenge 9
JEDI kütüphanesinden aldığım yardımlarla aşağıdaki tanımlamaları yaptım:
Daha sonra; program göçtüğünde bir log dosyası oluşturmak için bir callback fonksiyonu tanımladım:
Bir butona basıldığında bu callback fonksiyonu program kurtarma için register ettim:
Yine başka bir butonla exception oluşturuyorum ama RecoveryCallback fonksiyonu çalışmıyor
Kod: Tümünü seç
type
APPLICATION_RECOVERY_CALLBACK = function (pvParameter : Pointer) : DWORD; stdcall;
TApplicationRecoveryCallback = APPLICATION_RECOVERY_CALLBACK;
function ApplicationRecoveryFinished(bSuccess : BOOL) : HRESULT; stdcall;
function ApplicationRecoveryInProgress(out pbCanceled : BOOL) : HRESULT; stdcall;
function GetApplicationRecoveryCallback(hProcess: THandle; pRecoveryCallback : TApplicationRecoveryCallback; ppvParameter : PPointer; dwPingInterval : PDWORD; dwFlags : PDWORD) : HRESULT; stdcall;
function GetApplicationRestartSettings(hProcess: THandle; pwzCommandline : PWideChar; var pcchSize : DWORD; pdwFlags : PDWORD) : HRESULT; stdcall;
function RegisterApplicationRecoveryCallback(pRecoveryCallback : TApplicationRecoveryCallback;pvParameter : Pointer;dwPingInterval : DWORD;dwFlags : DWORD) : HRESULT; stdcall;
function RegisterApplicationRestart(pwzCommandline: PWideChar; dwFlags: DWORD): HRESULT; stdcall;
function UnregisterApplicationRecoveryCallback : HRESULT; stdcall;
function UnregisterApplicationRestart : HRESULT; stdcall;
implementation
function ApplicationRecoveryFinished; external kernel32 Name 'ApplicationRecoveryFinished';
function ApplicationRecoveryInProgress; external kernel32 Name 'ApplicationRecoveryInProgress';
function GetApplicationRecoveryCallback; external kernel32 Name 'GetApplicationRecoveryCallback';
function GetApplicationRestartSettings; external kernel32 Name 'GetApplicationRestartSettings';
function RegisterApplicationRecoveryCallback; external kernel32 Name 'RegisterApplicationRecoveryCallback';
function RegisterApplicationRestart; external kernel32 Name 'RegisterApplicationRestart';
function UnregisterApplicationRecoveryCallback; external kernel32 Name 'UnregisterApplicationRecoveryCallback';
function UnregisterApplicationRestart; external kernel32 Name 'UnregisterApplicationRestart';
Kod: Tümünü seç
function RecoveryCallback(pvParameter: Pointer): DWORD; stdcall;
var
FS: TFileStream;
MyClass: TObject;
Mesaj: String;
begin
FS := TFileStream.Create('C:\Log.txt', fmCreate);
try
Mesaj := Format('%s => %s', [FormatDateTime('dd/mm/yyyy hh:nn:ss', Now), 'Program göçtü :(']);
FS.Write(Mesaj[1], Length(Mesaj));
ApplicationRecoveryFinished(True);
finally
FS.Free;
end;
Result := 0;
end;
Kod: Tümünü seç
procedure TFormTest.RegisterClick(Sender: TObject);
var
Res: HRESULT;
begin
Res := RegisterApplicationRecoveryCallback(RecoveryCallback, nil, 5000, 0);
if (Res <> S_OK) then
ShowMessage('Register error');
end;
There's no place like 127.0.0.1