C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

3分後に自動シャットダウン

[トピック内 10 記事 (1 - 10 表示)]  << 0 >>

■83431 / inTopicNo.1)  3分後に自動シャットダウン
  
□投稿者/ ざっく (1回)-(2017/03/23(Thu) 13:03:36)

分類:[.NET 全般] 

3分後に自動実行します、というダイアログを出したあと
OKボタンが押されるか三分経つと自動的にシャットダウンが実行されるプログラムを
以下のように書きました。

ただ、このコードはCreateObject("WScript.Shell")を使っているため
option strictでエラーとなってしまいます。

どうすればエラー無しにすることができますか?


                Dim rc As Integer
                Dim WSH As Object = CreateObject("WScript.Shell")
                rc = WSH.Popup("シャットダウンしますか?(3分後に自動実行)", 180, "自動シャットダウン", vbOKCancel)

                WSH = Nothing

                If rc = vbOK Or rc = -1 Then            '1 vbOK     2 vbCancel  -1 自動停止した場合

                    Call Shell("shutdown -s -t 3", vbHide)   
                    Application.Exit()
                End If




引用返信 編集キー/
■83432 / inTopicNo.2)  Re[1]: 3分後に自動シャットダウン
□投稿者/ 魔界の仮面弁士 (1207回)-(2017/03/23(Thu) 13:23:44)
No83431 (ざっく さん) に返信
> WSH = Nothing
COM オブジェクトの即時解放を目的としているのなら、これでは不足です。

VBScript ならば Nothing 代入だけで十分でしたが、
VB.NET では Marshal.ReleaseComObject メソッドを使う必要があります。


> If rc = vbOK Or rc = -1 Then
Or 演算子ではなく、OrElse 演算子を使いましょう。


> ただ、このコードはCreateObject("WScript.Shell")を使っているため
> option strictでエラーとなってしまいます。
> どうすればエラー無しにすることができますか?

つい先日、 No83366No83378 でも同じような事を書きましたが、
Option Strict On で利用するのであれば、
 (案1)参照設定して利用する
 (案2)CallByName で対応する
 (案3)リフレクションで対応する
といった対処になります。

あるいは Partial Class や Partial Method 等を用いて、
Popup メソッドの処理部分のみを、Option Strict Off のファイルに逃がすかですね。


'案1
Dim wshShell As New IWshRuntimeLibrary.WshShell()
Dim rc As Integer = wshShell.Popup("シャットダウンしますか?(3分後に自動実行)", 180, "自動シャットダウン", vbOKCancel Or vbQuestion Or vbDefaultButton2)
System.Runtime.InteropServices.Marshal.ReleaseComObject(wshShell)
If rc = vbOK OrElse rc = -1 Then


'案2
Dim WSH As Object = CreateObject("WScript.Shell")
Dim rc As Integer = CInt(CallByName(WSH, "Popup", CallType.Method, "シャットダウンしますか?(3分後に自動実行)", 180, "自動シャットダウン", vbOKCancel Or vbQuestion Or vbDefaultButton2))
System.Runtime.InteropServices.Marshal.ReleaseComObject(WSH)
If rc = vbOK OrElse rc = -1 Then


'案3
Dim WSH As Object = CreateObject("WScript.Shell")
Dim rc As Integer = CInt(WSH.GetType().InvokeMember( _
  "Popup", System.Reflection.BindingFlags.InvokeMethod, Nothing, _
  WSH, New Object() { _
    "シャットダウンしますか?(3分後に自動実行)", _
    180, _
    "自動シャットダウン", _
    vbOKCancel Or vbQuestion Or vbDefaultButton2 _
  }))
System.Runtime.InteropServices.Marshal.ReleaseComObject(WSH)
If rc = vbOK OrElse rc = -1 Then
引用返信 編集キー/
■83433 / inTopicNo.3)  Re[2]: 3分後に自動シャットダウン
□投稿者/ ざっく (2回)-(2017/03/23(Thu) 13:42:17)
No83432 (魔界の仮面弁士 さん) に返信

ありがとうございます。うまくいきました。

ところで、
> VBScript ならば Nothing 代入だけで十分でしたが、
> VB.NET では Marshal.ReleaseComObject メソッドを使う必要があります。
という話に関してなのですが、COMオブジェクトを開放しなかった場合
どういう時に問題が発生しますか?
いままで特に開放処理をしなかったからといって
問題が発生したことがないと思うのですが。

引用返信 編集キー/
■83434 / inTopicNo.4)  Re[3]: 3分後に自動シャットダウン
□投稿者/ 魔界の仮面弁士 (1208回)-(2017/03/23(Thu) 15:05:22)
No83433 (ざっく さん) に返信
> どういう時に問題が発生しますか?

たとえばアウトプロセス(ActiveX EXE)の場合、
処理が完了した後も操作対象のアプリへの参照が残り続けることで、
相手側のアプリの終了が阻害され、非表示のゾンビプロセスとして
残り続けてしまう原因となりえます。


