Yorumları: 4.224
Konuları: 379
Kayıt Tarihi: 07-07-2016
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 16.975 Üstad
17-09-2016, Saat: 22:56
(Son Düzenleme: 04-11-2016, Saat: 09:46, Düzenleyen: TescilsizUzman.)
Merhaba,
Windows hedef platformu için bir çoğumuz uygulama yazarken DOS ekranında komut çalıştırma ihtiyacı duymuşuzdur.
Bu kapsamda üretilen ve Ücretsiz olarak dağıtılan son derece etkili ve kullanışlı bir Component'ten bahsederek, kullanımı konusunda bilgiler vermek istiyorum.
Kullanacağımız component TurboPack DOSCommand.
Genel Özellikleri;
- Komut satırında herhangi bir veya birden fazla iş yaptırıma (com, exe ve bat dosyalarını doğrudan çalıştırma),
- Komutların işlem sonucunu kendi uygulamanızda görebilme (OnNewChar ve OnNewLine olayları ile OutputLnes ve Lines özellikleri),
- Komutun bittiğini algılama (OnTerminateProcess ve OnTerminated olayları),
- Varsayılan dizini belirleyebilme (CurrentDir özelliği),
- Geçici Ortam Değişkenleri ekleyebilme (Environment özelliği),
- Karakter Decode ve Encode işlemleri yapabilme (OnCharEncoding ve OnCharDecoding olayları),
- Çalışmayan ve Hata oluşturan komutları ve hata türünü yakalama (OnExecuteError olayı),
- Çalıştırılacak Komutların İşletim Sisteminde öncelik sırasını belirleyebilme (Priority özelliği; aldığı değerler----> HIGH_PRIORITY_CLASS, IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS ve REALTIME_PRIORITY_CLASS),
- Satır Satır Komut işletebilme (SendLine özelliği)
- Çalışma anında iş durumu hakkında bilgi edinebilme (OnTerminateProcess olayı ve ProcessInformation özelliği),
Component'i indirmek için: TurboPack - DOSCommand
Örnek Bir Uygulama;
Yukarıdaki linkten TurboPack - DOSCommand Component'ini indirip kuralım.
Tool Palette Penceresi, DOSCommand sekmesinden form üzerine bir adet DosCommand nesnesi yerleştirelim.
Form üzerine komutları çalıştırmak ve komut geri dönüş değerlerini almak için birer adet Edit, Button ve Memo nesnesi yerleştirelim ve tasarımını aşağıdaki gibi yapalım.
Bir veya birden fazla komut içeren bir toplu işlem dosyası ( Batch dosyası) oluşturalım. Benim kullanacağım örnek dosya içeriği aşağıdaki gibi olacak.
Butonu çift tıklayıp, OnClick olayına aşağıdaki kodları yazalım.
procedure TForm1.Button1Click(Sender: TObject);
begin
DosCommand1.Priority := HIGH_PRIORITY_CLASS; {Çalışacak komutun iş önceliğini Yüksek olarak belirledik}
DosCommand1.CommandLine := edtKomut.Text; {Çalıştırılacak Komut veya Komutlar listesi}
DosCommand1.Execute; {Komutları çalıştır}
end;
DosCommand nesnesini seçelim ve Object Inspector Penceresi Events sekmesinde OnNewLine olayını çift tıklayalım ve aşağıdaki kodları yazalım.
procedure TForm1.DosCommand1NewLine(ASender: TObject; const ANewLine: string;
AOutputType: TOutputType);
begin
case AOutputType of
TOutputType.otEntireLine:
Memo1.Lines.Add(ANewLine);
end;
end;
Son olarak uygulamayı çalıştırıp, sonucuna bakalım.
İyi çalışmalar...
Yorumları: 4.224
Konuları: 379
Kayıt Tarihi: 07-07-2016
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 16.975 Üstad
18-09-2016, Saat: 00:20
(Son Düzenleme: 18-09-2016, Saat: 00:20, Düzenleyen: TescilsizUzman.)
Bu arada toplu iş dosyasının ilk satırında komutları gizlemek için kullandığım echo off komutunun başında @ işareti olması gerekiyordu (@echo off). Konumuzla pek alakası yok ama hatamı sonradan gördüğüm için düzeltme yapayım dedim.
Yorumları: 579
Konuları: 15
Kayıt Tarihi: 24-03-2017
Rep Puanı: 3.480 Uzman
28-03-2018, Saat: 00:53
(Son Düzenleme: 28-03-2018, Saat: 00:55, Düzenleyen: frmman.
Sebep: Link ilave
)
Merhaba Fesih bey
Delphi ile konsol uygulamasından veri alma ile ilgili arama yaparken çözümün DelphiCanda olduğunu görünce çok sevindim
C# da yazdığım bir konsol uygulaması ile Delphi vcl uygulamasını anlattığınız bileşeni kullanarak haberleştirmeyi denedim.
Uygulamayı windowsun cmd penceresinden çalıştırılınca, türkçe karakterleri sorunsuz olarak ekranda görebiliyorum.
cmd penceresinden c:\consol.exe --- "Şeker gibi" ekrana bir çıktı üretiyor.
Aynı işlemi delphi tarafında
DosCommand1.CommandLine :='c:\consol.exe';
şeklinde denediğimde çıktıyı memo nesnesine aktarıyor fakat türkçe karakterlerde bozulma meydana geliyor.
Makalenizde belirttiğiniz "OnCharEncoding ve OnCharDecoding olayları" nı kullanmayı beceremedim.
Aradan baya zaman geçmiş fakat yardımcı olursanız sevinirm.
Edit:
İlk mesajda geçen link pasif olmuş.
Güncel link : https://github.com/TurboPack/DOSCommand
Yorumları: 304
Konuları: 20
Kayıt Tarihi: 26-09-2016
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 3.967 Uzman
28-03-2018, Saat: 03:15
(Son Düzenleme: 28-03-2018, Saat: 03:16, Düzenleyen: barutali.)
(28-03-2018, Saat: 00:53)frmman Adlı Kullanıcıdan Alıntı: Merhaba Fesih bey
Delphi ile konsol uygulamasından veri alma ile ilgili arama yaparken çözümün DelphiCanda olduğunu görünce çok sevindim
C# da yazdığım bir konsol uygulaması ile Delphi vcl uygulamasını anlattığınız bileşeni kullanarak haberleştirmeyi denedim.
Uygulamayı windowsun cmd penceresinden çalıştırılınca, türkçe karakterleri sorunsuz olarak ekranda görebiliyorum.
cmd penceresinden c:\consol.exe --- "Şeker gibi" ekrana bir çıktı üretiyor.
Aynı işlemi delphi tarafında
DosCommand1.CommandLine :='c:\consol.exe';
şeklinde denediğimde çıktıyı memo nesnesine aktarıyor fakat türkçe karakterlerde bozulma meydana geliyor.
Makalenizde belirttiğiniz "OnCharEncoding ve OnCharDecoding olayları" nı kullanmayı beceremedim.
Aradan baya zaman geçmiş fakat yardımcı olursanız sevinirm.
Edit:
İlk mesajda geçen link pasif olmuş.
Güncel link : https://github.com/TurboPack/DOSCommand
Merhaba;
Nereden bulduğumu hatırlamıyorum ama aşağıdaki şekilde çözmüştüm.
function GetDosOutput(CommandLine: string; Work: string = 'C:\'): AnsiString;
var
SA: TSecurityAttributes;
SI: TStartupInfo;
PI: TProcessInformation;
StdOutPipeRead, StdOutPipeWrite: THandle;
WasOK: Boolean;
Buffer: array[0..255] of AnsiChar;
BytesRead: Cardinal;
WorkDir: string;
Handle: Boolean;
function StrOemToAnsi(const aStr : AnsiString) : AnsiString;
var
Len : Integer;
begin
if aStr = '' then Exit;
Len := Length(aStr);
SetLength(Result, Len);
OemToCharBuffA(PAnsiChar(aStr), PAnsiChar(Result), Len);
end;
begin
Result := '';
with SA do
begin
nLength := SizeOf(SA);
bInheritHandle := True;
lpSecurityDescriptor := nil;
end;
CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SA, 0);
try
with SI do
begin
FillChar(SI, SizeOf(SI), 0);
cb := SizeOf(SI);
dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
wShowWindow := SW_HIDE;
hStdInput := GetStdHandle(STD_INPUT_HANDLE); // don't redirect stdin
hStdOutput := StdOutPipeWrite;
hStdError := StdOutPipeWrite;
end;
WorkDir := Work;
Handle := CreateProcess(nil, PChar('cmd.exe /C ' + CommandLine),
nil, nil, True, 0, nil,
PChar(WorkDir), SI, PI);
CloseHandle(StdOutPipeWrite);
if Handle then
try
repeat
WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
if BytesRead > 0 then
begin
Buffer[BytesRead] := #0;
Result := StrOemToAnsi(Result) + Buffer;
end;
until not WasOK or (BytesRead = 0);
WaitForSingleObject(PI.hProcess, INFINITE);
finally
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
end;
finally
CloseHandle(StdOutPipeRead);
end;
end;
Kullanımı
Memo1.Lines.Text := GetDosOutput('TREE D:\');
Amatör Küme Bilgisayar Programcısı
Yorumları: 579
Konuları: 15
Kayıt Tarihi: 24-03-2017
Rep Puanı: 3.480 Uzman
Teşekkürler @ barutali
Memo2.Lines.Text := GetDosOutput('TREE C:\1');
Önerdiğiniz yöntemi de denedim, C:\1 klasörü içerisine türkçe karakter içeren klasörler isimlerinde bozulma meydana geldi.
Yorumları: 579
Konuları: 15
Kayıt Tarihi: 24-03-2017
Rep Puanı: 3.480 Uzman
Aşağıdaki kod türkçe karakter problemi çıkartmadan çalışıyor.
DosCommand komponenti çıktı parametrelerini işlem devam ederken gösterebiliyor. Güzel bir özellik.
Çok fazla sayıda dosya içeren bir klasörün listelenmesi işleminde, işlem devam ederken ekrana yansımanı göze çok güzel görünüyor.
Diğer çözümlerde işlem bittikden sonra sonuç görünüyor.
Kaynak
procedure RunDosInMemo(DosApp: string; AMemo:TMemo);
const
READ_BUFFER_SIZE = 2400;
var
Security: TSecurityAttributes;
readableEndOfPipe, writeableEndOfPipe: THandle;
start: TStartUpInfo;
ProcessInfo: TProcessInformation;
Buffer: PAnsiChar;
BytesRead: DWORD;
AppRunning: DWORD;
begin
Security.nLength := SizeOf(TSecurityAttributes);
Security.bInheritHandle := True;
Security.lpSecurityDescriptor := nil;
if CreatePipe({var}readableEndOfPipe, {var}writeableEndOfPipe, @Security, 0) then
begin
Buffer := AllocMem(READ_BUFFER_SIZE+1);
FillChar(Start, Sizeof(Start), #0);
start.cb := SizeOf(start);
// Set up members of the STARTUPINFO structure.
// This structure specifies the STDIN and STDOUT handles for redirection.
// - Redirect the output and error to the writeable end of our pipe.
// - We must still supply a valid StdInput handle (because we used STARTF_USESTDHANDLES to swear that all three handles will be valid)
start.dwFlags := start.dwFlags or STARTF_USESTDHANDLES;
start.hStdInput := GetStdHandle(STD_INPUT_HANDLE); //we're not redirecting stdInput; but we still have to give it a valid handle
start.hStdOutput := writeableEndOfPipe; //we give the writeable end of the pipe to the child process; we read from the readable end
start.hStdError := writeableEndOfPipe;
//We can also choose to say that the wShowWindow member contains a value.
//In our case we want to force the console window to be hidden.
start.dwFlags := start.dwFlags + STARTF_USESHOWWINDOW;
start.wShowWindow := SW_HIDE;
// Don't forget to set up members of the PROCESS_INFORMATION structure.
ProcessInfo := Default(TProcessInformation);
//WARNING: The unicode version of CreateProcess (CreateProcessW) can modify the command-line "DosApp" string.
//Therefore "DosApp" cannot be a pointer to read-only memory, or an ACCESS_VIOLATION will occur.
//We can ensure it's not read-only with the RTL function: UniqueString
UniqueString({var}DosApp);
if CreateProcess(nil, PChar(DosApp), nil, nil, True, NORMAL_PRIORITY_CLASS, nil, nil, start, {var}ProcessInfo) then
begin
//Wait for the application to terminate, as it writes it's output to the pipe.
//WARNING: If the console app outputs more than 2400 bytes (ReadBuffer),
//it will block on writing to the pipe and *never* close.
repeat
Apprunning := WaitForSingleObject(ProcessInfo.hProcess, 100);
Application.ProcessMessages;
until (Apprunning <> WAIT_TIMEOUT);
//Read the contents of the pipe out of the readable end
//WARNING: if the console app never writes anything to the StdOutput, then ReadFile will block and never return
repeat
BytesRead := 0;
ReadFile(readableEndOfPipe, Buffer[0], READ_BUFFER_SIZE, {var}BytesRead, nil);
Buffer[BytesRead]:= #0;
OemToAnsi(Buffer,Buffer);
AMemo.Text := AMemo.text + String(Buffer);
until (BytesRead < READ_BUFFER_SIZE);
end;
FreeMem(Buffer);
CloseHandle(ProcessInfo.hProcess);
CloseHandle(ProcessInfo.hThread);
CloseHandle(readableEndOfPipe);
CloseHandle(writeableEndOfPipe);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin {button 1 code}
RunDosInMemo('chkdsk.exe c:\',Memo1);
end;
Yorumları: 579
Konuları: 15
Kayıt Tarihi: 24-03-2017
Rep Puanı: 3.480 Uzman
DosCommand komponentinin türkçe karakter problemini , onCharDecoding olayında " code page" kullanarak aşağıdaki şekilde çözdüm.
Kod içerisindeki linkde code page ile ilgili açıklayıcı tablo bulunmaktadır.
Not: onCharDecoding olayı oluşturulunca onNewLine olayı otomatik olarak devre dışı kalıyor.
Konsoldan cevap olarak çok fazla veri geldiğinde yukarıda paylaştığım
procedure RunDosInMemo(DosApp: string; AMemo:TMemo);
ile başlayan yöntem kilitlenip kalıyordu. DosCommand komponenti sorunsuz çalışıyor.
function TForm1.DosCommand1CharDecoding(ASender: TObject;
ABuf: TStream): string;
var s:string;
Bytes: TBytes;
begin
SetLength(Bytes, abuf.Size);
abuf.Read(bytes[0],ABuf.Size -1);
// https://msdn.microsoft.com/en-us/library...s.85).aspx
// 857 ibm857 OEM Turkish; Turkish (DOS)
// 1026 IBM1026 IBM EBCDIC Turkish (Latin 5)
// 1254 windows-1254 ANSI Turkish; Turkish (Windows)
s:= TEncoding.GetEncoding(857).GetString(bytes);
Memo1.Lines.Add(s);
end;
Yorumları: 4.224
Konuları: 379
Kayıt Tarihi: 07-07-2016
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 16.975 Üstad
Merhaba,
Linux hedef platformunda Terminal (CMD) üzerinde bir komutu çalıştırmak için de bir çözüm paylaşılmış.
Learn How To Execute External Commands On Linux From An Auto Tables For RAD Server API Endpoint
Yorumları: 656
Konuları: 69
Kayıt Tarihi: 24-01-2018
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 892 Acemi
Teşekkürler, çok güzel birkonu olmuş.
Yorumları: 656
Konuları: 69
Kayıt Tarihi: 24-01-2018
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 892 Acemi
(17-09-2016, Saat: 22:56)Fesih ARSLAN Adlı Kullanıcıdan Alıntı: Merhaba,
Windows hedef platformu için bir çoğumuz uygulama yazarken DOS ekranında komut çalıştırma ihtiyacı duymuşuzdur.
Bu kapsamda üretilen ve Ücretsiz olarak dağıtılan son derece etkili ve kullanışlı bir Component'ten bahsederek, kullanımı konusunda bilgiler vermek istiyorum.
Kullanacağımız component TurboPack DOSCommand.
Genel Özellikleri;
- Komut satırında herhangi bir veya birden fazla iş yaptırıma (com, exe ve bat dosyalarını doğrudan çalıştırma),
- Komutların işlem sonucunu kendi uygulamanızda görebilme (OnNewChar ve OnNewLine olayları ile OutputLnes ve Lines özellikleri),
- Komutun bittiğini algılama (OnTerminateProcess ve OnTerminated olayları),
- Varsayılan dizini belirleyebilme (CurrentDir özelliği),
- Geçici Ortam Değişkenleri ekleyebilme (Environment özelliği),
- Karakter Decode ve Encode işlemleri yapabilme (OnCharEncoding ve OnCharDecoding olayları),
- Çalışmayan ve Hata oluşturan komutları ve hata türünü yakalama (OnExecuteError olayı),
- Çalıştırılacak Komutların İşletim Sisteminde öncelik sırasını belirleyebilme (Priority özelliği; aldığı değerler----> HIGH_PRIORITY_CLASS, IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS ve REALTIME_PRIORITY_CLASS),
- Satır Satır Komut işletebilme (SendLine özelliği)
- Çalışma anında iş durumu hakkında bilgi edinebilme (OnTerminateProcess olayı ve ProcessInformation özelliği),
Component'i indirmek için: TurboPack - DOSCommand
Örnek Bir Uygulama;
Yukarıdaki linkten TurboPack - DOSCommand Component'ini indirip kuralım.
Tool Palette Penceresi, DOSCommand sekmesinden form üzerine bir adet DosCommand nesnesi yerleştirelim.
Form üzerine komutları çalıştırmak ve komut geri dönüş değerlerini almak için birer adet Edit, Button ve Memo nesnesi yerleştirelim ve tasarımını aşağıdaki gibi yapalım.
Bir veya birden fazla komut içeren bir toplu işlem dosyası (Batch dosyası) oluşturalım. Benim kullanacağım örnek dosya içeriği aşağıdaki gibi olacak.
Butonu çift tıklayıp, OnClick olayına aşağıdaki kodları yazalım.
procedure TForm1.Button1Click(Sender: TObject);
begin
DosCommand1.Priority := HIGH_PRIORITY_CLASS; {Çalışacak komutun iş önceliğini Yüksek olarak belirledik}
DosCommand1.CommandLine := edtKomut.Text; {Çalıştırılacak Komut veya Komutlar listesi}
DosCommand1.Execute; {Komutları çalıştır}
end;
DosCommand nesnesini seçelim ve Object Inspector Penceresi Events sekmesinde OnNewLine olayını çift tıklayalım ve aşağıdaki kodları yazalım.
procedure TForm1.DosCommand1NewLine(ASender: TObject; const ANewLine: string;
AOutputType: TOutputType);
begin
case AOutputType of
TOutputType.otEntireLine:
Memo1.Lines.Add(ANewLine);
end;
end;
Son olarak uygulamayı çalıştırıp, sonucuna bakalım.
İyi çalışmalar...
Öncelikle bilgilendirme için çok teşekkürler Fesih Bey. Birşey sormak istiyorum içeriğinde çalıştırdığımız komutların azılarında E/H sorusu var , sanırım yönetici yetkisinden içindeki komutları bu yetki sorununa takılmadan nasıl çalıştırabilir. Mesela ben sql server durdurmak istiyorum. Bir süre sonra çalıştırmak istiyorum ama durdurmaya çalıştığımda E/H kısmında kaldığı için çalışmıyor.
|