Dos窓で?

解決


マグ  2005-08-05 02:15:23  No: 123923

開発環境: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から送りたいのですが、どうすればよろしいでしょうか?


GOD  2005-08-05 03:05:53  No: 123924

> VB.NETから送りたいのですが、どうすればよろしいでしょうか?
>
具体的なコードは書いてないから本当にうまくいくか分からないけど。

ウィンドウハンドルさえ分かればあとは普通にキーを送れそうですね。
ウィンドウハンドルの求め方がいまいち微妙。
(.NETならそのようなものが用意されているかも。プロセスID→ウィンドウハンドル)
VB6ならEnumWindowとかでウィンドウを列挙して取得できたウィンドウハンドル
からプロセスIDを求めてShellの返値と同等か見ればいけそうだけど。


とおり  2005-08-05 10:38:49  No: 123925

Dos窓で、ウインドウハンドルや
外部からのシグナル系はたとえばCopyコマンドが
そういう作りになっていないCopyコマンドでは無理だと
思うんですが。

どちらかというと、ctrl + c より
Dos窓自体を閉じる方が正解では?

方法をご存知らしいGODさんにお任せです。

http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200508/05080001.txt
の続きの話ですよね?

私も知りたい。


ひろ  2005-08-05 19:44:27  No: 123926

何となく思っただけ何で外しているかもしれませんが、
SIGINT か CTRL_C_EVENT を投げることで何とかなりませんか?


id_rsa+  2005-08-05 20:31:53  No: 123927

GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)ってコンソールアプリからしか送れないみたいなんだよね。。。
VB6で作ったことあるけど、結構苦労した・・・


id_rsa+  2005-08-05 21:09:04  No: 123928

手元に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


葉月  2005-08-05 21:34:49  No: 123929

質問とは関係ないが・・・
表題を見て・・・
DOS窓で?・・・なんなんだよ!って思ったのは私だけでつか・・・


葉月  2005-08-05 21:36:52  No: 123930

ちなみにこれより前の質問で

FORMの透過で?

表題の通りですが・・・とあるが
何が表題のとおりかもさっぱりわからんかった・・・


マグ  2005-08-05 23:23:44  No: 123931

http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200508/05080001.txt
>の続きの話ですよね?

そうです。
でも、スレヌシが違います。

高速処理に中止が出来たらいいなぁと興味が出てきた
調べているのですが、なかなか出来ません(TT)

>ウィンドウハンドルさえ分かればあとは普通にキーを送れそうですね。

ウィンドウハンドルが出てきたと仮定して、
どのようにコーティングすれば、キーを送ることが可能なのでしょうか?


マグ  2005-08-06 03:05:25  No: 123932

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


moke  2005-08-06 03:15:21  No: 123933

↑一言で言うと  DOSは過去の産物  という事ですか?


id_rsa+  2005-08-06 04:24:50  No: 123934

AllocConsole の後で、
ShowWindow GetConsoleWindow(), SW_HIDE
こんなカンジ。


マグ  2005-08-06 08:12:58  No: 123935

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のデフラグがそのメッセージを広い、分析して、表示。」
の動作がない分だけ、スピードが速い。


通ってみた  2005-08-06 09:00:51  No: 123936

葉月さんが言ってるのは「DOS窓とは何か」ではなく「この表題はなんなんだ」ってことだと思われ


id_rsa+  2005-08-06 15:18:17  No: 123937

>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まで一緒に閉じてしまいました。
になっちゃうんですよ。。


通ってみた  2005-08-06 16:43:50  No: 123938

つーか、Windows3.1辺りを知らなかったりNTが2000より後だったりいろいろおかしい感じがする訳だが

2000はNTの進化系


マグ  2005-08-06 18:33:27  No: 123939

>つーか、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' に変換できません。"
とエラーが出てしまいます。


ねろ  2005-08-06 19:23:50  No: 123940

>次が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を使った方が良いかも。


マグ  2005-08-06 19:55:52  No: 123941

>葉月さんが言ってるのは「DOS窓とは何か」ではなく「この表題はなんなんだ」ってことだと思われ
すみません。気がつきませんでした。
別のレスでDosの話をしていたので、頭の中がDos窓のことで、
占拠状態に陥っていたので、Shell関数のことが出ずに、
Dos窓と書いてしまいました。
そして、表題を「Shell(Dos窓)を途中で終了させるにはどうすれば?」
と書いても良かったのですが、別のレスで書いてあるだろうと思われて、
飛ばされるかも?っと思ったので、このような表題になってしまいました。
分かりづらくて、すみませんでした。


葉月α  2005-08-08 20:01:22  No: 123942

通ってみたさん補足サンクス♪

ちなみにNT4だろうがWIN95だろうが
DOS3.3(もしくはそれ以前)もしっかり経験者です
(小学生でしたがコマンドでFormatやExe起動程度ならできました・・・
いっぱいフロッピーディスク壊しましたけど・・・(懐))


葉月α  2005-08-08 20:15:19  No: 123943

追記してこんな所でケンカ売る気は無いつもりだが

>別のレスで書いてあるだろうと思われて、
>飛ばされるかも?っと思ったので

と言われても、それを理由にするとしたら

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

以上全てその理由でつか?


通ってみた  2005-08-08 20:50:04  No: 123944

>>葉月さん
よくこんなにみつけてきましたね・・・w

以下、新規投稿のガイドラインより引用
>>    ・「〜するには?」のような質問形式にしてください。

これの勘違いでしょうな
質問者の表題には述語がないので、以後そこを気をつければよろしいかと


葉月α  2005-08-08 20:54:17  No: 123945

”で?”で検索したら出てきましたw


id_rsa+  2005-08-08 21:10:12  No: 123946

ところで、みなさん。私は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


マグ  2005-08-08 21:21:31  No: 123947

>>別のレスで書いてあるだろうと思われて、
>>飛ばされるかも?っと思ったので

>と言われても、それを理由にするとしたら
>・・・・・・
>以上全てその理由でつか?

違うと思います。
知らないうちに言葉がクセになっていた可能性があるかも?

>これの勘違いでしょうな
>質問者の表題には述語がないので、以後そこを気をつければよろしいかと

はい、気をつけます。

そして、
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' に変換できません。"
とエラーで出ます。
どのようにソースを変えればいいのでしょうか?


マグ  2005-08-08 21:40:45  No: 123948

id_rsa+さん、ありがとうございます。
出来ました。
でも、VB.NETって'AddressOf'が入ってきただけでこんなに複雑になるなんて・・・・・


id_rsa+  2005-08-08 22:05:48  No: 123949

どういたしまして。
>でも、VB.NETって'AddressOf'が入ってきただけでこんなに複雑になるなんて・・・・・

ほんと・・・VBの長所の「お手軽さ」が無くなってる気がする。。
この間も.NET付属のクリレポ配布するのに、なんかタイヘンだった(;;)


GOD  2005-08-09 20:45:30  No: 123950

最近少し忙しかったので既に遅いけど・・・(夏休みが一週ずれたし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


GOD  2005-08-09 22:28:56  No: 123951

2005/08/09(火) 11:45:30で投稿したプログラムはうまく動いていなかった。(TT
PostMessageで投げるとCtrl+C(複合キー)は正しく認識してくれないみたい。
(abcみたいに単体なら送れるのだけど)
ここをうまく改造できればいけそうだけど・・・ちょっと思いつかないな。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加