[Visual Studio .NET クライアントで自動化した Office アプリケーションが終了しない]
http://bit.ly/KB317109ja
》 オブジェクトの使用が終了したら、
》 System.Runtime.InteropServices.Marshal.ReleaseComObject を使用します。
》 このメソッドによって RCW の参照カウントを減らします。


[Visual Basic .NET から Access を自動化する方法]
https://support.microsoft.com/ja/help/317113
》oDB と oDBEngine の各オブジェクトを解放するコードに注目してください。
》これらのオブジェクトを使用して、コードの完了後に
》Access が正常に終了するようにする必要があります。


インプロセス(ActiveX DLL)の場合は、アウトプロセスほどには
大きな問題になりにくいですが、それでも繰り返し呼ばれるような
オブジェクトの場合には、問題になることがあります。

[高負荷下で ADO を .NET COM interop または Java で使用するとアクセス違反が発生する]
http://bit.ly/KB321415ja
》 COM オブジェクトの使用後、明示的に COM オブジェクトへの参照を解放する。
》 .NET 言語 (Microsoft Visual C# .NET や Microsoft Visual Basic .NET など) では、
》 ReleaseComObject メソッドを使用してオブジェクトへの参照を解放することができます。
引用返信 編集キー/
■83435 / inTopicNo.5)  Re[4]: 3分後に自動シャットダウン
□投稿者/ ざっく (3回)-(2017/03/23(Thu) 15:39:25)
ありがとうございます。

あと、できれば以下の二つについても教えてください。


Dim obj As Object = CreateObject("Shell.Application").Namespace(0).ParseName(filepath)
ddd = TimeSpan.FromSeconds(Int(CDbl(obj.ExtendedProperty("Duration") / 1000 / 10)) / 1000)

というところでもエラーが出るのですが
「Microsoft Shell Controls And Automation」を参照設定した上で、
以下のように書き換えることで、
CreateObject("Shell.Application")のところではエラーが出なくなりました。

Dim ShellObject As New Shell32.Shell

Dim obj As Object = ShellObject.NameSpace(0).ParseName(filepath)

GetDuration4 = TimeSpan.FromSeconds(Int(CDbl(obj.ExtendedProperty("Duration") / 1000 / 10)) / 1000)

しかし、今度はobj.ExtendedPropertyのところでエラーが出てしまいます。


あと、

Dim shell As New Shell32.Shell
Dim wins = shell.Windows
Dim count As Integer = wins.Count

というところでもエラーが出てしまいます。
winsは何で宣言すればうまくいきますでしょうか?


引用返信 編集キー/
■83439 / inTopicNo.6)  Re[5]: 3分後に自動シャットダウン
□投稿者/ 魔界の仮面弁士 (1209回)-(2017/03/23(Thu) 17:00:50)
No83435 (ざっく さん) に返信
> Dim ShellObject As New Shell32.Shell
> Dim obj As Object = ShellObject.NameSpace(0).ParseName(filepath)

(1) 後で ReleaseComObject に渡せるよう、各オブジェクトを変数に取りましょう。

Dim ShellObject As New Shell32.Shell()
Dim oFolder As Shell32.Folder = ShellObject.NameSpace(Shell32.ShellSpecialFolderConstants.ssfDESKTOP)
Dim oItem As Shell32.FolderItem = oFolder.ParseName(filepath)


> ddd = TimeSpan.FromSeconds(Int(CDbl(obj.ExtendedProperty("Duration") / 1000 / 10)) / 1000)
> しかし、今度はobj.ExtendedPropertyのところでエラーが出てしまいます。

(2) ExtendedProperty メソッドは FolderItem2 型のメンバーだからです。

ParseName メソッドの戻り値は FolderItem 型ですが、
FolderItem2 型は FolderItem 型の派生クラスなので、
DirectCast でキャストしてから呼び出せば OK です。

Dim duration As Object = DirectCast(oItem, Shell32.FolderItem2).ExtendedProperty("Duration")


> GetDuration4 = TimeSpan.FromSeconds(Int(CDbl(obj.ExtendedProperty("Duration") / 1000 / 10)) / 1000)

(3) Option Stric On の場合は、Object 型に対する算術演算を行えません。

ゆえにこの場合は、元のコードを生かすのなら
 'GetDuration4 = TimeSpan.FromSeconds(Int(CDbl(duration / 1000 / 10)) / 1000) 'NG
 GetDuration4 = TimeSpan.FromSeconds(Int(CDbl(duration) / 1000 / 10) / 1000) 'OK
のように書き換えることでコンパイルが通るようになります。

しかしながら、ExtendedProperty("Duration") の戻り値は
そもそも「100 ns 単位の時間を表す UInt64 値」ですので、
実際にはもっと単純に、下記のように書けば十分だったりします。

 GetDuration4 = New TimeSpan(CLng(duration))


最後に後始末。

