View Full Version : نوشتن برنامه های Command Line با دلفی
مجتبی تاجیک
چهارشنبه 23 اردیبهشت 1388, 14:15 عصر
:لبخندساده:سلام
:متفکر:دوستان چطور میتونم یه برنامه ی Command Line با دلفی بنویسم ، یعنی مثلا وقتی برنامم اجرا شد و بهش با خط فرمان ( CMD ) یا هر برنامه ی دیگه ای فرمان Exit رو به صورت زیر صادر کردم برنامم بسته شه ...
"MyProject.exe","Exit"
:چشمک:ممنون .
Saeed_m_Farid
چهارشنبه 23 اردیبهشت 1388, 14:50 عصر
:لبخندساده:سلام
:متفکر:دوستان چطور میتونم یه برنامه ی Command Line با دلفی بنویسم ، یعنی مثلا وقتی برنامم اجرا شد و بهش با خط فرمان ( CMD ) یا هر برنامه ی دیگه ای فرمان Exit رو به صورت زیر صادر کردم برنامم بسته شه ...
"MyProject.exe","Exit":چشمک:ممنون .
با سلام
بنده متوجه اون تکه کدی که آخر پست گذاشتین نشدم، ولی اگه بخواین یه شبیه سازی Command Promt داس داشته باشین نظر من اینه :
یه پروژه کنسول ایجاد کنید
یه لیستی از کلمات کلیدی که واسه برنامتون مهمه، تهیه کنید. مثلا exit برای خروج، help واسه راهنمایی (اگه نمیخواین help کامند پرامت اصلی نمایش داده بشه و ...)
بافر کاربر رو Readln کرده و اگه جزء لیست کلمات کلیدی بود، کار مربوطه رو باهاش انجام بدین، مثلا واسه
UpperCase(FcmdBuffer) = 'EXIT' میتونید Application.Terminate کنید و ...
واسه بقیه موارد اگه بافر دریافتی یه فایل موجود و اجرایی نبود (ترکیبی از دستور Shell و پارامترهاش بود) من این کار رو میکنم :
GetEnvironmentVariable('COMSPEC',
Fcmdbuffer,
SizeOf(FcmdBuffer));
g_szProcessInstance.ProcessID :=
ShellExecute(Handle ,
'open',
Fcmdbuffer,
PChar('/c' + FParams),
PChar(ExtractFilePath(Fcmdbuffer)),
SW_SHOWNORMAL); که در اینجا FParams هم دستور تایپ شده و شامل پارامترهای اون دستور هست ...
اگه بافر دریافتی فایل اجرایی موجود در سیستم (امتحان با FileExist) و دارای پسوند اجرایی (exe, com, bat , ...) بود، از طریق RunProcess که تابعش در زیر اومده اجراش میکنم :
(************************************************* ***************)
function RunProcess(FileName : string;
Params : string;
ShowCmd : DWORD;
ProcID : PDWORD;
wait : Boolean): DWORD;
var
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
begin
FillChar(StartupInfo, SizeOf(StartupInfo), #0);
StartupInfo.cb := SizeOf(StartupInfo);
StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_FORCEONFEEDBACK;
StartupInfo.wShowWindow := ShowCmd;
if not CreateProcess(
@FileName[1],
@Params[1],
nil,
nil,
False,
CREATE_NEW_CONSOLE or
NORMAL_PRIORITY_CLASS,
nil,
PChar(ExtractFilePath(FileName)),
StartupInfo,
ProcessInfo)
then
Result := WAIT_FAILED
else
begin
if wait = FALSE then
begin
if ProcID <> nil then
ProcID^ := ProcessInfo.dwProcessId;
result := WAIT_FAILED;
exit;
end;
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
GetExitCodeProcess(ProcessInfo.hProcess, Result);
end;
if ProcessInfo.hProcess <> 0 then
CloseHandle(ProcessInfo.hProcess);
if ProcessInfo.hThread <> 0 then
CloseHandle(ProcessInfo.hThread);
end;
(************************************************* ***************)
میتونین مثلا اگه بافر دریافتی LOAD بود، با یک TOpenDialog فایل رو از کاربر بگیرین و با همون تابع RunProcess اجراش کنید، نمونه گرفتن فایل :
(************************************************* ***************)
procedure LoadProc;
begin
with TOpenDialog.Create(Self) do try
Filter := 'Executable files (*.exe)|*.exe|';
Filter := Filter + 'Com files (*.com)|*.com|';
Filter := Filter + 'Batch files (*.bat;*.cmd)|*.bat;*.cmd|';
Filter := Filter + 'All files (*.*)|*.*';
if Execute then begin
if FileExists(FileName) then
edtAppName.Text := FileName
else
MessageBox(Handle,
'Input FileName isn''t valid, you may type invalid file name!',
'File path/name is incorrect!',
MB_ICONERROR or MB_OK);
end;
finally
Free;
end;
end;
(************************************************* ***************)
البته امیدوارم منظورتون رو درست گرفته باشم، واسه ایجاد Console Application هم مراحل روبرو File->New->Others و اونجا هم که Console Application هست و انتخابش کنید ...
علی کشاورز
چهارشنبه 23 اردیبهشت 1388, 18:31 عصر
فکر می کنم منظور دریافت پارامتر از خط فرمان بوده. برای این کار از ParamCount و ParamStr استفاده کنید. ParamCount تعداد پارامترهای خط فرمانی که به برنامه شما ارسال شده را بر می گردانه، و ParamStr هم پارامتر مورد نظر را برگشت میده.
as13851365
پنج شنبه 24 اردیبهشت 1388, 12:13 عصر
سوال :
البته تا اونجایی که من فهمیدم برای ارسال پارامتر به یک برنامه باید هنگام اجرا کردن برنامه مزبور پارامترها را ارسال کنیم حالا اگر برنامه در حال اجرا باشه چطوری می تونید پارامترها را بهش ارسال کنیم و یک نسخه از برنامه اجرا نشه ؟
مثلا به برنامه X کار Copy , delete , help یک سری فایل ها رو دادیم حالا وقتی که برنامه را با پارامتر yes اجرا می کنیم برنامه ی X کار Copy رو شروع می کنه :
s:=' X آدرس برنامه ';
ShellExecute(Handle,'open',pchar(s),'yes',nil,SW_S HOWNORMAL);
حالا برنامه اجرا می شه و کار کپی رو شروع می کنه حالا چطوری می تونم یه پارامتر دیگه به برنامه ارسال کنم که کار delete رو انجام بده ؟
در حالت عادی من بعد از این که کار برنامه تمام شد بسته می شه و مجدد برنامه را با پارامتر دیگه اجرا می کنم حالا نمی شه وقتی که برنامه در حال اجرا است پارامتر دیگه ای بهش ارسال کرد ؟
البته نمی دونم این سوال مربوط به این بحث می شه یا نه ولی اگر راهنمایی کنید ممنون می شم.
Saeed_m_Farid
پنج شنبه 24 اردیبهشت 1388, 14:08 عصر
در حالت عادی من بعد از این که کار برنامه تمام شد بسته می شه و مجدد برنامه را با پارامتر دیگه اجرا می کنم حالا نمی شه وقتی که برنامه در حال اجرا است پارامتر دیگه ای بهش ارسال کرد ؟نظر بنده اینه : میتونید یه فلگ واسه اینکه کاربر دستور اتمام برنامه داده یا نه مثل bCloseApp بذارید تا زمانی که bCloseApp معادل True نشده (یعنی کاربر مثلا exit تایپ نکرده) تو یه While از کاربر بافر درخواستی اش رو بگیرید و مراحل رو طبق پست 2 ادامه بدین ...
در ضمن این ربطی به گرفتن پارامترهای خط فرمان نداره، بلکه یه شبیه سازی این خط فرمان میشه که میتونین بافرهایی که جزو لیست دستورات شما نیست رو بفرستین به ShellExecute یا RunProcess و ادامه مراحل کار ...
مجتبی تاجیک
پنج شنبه 24 اردیبهشت 1388, 14:23 عصر
نظر بنده اینه : میتونید یه فلگ واسه اینکه کاربر دستور اتمام برنامه داده یا نه مثل bCloseApp بذارید تا زمانی که bCloseApp معادل True نشده (یعنی کاربر مثلا exit تایپ نکرده) تو یه While از کاربر بافر درخواستی اش رو بگیرید و مراحل رو طبق پست 2 ادامه بدین ...
در ضمن این ربطی به گرفتن پارامترهای خط فرمان نداره، بلکه یه شبیه سازی این خط فرمان میشه که میتونین بافرهایی که جزو لیست دستورات شما نیست رو بفرستین به ShellExecute یا RunProcess و ادامه مراحل کار ...
فکر نمیکنم درست باشه .
منم دقیقا همین مسئله برام پیش اومده ، دوستان چیزی از این موضوع میدونن ؟
Saeed_m_Farid
پنج شنبه 24 اردیبهشت 1388, 15:57 عصر
فکر نمیکنم درست باشه .
منم دقیقا همین مسئله برام پیش اومده ، دوستان چیزی از این موضوع میدونن ؟
عذر میخوام جناب SilverSoft میشه بگین فکر نمی کنین چی درست باشه؟
دقیقتر بفرمایید، من واسه این فرمایش شما نشستم یه نمونه کد نوشتم ببینم کجاش ممکنه درست نباشه؟
فقط موردی که هست اینه که شما بخواین تو همون Console که برنامه ایجاد میشه دستورات API رو مستقیماً اجرا کنید که اونوقت باید Pipe زده بشه، اونم اگه بخواید توضیح میدم.
نمونه برنامه فقط واسه اینکه فکر کنید درسته :
program CmdLineSimulation;
{$APPTYPE CONSOLE}
uses
Windows,
SysUtils,
ShellApi;
const
COMMANDS_NUM = 9;
type
Command_Set = Array [0 .. COMMANDS_NUM] of String;
(************************************************* ***************)
var
bCanClose: Boolean;
sCmdBuffer: String;
const
APP_CMD_LIST : Command_Set = ('test1',
'test2',
'test3',
'test4',
'test5',
'test6',
'test7',
'test8',
'test9',
'exit');
CMD_DEFAULT = 'SMF Test > ';
(************************************************* ***************)
function isCmdRegistered(sCmdName: String): Boolean;
var
idx: Integer;
begin
Result := False;
for idx := 0 to COMMANDS_NUM do
if LowerCase(sCmdBuffer) = APP_CMD_LIST[idx] then
Result := True;
end;
(************************************************* ***************)
procedure doSomething(sCmdName: String);
begin
if LowerCase(sCmdName) <> 'exit' then begin
Writeln('You type somthing like ', QuotedStr(sCmdName));
// Place your code here ...
end else
bCanClose := True;
end;
(************************************************* ***************)
function RunCmdLine(szCmdBuffer: String): Integer;
var
szCmdPath: array [0 .. MAX_PATH ] of Char;
begin
GetEnvironmentVariable('COMSPEC',
szCmdPath,
SizeOf(szCmdPath));
Result := ShellExecute(0 ,
'open',
szCmdPath,
PChar('/c' + szCmdBuffer),
PChar(ExtractFilePath(szCmdPath)),
SW_SHOWNORMAL);
end;
(************************************************* ***************)
begin
bCanClose := False;
while not bCanClose do begin
Write(CMD_DEFAULT);
Readln(sCmdBuffer);
if isCmdRegistered(sCmdBuffer) then begin
Writeln('Registered');
doSomething(sCmdBuffer);
end else begin
Writeln('Not Registered');
RunCmdLine(sCmdBuffer);
end;
Writeln;
end;
(************************************************* ***************)
end.
با تشکر
علی کشاورز
پنج شنبه 24 اردیبهشت 1388, 20:16 عصر
حالا اگر برنامه در حال اجرا باشه چطوری می تونید پارامترها را بهش ارسال کنیم و یک نسخه از برنامه اجرا نشه ؟
اون وقت از روش های Inter-process Communication استفاده میشه. می تونید IPC را در سایت جستجو کنید.
مجتبی تاجیک
جمعه 25 اردیبهشت 1388, 02:09 صبح
عذر میخوام جناب SilverSoft میشه بگین فکر نمی کنین چی درست باشه؟
دقیقتر بفرمایید، من واسه این فرمایش شما نشستم یه نمونه کد نوشتم ببینم کجاش ممکنه درست نباشه؟
فقط موردی که هست اینه که شما بخواین تو همون Console که برنامه ایجاد میشه دستورات API رو مستقیماً اجرا کنید که اونوقت باید Pipe زده بشه، اونم اگه بخواید توضیح میدم.
دوست عزیز من دقیقا چیزی که آقای کشاورز گفتن رو لازم داشتم ( برنامه ای که از طریق برنامه ی دیگه دستور بگیره ) که آقای کشاورز در پست 3 روشش رو گفتن که با 2 تابع ParamCount و ParamStr هستش .
در مورد سوال بعدی هم چون با ارسال یه دستور به برنامه یه نسخه دیگه از برنامه اجرا میشد اون سوال رو پرسیدم تا همیشه یک نسخه از برنامه قابل اجرا باشه و لازم نباشه هر بار یه نسخه اجرا شه .
برنامه ای که شما نوشتید بحثش جدا هست، اگر درست بود آقای کشاورز هم تائیدش میکردن .
vBulletin® v4.0.8, Copyright ©2000-1390, Jelsoft Enterprises Ltd.