人気ブログランキング | 話題のタグを見る
(.Net).Netアプリケーションから Windows タスクスケジューラを操作する
(SQL Server 2005) Express Edition は SQL Agent job スケジューリングサービス がない!?で書いたように Express Edition はエージェントサービスがないため、自動バックアップするためにアプリ側から Windows のタスクスケジューラにバックアップ処理を登録して行おうと考えました。

これが想像以上に悪戦苦闘しました。単に.Netアプリケーションからタスクを登録したいだけなのに。。。

今回の要件はこんな感じです。
・プログラム側からタスクの登録、削除、一覧取得ができる。
・Windows 2000(Client),Windows Server 2003(Server)以上で動くこと。(もちろんXPのHomeEditionでも)

まず、Windows タスクスケジューラにタスクを登録する方法はいくつかあるようです。
1.GUIから操作する
XPだとコンパネのタスク,Vistaだと管理ツールのタスクスケジューラから操作する方法です。今回の要件はアプリケーション側から操作するの却下。

2.at.exe コマンドを使う
Windows NT 時代からある古いコマンドです。ただこれは互換性のためだけに残されているコマンドで非常に使い勝手が悪いです。@IT タスク・スケジューラをコマンド・プロンプトから制御するでも「Windows XP以降のOSでは、at.exeは利用せず、必ずこちらを利用するべきである」とあるので、却下。(一応 Vista でも at コマンド存在してました。)

3.schtasks.exe コマンドを使う
このコマンドラインタスク管理ツールを使うとかなり柔軟にできるのでいいんですが、一つ問題が。。XP以降でしか使えないことです。さらにXPでも Home Editon はこのコマンドが存在しません。なんでって感じですがこの方法も惜しみながら却下。

4.WMI で Win32_ScheduledJob クラスを使う
この Win32_ScheduledJob は at.exe 使っており、結局2.と同じなので却下。
WMIでタスク管理する方法はTechNet:スクリプトを使用してタスクのスケジュールを管理することはできますか参照。

5.Win32 API NetScheduleJob系 を使う
一応 API で NetScheduleJobAdd , NetScheduleJobDel , NetScheduleJobEnum , NetScheduleJobGetInfo が用意されてるみたいですが、これも少し調べてみるとあんまり使い勝手良くないみたいですね。というよりこれが at.exe や Win32_ScheduledJob のコアになってるんじゃないでしょうか?(詳しく調査してないんで分かりませんが。。) ま、そういうわけで却下。

6.COM ITaskSchedulerを使う
ITaskScheduler を使うと大抵のことはできそうな感じです。今回の要件も満たせるので結局この方法で行くことにしました。しかし、COMがよくわかってない故に苦戦しました。。

ちなみに Vista 以降はタスクスケジューラのバージョンが2.0になったためより COM も ITaskScheduler ではなく ITaskService を使って操作するスタイルになったようです。(
また、WMI でも Schedule.Service たるクラスが用意されてスクリプトで簡単にタスク操作できるようになってるっぽいですね。
Vista でスクリプトからタスク操作する方法はTechNet Windows Vista でスケジュールされたタスクを実行する方法はありますかを参照。)


まず参考にさせていただいたのは@IT BBS【C#】C#アプリからによるタスク登録の自動化についてです。


どうやらタスクスケジューラ操作関連の COM は C:\Windows\System32\mstask.dll に格納されてるっぽいです。

さて、実は不肖ながら3流PGは COM 技術についてほとんど無知です。
概念はちょこっとはかじってますが、いざ COM を作ったり使うことはほとんどしたことがありません。

ただ以前 DirectShow を.Netから使うときに COM の ActiveMovieControl を参照設定から利用したときはありました。(ActiveMovieControlでDirectShow。)

で、今回も試しに ActiveMovieControl の時と同じ手法(参照の追加でCOMタブ)でCOMを使おうとしましたが、一覧に出てきません。
まさに、上記 @IT BBS の質問者の状態です。

まず、この点(つまり .Net からどうすれば COM が見えるのか)を調べてみました。
参考にしたのは、DirectShowの時も読んだMSDN:第 7 章 「相互運用パフォーマンスの向上」 と、MSDN:COM 相互運用性 - 第 1 部 : C# クライアント チュートリアルです。

ActiveMovieControl を使った時は、Visual Studio で参照設定すれば勝手に Interop.QuartzTypeLib.dll という DLL ができて、これを操作すれば COM 簡単に扱えました。
COM にはタイプライブラリというインターフェイスの定義を格納したものがあるらしく、Visual Studio はこのタイプライブラリを指定すると自動的に.NET Framework メタデータに変換し、どのマネージ言語からでも呼び出すことができるマネージ ラッパーを作成してくれるようです。
この マネージラッパーは Visual Studio を使わなくても NET の SDK に付属する TlbImp.exe (C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\TlbImp.exe) を使っても作成できるようです。
試しに ActiveMovieControl のDLL(c:\Windows\System32\quartz.dll) を TlbImp を使ってマネージラッパーに変換してみました。

C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin>TlbImp.exe c:\Windows\System32\quartz.dll
Microsoft (R) .NET Framework Type Library to Assembly Converter 3.5.30729.1
Copyright (C) Microsoft Corporation. All rights reserved.

Type library imported to QuartzTypeLib.dll

これで QuartzTypeLib.dll が生成されました。

