開発環境:VB.NET + Windows XP pro + コマンドプロプト
VB.NETからDos・コマンドプロプトにキーのコマンドを送るには
どうすれば、よろしいでしょうか?
Dim process As Object
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
process = Shell("xcopy 元 コピー先 /s")
End Sub
を実行している最中に中止ボタンが押されたときに
この処理(XCopyコマンド)を止めるために' Ctrl + C 'のキーを
VB.NETから送りたいのですが、どうすればよろしいでしょうか?
> VB.NETから送りたいのですが、どうすればよろしいでしょうか?
>
具体的なコードは書いてないから本当にうまくいくか分からないけど。
ウィンドウハンドルさえ分かればあとは普通にキーを送れそうですね。
ウィンドウハンドルの求め方がいまいち微妙。
(.NETならそのようなものが用意されているかも。プロセスID→ウィンドウハンドル)
VB6ならEnumWindowとかでウィンドウを列挙して取得できたウィンドウハンドル
からプロセスIDを求めてShellの返値と同等か見ればいけそうだけど。
Dos窓で、ウインドウハンドルや
外部からのシグナル系はたとえばCopyコマンドが
そういう作りになっていないCopyコマンドでは無理だと
思うんですが。
どちらかというと、ctrl + c より
Dos窓自体を閉じる方が正解では?
方法をご存知らしいGODさんにお任せです。
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200508/05080001.txt
の続きの話ですよね?
私も知りたい。
何となく思っただけ何で外しているかもしれませんが、
SIGINT か CTRL_C_EVENT を投げることで何とかなりませんか?
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)ってコンソールアプリからしか送れないみたいなんだよね。。。
VB6で作ったことあるけど、結構苦労した・・・
手元にVB6しかないので、参考程度に・・・・
Private Declare Function AllocConsole Lib "kernel32" () As Long
Private Declare Function FreeConsole Lib "kernel32" () As Long
Private Declare Function SetConsoleCtrlHandler Lib "kernel32" (ByVal lpHandlerRoutine As Long, ByVal bAdd As Long) As Long
Private Declare Function GenerateConsoleCtrlEvent Lib "kernel32" (ByVal dwCtrlEvent As Long, ByVal dwProcessGroupId As Long) As Long
Private Const CTRL_C_EVENT = &H0&
Private Sub Command1_Click()
Shell "xcopy C:\TEST D:\TEST\ /s"
End Sub
Private Sub Command2_Click()
Call GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)
End Sub
Private Sub Form_Load()
Call AllocConsole
Call SetConsoleCtrlHandler(AddressOf HandlerRoutine, 1)
End Sub
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Call FreeConsole
End Sub
※標準モジュール
Public Function HandlerRoutine(ByVal Param As Long) As Long
HandlerRoutine = 1
End Function
質問とは関係ないが・・・
表題を見て・・・
DOS窓で?・・・なんなんだよ!って思ったのは私だけでつか・・・
ちなみにこれより前の質問で
FORMの透過で?
表題の通りですが・・・とあるが
何が表題のとおりかもさっぱりわからんかった・・・
>http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200508/05080001.txt
>の続きの話ですよね?
そうです。
でも、スレヌシが違います。
高速処理に中止が出来たらいいなぁと興味が出てきた
調べているのですが、なかなか出来ません(TT)
>ウィンドウハンドルさえ分かればあとは普通にキーを送れそうですね。
ウィンドウハンドルが出てきたと仮定して、
どのようにコーティングすれば、キーを送ることが可能なのでしょうか?
>Dos窓自体を閉じる方が正解では?
Shell("Exit")と行ったのですが出来ませんでした。
id_rsa+さん、ひろさん、とおりさん、GODさん ありがとうございます。
できました。
ソースはこのような感じです。
Private Declare Function AllocConsole Lib "kernel32" () As Integer
Private Declare Function FreeConsole Lib "kernel32" () As Integer
Private Declare Function GenerateConsoleCtrlEvent Lib "kernel32" ( _
ByVal dwCtrlEvent As Integer, ByVal dwProcessGroupId As Integer) As Integer
Private Const CTRL_C_EVENT = &H0&
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Shell("xcopy 元 コピー先)
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Call GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Call AllocConsole()
'Call SetConsoleCtrlHandler(AddressOf HandlerRoutine, 1)
End Sub
Private Sub Form1_Closed(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Closed
Call FreeConsole()
End Sub
Public Function HandlerRoutine(ByVal Param As Integer) As Integer
HandlerRoutine = 1
End Function
あと、バックグラウンドで動作させるにはどうすればよろしいでしょうか?
さすがにDos窓をデスクトップ上で見せたくないので・・・・・
>葉月さん
DosはOSの元です。
つまり、元祖。
もともと昔はDosでの操作でした。
しかし、Windows 〜〜〜←忘れた・・・・・
がDosを経由させて、デスクトップ上に表示させて、動作するOSが完成。
次にWindows 95、98と次々と出てきて、Windows 2000とWindows Meに分かれて、
Windows NT が登場。
次がWindows XP Home とWindows XP Proが出てきました。
つまり、これらのOSはDosを経由して、動いています。
そして、Widows 2000以前がそのDosを操作するものをDos窓と言われている
アプリです。
このアプリは元祖からずっと、引き継がれています。
Window XPは「コマンドプロンプト」という名称に変わっています。
で、VB.NETのShell関数はこの元祖から引き継がれている
Dos窓/コマンドプロプトにコマンドを送る関数です。
だから、昔の方は最近のデスクトップ上にによる操作より
Dos窓が落ち着いて、好きだと言う人がいます。
しかし、最近の若い方はデスクトップ上が好きだと言う方が100%です。
そして、一ついえることは最近の若者はDos窓の操作が出来ないということです。
理由は、Dosを使わなくても、OS自体が相当の機能を持っていること。
よって、たとえ、先生が知っていても、無理に教える必要がない。
そして、本人も知ろうとはしない。
なぜなら、めんどくさいから。
そして、Dos窓の存在が知られないまま、その生徒が先生になる。
上の繰り返し。
ということです。
ってか上の文章でめちゃくちゃ言ってますが、私も人のことが言えないんですけどね・・・・・
まだ、学生ですし・・・・・・
Dos窓のことを知っている理由としては、無理やり、教えられた。
どんなに聞いても、「知ってれば、何か必要な時が来る」という理由だけで
強引に・・・・
あのときは悲劇だったかも(TT)
↑一言で言うと DOSは過去の産物 という事ですか?
AllocConsole の後で、
ShowWindow GetConsoleWindow(), SW_HIDE
こんなカンジ。
id_rsa+さん、ありがとうございます。
Dos窓を非表示させることが出来ましたが・・・・・
中止をすると、Formまで一緒に閉じてしまいました。
質問の内容を満たしたので、これで解決としました。
>一言で言うと DOSは過去の産物 という事ですか?
そういうことです。
Dosからあるから、Dos窓やコマンドプロンプトがあり、
それがあるから、OSがあり、OSがあるからDos系のソフトウィアーが存在し、
それがあるから、VB.NETや開発系のソフトが存在し、
また、それがあるから、VB.NET製などのソフトが存在するということです。
まとめると、Dos窓でデフラグをかけるときとWindows XPなどの標準的な機能でデフラグをかけるとき・・・・・
Dos窓でかけたほうが断然、速いです。
その理由としては、
XPの標準のでフラグの仕掛けは
デフラグを実行→指示をDos窓に伝える→Dosが実行される。→
Dosから現在の状態が出される。→その状態をDos窓に出力→
Windows XPのデフラグがそのメッセージを広い、分析して、表示。
Dos窓からの場合は
指示をDos窓に入力→Dosが実行される。→Dosから現在の状態が出される。→その状態をDos窓に出力
よって、「Windows XPのデフラグがそのメッセージを広い、分析して、表示。」
の動作がない分だけ、スピードが速い。
葉月さんが言ってるのは「DOS窓とは何か」ではなく「この表題はなんなんだ」ってことだと思われ
>Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
> Call AllocConsole()
> 'Call SetConsoleCtrlHandler(AddressOf HandlerRoutine, 1)
>End Sub
このSetConsoleCtrlHandlerってトコをコメントにしてるから、
>中止をすると、Formまで一緒に閉じてしまいました。
になっちゃうんですよ。。
つーか、Windows3.1辺りを知らなかったりNTが2000より後だったりいろいろおかしい感じがする訳だが
2000はNTの進化系
>つーか、Windows3.1辺りを知らなかったりNTが2000より後だったりいろいろおかしい感じがする訳だが
思い出しました。
Windows 3.1でした・・・・・
すみません。
間違えました。
2000より、NTが先に登場していました。
>このSetConsoleCtrlHandlerってトコをコメントにしてるから、
そこがエラーになってしまいます。
Private Declare Function SetConsoleCtrlHandler Lib "kernel32" ( _
ByVal lpHandlerRoutine As Integer, ByVal bAdd As Integer) As Integer
Public Function HandlerRoutine(ByVal Param As Integer) As Integer
HandlerRoutine = 1
End Function
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Call AllocConsole()
Call SetConsoleCtrlHandler(AddressOf HandlerRoutine, 1)
End Sub
と記述しているのですが、
"'Integer' は、デリゲート型でないため、'AddressOf' 式を 'Integer' に変換できません。"
とエラーが出てしまいます。
>次がWindows XP Home とWindows XP Proが出てきました。
>つまり、これらのOSはDosを経由して、動いています。
Windows 3.1,Windows 9xはMS-DOSの上で動くアプリケーションソフト。
Windows NT 系(2000,Xp)は32ビットの完全なるOS、従って
NT系にはMS-DOSは無く、DOS窓(正式にはコマンドプロンプト)は
MS-DOSのエミュレーションモード。
従ってNT系ではDOS窓の速度は絶対的に速いとは言えない。
ただしファイルのコピーなどの操作で、オーバーヘッドの多いVBの関数
に比べて、DOS窓の操作はかなり速いはず。
>↑一言で言うと DOSは過去の産物 という事ですか?
全くその通り、いつまでもこんなものを使っていてはいかん。
(言い出しておいてスマン。orz)
元の質問はSHFileOperationを使ってファイルをコピーしている
と書いてあるが、この関数は遅いのではないかな、速度を重視するなら
CopyFileを使った方が良いかも。
>葉月さんが言ってるのは「DOS窓とは何か」ではなく「この表題はなんなんだ」ってことだと思われ
すみません。気がつきませんでした。
別のレスでDosの話をしていたので、頭の中がDos窓のことで、
占拠状態に陥っていたので、Shell関数のことが出ずに、
Dos窓と書いてしまいました。
そして、表題を「Shell(Dos窓)を途中で終了させるにはどうすれば?」
と書いても良かったのですが、別のレスで書いてあるだろうと思われて、
飛ばされるかも?っと思ったので、このような表題になってしまいました。
分かりづらくて、すみませんでした。
通ってみたさん補足サンクス♪
ちなみにNT4だろうがWIN95だろうが
DOS3.3(もしくはそれ以前)もしっかり経験者です
(小学生でしたがコマンドでFormatやExe起動程度ならできました・・・
いっぱいフロッピーディスク壊しましたけど・・・(懐))
追記してこんな所でケンカ売る気は無いつもりだが
>別のレスで書いてあるだろうと思われて、
>飛ばされるかも?っと思ったので
と言われても、それを理由にするとしたら
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200406/04060106.txt
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200408/04080062.txt
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200410/04100078.txt
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200411/04110001.txt
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200411/04110030.txt
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200411/04110039.txt
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200411/04110108.txt
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200412/04120098.txt
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200504/05040041.txt
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200507/05070156.txt
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200508/05080007.txt
以上全てその理由でつか?
>>葉月さん
よくこんなにみつけてきましたね・・・w
以下、新規投稿のガイドラインより引用
>> ・「〜するには?」のような質問形式にしてください。
これの勘違いでしょうな
質問者の表題には述語がないので、以後そこを気をつければよろしいかと
”で?”で検索したら出てきましたw
ところで、みなさん。私はVB.NETあまり詳しくないんですが、
こんな感じで合ってますか?
Declare Function SetConsoleCtrlHandler Lib "kernel32.dll" (ByVal HandlerRoutine As ConsoleCtrlDelegate,ByVal Add As Boolean) As Boolean
Delegate Function ConsoleCtrlDelegate(ByVal dwControlType As Integer) As Boolean
SetConsoleCtrlHandler(AddressOf HandlerRoutine, True)
Public Shared Function HandlerRoutine(ByVal dwControlType As Integer) As Boolean
HandlerRoutine = True
End Function
>>別のレスで書いてあるだろうと思われて、
>>飛ばされるかも?っと思ったので
>と言われても、それを理由にするとしたら
>・・・・・・
>以上全てその理由でつか?
違うと思います。
知らないうちに言葉がクセになっていた可能性があるかも?
>これの勘違いでしょうな
>質問者の表題には述語がないので、以後そこを気をつければよろしいかと
はい、気をつけます。
そして、
Private Declare Function SetConsoleCtrlHandler Lib "kernel32" (ByVal lpHandlerRoutine As Long, ByVal bAdd As Long) As Long
Private Sub Form_Load()
Call AllocConsole
Call SetConsoleCtrlHandler(AddressOf HandlerRoutine, 1)
End Sub
※標準モジュール
Public Function HandlerRoutine(ByVal Param As Long) As Long
HandlerRoutine = 1
End Function
のVB6のソースをVB.NETのソースに変えたのですが、
Private Declare Function SetConsoleCtrlHandler Lib "kernel32" ( _
ByVal lpHandlerRoutine As Integer, ByVal bAdd As Integer) As Integer
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Call AllocConsole()
Call SetConsoleCtrlHandler(AddressOf HandlerRoutine, 1) '←
End Sub
Public Function HandlerRoutine(ByVal Param As Integer) As Integer
HandlerRoutine = 1
End Function
矢印のところで
"'Integer' は、デリゲート型でないため、'AddressOf' 式を 'Integer' に変換できません。"
とエラーで出ます。
どのようにソースを変えればいいのでしょうか?
id_rsa+さん、ありがとうございます。
出来ました。
でも、VB.NETって'AddressOf'が入ってきただけでこんなに複雑になるなんて・・・・・
どういたしまして。
>でも、VB.NETって'AddressOf'が入ってきただけでこんなに複雑になるなんて・・・・・
ほんと・・・VBの長所の「お手軽さ」が無くなってる気がする。。
この間も.NET付属のクリレポ配布するのに、なんかタイヘンだった(;;)
最近少し忙しかったので既に遅いけど・・・(夏休みが一週ずれたしorz)
VB6でEnumWindowsを使ったサンプルを貼っておきますね。
'Form側
Private Sub Form_Load()
'タスクIDを外部変数に保存
glngShellProcID = Shell("cmd.exe /c dir /?")
End Sub
'Ctrl+C送信ボタン
Private Sub cmdSend_Click()
'ウィンドウの列挙
Call EnumWindows(AddressOf EnumWindowProc, &H0)
End Sub
'標準モジュール側
Public glngShellProcID As Long
'EnumWindowのコールバック関数
Public Function EnumWindowProc(ByVal hwnd As Long, ByVal lParam As Long) As Boolean
Dim lngProcID As Long
Dim lngThreadID As Long
'ハンドルからスレッド、プロセスIDを求める
lngThreadID = GetWindowThreadProcessId(hwnd, lngProcID)
'Shellしたものと同じ?
If lngProcID = glngShellProcID Then
'Ctrl+Cを送る(キーエミュ)
Call PostMessage(hwnd, WM_KEYDOWN, vbKeyControl, GetlParam(vbKeyControl, False))
Call PostMessage(hwnd, WM_KEYDOWN, vbKeyC, GetlParam(vbKeyC, False))
Call PostMessage(hwnd, WM_KEYUP, vbKeyC, GetlParam(vbKeyC, True))
Call PostMessage(hwnd, WM_KEYUP, vbKeyControl, GetlParam(vbKeyControl, True))
End If
EnumWindowProc = True
End Function
Public Function GetlParam(lngKeyCode As Long, blnUp As Boolean) As Long
Dim lngVK As Long
Dim lnglParam As Long
lngVK = MapVirtualKey(lngKeyCode, 0)
lnglParam = 1 Or (lngVK * (2 ^ 16))
If blnUp Then
lnglParam = lnglParam Or &HC0000000
End If
'ここは他の拡張キーでも同じ事をする必要があるが今回はこれだけなので・・・
If lngKeyCode = vbKeyControl Then
lnglParam = lnglParam Or &H1000000
End If
GetlParam = lnglParam
End Function
2005/08/09(火) 11:45:30で投稿したプログラムはうまく動いていなかった。(TT
PostMessageで投げるとCtrl+C(複合キー)は正しく認識してくれないみたい。
(abcみたいに単体なら送れるのだけど)
ここをうまく改造できればいけそうだけど・・・ちょっと思いつかないな。
ツイート | ![]() |