System.Runtime.InteropServices.Marshal.ReleaseComObject(oItem)
System.Runtime.InteropServices.Marshal.ReleaseComObject(oFolder)
System.Runtime.InteropServices.Marshal.ReleaseComObject(ShellObject)
引用返信 編集キー/
■83440 / inTopicNo.7)  Re[5]: 3分後に自動シャットダウン
□投稿者/ 魔界の仮面弁士 (1210回)-(2017/03/23(Thu) 17:27:29)
No83435 (ざっく さん) に返信
> Dim shell As New Shell32.Shell
> Dim wins = shell.Windows
> Dim count As Integer = wins.Count
> winsは何で宣言すればうまくいきますでしょうか?

Windows メソッドの戻り値は Object 型なので、そのまま
 Dim wins As Object = shell.Windows
ということになりますね。

ここを実際の型に合わせたいということであれば、
 Dim wins As SHDocVw.IShellWindows
です。SHDocVw のタイプライブラリを使うための参照設定は
開発環境によって異なるのですが、最近の OS であれば、いずれも
"Microsoft Internet Controls" という名前になっているはずです。

また、これも No83439 の FolderItem → FolderItem2 と同様に、
Object → IShellWindows へのキャストが必要ですね。


とはいえ、そもそも SHDocVw への参照設定も用意してあるのなら
Shell32.Shell の Windows メソッドに頼る必要は無く、最初から
 Dim wins As New SHDocVw.ShellWindows()
だけで事足ります。

元のコードだと、変数 shell と wins の 2 つの COM オブジェクトを使いますが、
これなら 1 つだけで済むので、ReleaseComObject の手間も減らせます。
引用返信 編集キー/
■83441 / inTopicNo.8)  Re[6]: 3分後に自動シャットダウン
□投稿者/ ざっく (4回)-(2017/03/23(Thu) 18:16:21)
ありがとうございます。

winsの子アイテムから
フルパスを取得したいのですが
子アイテムの型はIWebBrowser2で合っていますか?
Dim win As IWebBrowser2 = CType(wins.Item(CObj(i)), IWebBrowser2)

Dim path As String = CStr(win.Document.Folder.Self.Path)
というところで遅延バインディングを使用できない、というエラーが出ますが
ここは何で宣言すれば良いですか?

 
引用返信 編集キー/
■83443 / inTopicNo.9)  Re[7]: 3分後に自動シャットダウン
□投稿者/ 魔界の仮面弁士 (1211回)-(2017/03/23(Thu) 19:40:03)
No83441 (ざっく さん) に返信
> winsの子アイテムから
> フルパスを取得したいのですが

題名「3分後に自動シャットダウン」から随分かけ離れてきましたね…。
関連する内容ではあるのでしょうけど。

ちなみにターゲットのウィンドウハンドルが分かっている場合には、
WM_HTML_GETOBJECT 経由で IWebBrowser2 を得ることも出来ます。
今回は使わない方法だとは思いますが、蛇足までに。


> 子アイテムの型はIWebBrowser2で合っていますか?
> Dim win As IWebBrowser2 = CType(wins.Item(CObj(i)), IWebBrowser2)

列挙されるアイテムは、基本的には IWebBrowser2 型のはずです。
念のため、wins.Item から得たアイテムを Object 型変数に取り出してから
TryCast にて IWebBrowser2 への変換を試みて下さい。

そうして取り出した IWebBrowser2 の実体は、
Internet Explorer の場合もあれば、
Windows Explorer の場合もあります。
(WebBrowser も IWebBrowser2 型を持っていますが、
 これは ShellWindows で列挙されないので今回は除外)

実行環境によっては、IE と Explorer の違いまでも
意識せねばならないケースがありますが、今回は
両者を同じように扱っても問題ないでしょう。


> Dim path As String = CStr(win.Document.Folder.Self.Path)

Document プロパティの戻り値は Object 型になっているのは、
Document プロパティから返されるオブジェクトが、
表示されているコンテンツに左右されるためです。

たとえば、PDF を表示した IE であれば、AcroPDF/AxAcroPDF 等が返されることもありますし、
埋め込み Excel なら Workbook オブジェクトが返されたりもしますし、HTML ページなら
IHTMLDocument2、フォルダーなら IShellFolderView 系統のインターフェイスといった感じで。

しかも表示コンテンツによっては、固有のインターフェイスを持たない
実行時バインド専用のオブジェクトが返されることさえありますので、Document 配下については
 (1) Option Strict Off でダックタイプ的に処理する
 (2) CallByName や リフレクションで呼び出す
 (3) TryCast で固有型へのキャストを試みてから呼び出す
などの方法で対処することを検討してみて下さい。

また、もしも Document の調査が手間なようであれば、IWebBrowser2 の
LocationURL / LocationName プロパティで代用出来るかもしれません。
引用返信 編集キー/
■83444 / inTopicNo.10)  Re[8]: 3分後に自動シャットダウン
□投稿者/ ざっく (1回)-(2017/03/23(Thu) 21:27:58)
出力形式が定まらないものもあるのですね。
非常に勉強になりました
どうもありがとうございました。
 
解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