ところが、どの COM もタイプライブラリを持っているというわけではないようです。
上記の "MSDN:COM 相互運用性 - 第 1 部 " によると、「COM 定義を C# に変換する方法としては TlbImp が適していますが、常に TlbImp を使用できるわけではありません。たとえば、COM 定義の typelib が存在しない場合や、TlbImp が typelib の定義を処理できない場合は TlbImp を使用できません。このような場合には、C# 属性を使用して C# ソース コード内で COM 定義を手動で定義します。C# ソース マップを作成すると、C# ソース コードをコンパイルするだけでマネージ ラッパーを生成できます。」とありますしね。

で、今回の使う予定の ITaskScheduler の COM はタイプライブラリを持っていません。(タスクスケジューラ2.0以降(Vista以降)では、タスク操作のCOMへのタイプライブラリが提供されてるみたいです。Visual Studio の参照追加でも「TaskScheduler1.1 タイプ ライブラリ」と出てきます。詳しくはMSDNマガジン:タスク スケジューラ 2.0。これ使えば簡単なんでしょうが、なぜXP以前にはないのか。。。)
つまり、タイプライブラリが本来持っているインターフェイスを自身で定義してやらないといけないわけです。そして、便利なマネージラッパークラスももちろん作ってくれません。


話はそれますが、COM自体について。。
COM はインタフェースを介して、呼び出し元プログラムと通信を行うようです。
あんま理解してませんが、詳しくはCOMの基礎がや@IT:COM+に見る分散オブジェクトの特徴 分かりやすいです。
また、まだ最初しか読んでませんが、MSDN:COM プログラミングの基本 (上),COM プログラミングの基本 (中),COM プログラミングの基本 (下)も参考になりそうです。
で、COM は クラスID、インターフェイスID が決まっていて(中身はGUID)、たいていレジストリに GUID に対応する DLL へのパスが格納されてるみたいですね。(GUID から実際のファイルパスへの解決は API レベル(例えば CoCreateInstance() 等)でやってるくれるみたいなので開発者は意識しなくてよいようです。)
そういえば、レジストリにクラスIDみたいなものあったなーと思い見てみました。
例えば今回使うタスクスケジューラのCOMが入っている mstask.dll はレジストリ上は下記の場所に定義されてました。
HKEY_CLASSES_ROOT\CLSID\{148BD52A-A2AB-11CE-B11F-00AA00530503}\InProcServer32


さて、そろそろ本題復帰。

参考にしている@IT BBS【C#】C#アプリからによるタスク登録の自動化についてで、ありがいたいことにタスクを登録する C# のコードが紹介されてました。


今回のプロジェクトは VB.Net だったので上で紹介されたコードを VB.Net に変換してみました。

(.Net).Netアプリケーションから Windows タスクスケジューラを操作する(@IT参考コード編)にコードはあげています。

ただ、タスク登録だけしかできません。なぜなら、インターフェイスのメソッドの最低限の登録以外はすべてダミーメソッドだからです。
ということは、残りのメソッドやインターフェイスの定義を書かないといけません。

定義自体は探せば結構あるんですよね。
1つはMSDN:Task Scheduler 1.0 Interfacesはインターフェイスの定義+リファレンスが載ってます。ただし、英語だけで日本語の情報はないようで。。。
また、@IT であったPINVOKE.NETでもITaskSchedulerのインターフェイスは載せられてました。(このサイトはWin32 APIやアンマネージAPIをマネージコードから呼び出すためのPInvokeの記述を探すことのできるサイトとして、結構有名らしいです。知りませんでした。。)
さらに、Visual C/C++開発環境か Windows SDK 入ってると mstask.dll のヘッダファイル "MSTask.h"(パスは自分の環境だとC:\Program Files\Microsoft SDKs\Windows\v6.0A\Include)でもインターフェイスの定義分かります。ただ、量が多いし、C/C++になれないと大変。。

今回の要件を満たすためのコードを書くだけでも結構な数の定義を書かないといけません。
時間もないし、メソッドの引数の型変換のマーシャリングや.Netでの属性がいまいちわかってないので自力はなかばあきらめモードに...

てなわけで他力本願全開でググっているとこのような記事見つけました。
Windowsのタスクスケジューラをプログラムから設定する。この追記部分のリンク先のページから "Download demo project" でタスクスケジューラ操作用ライブラリがダウンロードできました。
しかし、言語が C++ && 英語(コメントがね)。今回は使えませんが、C++ やるときにはいいかもしれません。


さらにいろいろググってるついに見つけました。

番外編入れると12回という長期連載の ITaskScheduler もろもろ実装方法の記事です。
COM クライアント実装の道程 for TaskScheduler その1
COM クライアント実装の道程 for TaskScheduler その2
COM クライアント実装の道程 for TaskScheduler その番外編1 ~アンマネージドメモリへの手抜き
アンマネージドメモリへの手抜き VB.NET編
COM クライアント実装の道程 for TaskScheduler その3
COM クライアント実装の道程 for TaskScheduler その4
COM クライアント実装の道程 for TaskScheduler その番外編2 ~ COM オブジェクトと GC とファイナライザ
COM クライアント実装の道程 for TaskScheduler その5
COM クライアント実装の道程 for TaskScheduler その6
COM クライアント実装の道程 for TaskScheduler その7
COM クライアント実装の道程 for TaskScheduler その8
COM クライアント実装の道程 for TaskScheduler その最終回
かなり長いですが、読むとなるほどというところが多いですね。
最終回ではタスク操作をライブラリ化して VS プロジェクトまで公開しているので、非常に助かります。
最初からのこの記事みつけとば半日苦労せずにすみました。。。

余談ですが、タスクスケジューラで登録したタスクって、%sytemroot%¥Tasks フォルダにファイルとして登録されるんですね。
恥ずかしながら知りませんでした。。
by jehoshaphat | 2009-04-28 23:45 | .Net開発


<< (.Net).Netアプリケー... (SQL Server 200... >>