印刷用ページ      送信     
クリックして評価とフィードバックをお寄せください
 Windows と C++: タスク スケジューラ 2.0
Related Articles
BizTalk Server 2006 R2 の EDI 機能を紹介し、スキーマの作成、ドキュメントのマッピング、EDI の配信と転送、および例外処理について説明します。

By Mark Beckner (8 月号 2008)
ユーザー エクスペリエンスの構築に完全な自由度を与えることには長短がありますが、多少の芸術的センスがあれば、アプリケーションの使いやすさが向上します。

By Howard Dierking (8 月号 2008)
今月のコラムでは、HTTP クライアントの実装用の新しい強力な API である Windows HTTP サービス (WinHTTP) の使用方法について説明します。

By Kenny Kerr (8 月号 2008)
Jeffrey Richter が AsyncEnumerator クラスのさまざまなすばらしい機能を紹介します。

By Jeffrey Richter (8 月号 2008)
More ...
Articles by this Author
今月のコラムでは、HTTP クライアントの実装用の新しい強力な API である Windows HTTP サービス (WinHTTP) の使用方法について説明します。

By Kenny Kerr (8 月号 2008)
Kenny Kerr は、Visual C++ を現代的かつ便利に使用できるようになる Visual C++ 2008 Feature Pack を絶賛しています。

By Kenny Kerr (6 月 2008)
Kenny Kerr 氏は、Visual C++ を現代的かつ便利に使用できるようになる Visual C++ 2008 Feature Pack を絶賛しています。

By Kenny Kerr (May 2008)
Visual C++ 2008 の新しい Feature Pack を使用すると、現代的なユーザー インターフェイスを構築するための多数の新しい MFC クラスなど、Visual C++ の利便性が向上します。

By Kenny Kerr (April 2008)
Windows Vista と Windows Server 2008 では、より安全で応答性の高いサービスをより簡単に作成できるようにするための大幅な変更がいくつか加えられています。

By Kenny Kerr (Launch 2008)
Kenny Kerr が、タスク ダイアログ、Aero ウィザード、ファイルを開くダイアログなどの、Windows Vista の新しいコントロールの拡張をサポートする Windows Template Library (WTL) について検討します。

By Kenny Kerr (December 2007)
Windows Vista のリリースでは、すばらしい機能を実行する余地が C++ 開発者にも豊富に与えられています。この新しいコラムでは、そのために必要な情報を提供します。

By Kenny Kerr (August 2007)
Cryptography Next Generation (CNG) は、CryptoAPI を今後長期にわたって置き換え、CryptoAPI が提供してきたすべての暗号化プリミティブの代用となることを目的としています。

By Kenny Kerr (July 2007)
More ...
Popular Articles
InfoPath フォームおよび他の Office ドキュメントを使用して、ターゲット アクティビティにデータを渡したり、Office ドキュメントで使用するためのデータを渡すワークフローの作成方法を学習します。

By Rick Spiewak (6 月 2008)
BizTalk Server 2006 R2 の EDI 機能を紹介し、スキーマの作成、ドキュメントのマッピング、EDI の配信と転送、および例外処理について説明します。

By Mark Beckner (8 月号 2008)
Windows Mobile SDK に含まれる Provisioning API のおかげで、数行のコードと XML を使って会社の各モバイル デバイスを設定できるようになりました。その設定方法を説明します。

By Mike Calligaro (April 2008)
この記事では、著者 John Torjo が自作の C++ GUI ライブラリ、eGUI++ のガイドを提供し、ユーザー インターフェイス プログラミングを簡単にする方法を説明しています。

By John Torjo (6 月 2008)
More ...
Read the Blog
Correctly engineered concurrent code must live by an extra set of rules. Reads and writes from memory and access to shared resources need to be regulated so that conflicts do not arise. Additionally, threads often need to coordinate to get the job done. In the October 2008 issue of MSDN Magazine, Joe ...
Read more!
Well designed code keeps things that have to change together as close together in the code as possible and allows unrelated things in the code to change independently, while minimizing duplication in the code. In the October 2008 issue of MSDN Magazine, Jeremy Miller shows you some design ...
Read more!
The process for ink capture and analysis on the Tablet PC is straightforward in managed code. To the uninitiated developer, however, creating unmanaged Tablet PC applications can be rather daunting. In the October 2008 issue of MSDN Magazine, Gus Class a quick introduction to the Tablet PC ...
Read more!
Multicore systems are becoming increasingly prevalent, but the majority of software today will not automatically take advantage of this additional processing ability. And multithreaded programming, for anything but the most trivial of systems, is incredibly difficult and error prone today. In the October 2008 issue of MSDN ...
Read more!
Concurrent programming is notoriously difficult, even for experts. You have all of the correctness and security challenges of sequential programs plus all of the difficulties of parallelism and concurrent access to shared resources. In the October 2008 issue of MSDN Magazine, David Callahan describes ...
Read more!
A major advantage of AJAX and Silverlight applications is that they can transparently and continuously interact with a back-end service. The problem is that they run over HTTP, which wasn't designed with security in mind. In the September 2008 issue of MSDN Magazine, Dino Esposito shows you ...
Read more!
More ...
Windows と C++
タスク スケジューラ 2.0
Kenny Kerr

コードのダウンロード : : WindowsWithC++2007_10.exe (156 KB)
Browse the Code Online
Windows Vista® では、タスク スケジューラが大きく見直されました。類似点もいくつかありますが、Windows® 98 以来使用されてきた元のタスク スケジューラに比べて、新しいタスク スケジューラ (タスク スケジューラ 2.0) ははるかに強力です。単なるエンド ユーザー向けの簡単なツールから、複雑なバックグラウンド操作を設計および管理するための強力なプラットフォームへと進化を遂げました。このため、多くの場合に Windows サービスを開発する必要がなくなります。
たとえば、プロジェクトで更新を自動的に確認する必要があるものとします。この場合、バックグラウンドで稼働して数日ごとに更新を確認するような Windows サービスを記述することが考えられます。ただし、常に実行し続けるサービスの代わりに、数日ごとに実行されて更新を確認した後に停止するようなスケジュール タスクを設計することもできます。さらには、更新を実行するユーザーがいないときにリソースが浪費されないよう、ユーザーがログインしている間にのみ実行されるようにすることもできます。
これからは新しいタスク スケジューラの時代であるとマイクロソフトの開発者たちが考えていることは、Windows Vista のあちこちでバックグラウンド タスクの管理にこれが使用されている事実からも明らかです。副次的効果として、こうしたタスクすべてを処理するために新しく作成しなければならないサービスの数が減少します。また、ブラックボックス的な Windows サービスの目的を解明するよりは、タスクを調べてその動作を確認するほうがはるかに簡単なため、Windows の管理と診断も簡素化されます。Windows 自体の一部を成すタスクにとって、タスク スケジューラはタスク ホストとしても機能します。この場合、タスク固有の多数のプロセスが 1 つに統合されるため、それらの操作をホストするために必要なリソースがさらに減少します。
このすばらしい新サービスに読者が一刻も早く習熟して活用できるよう、このコラムではタスク スケジューラの主要概念と構成要素について説明します。

タスク サービスと記憶域
まず取り上げるのは、タスク スケジューラ サービス、つまりタスクを実際にスケジュールするサービスです。タスク スケジューラではファイル システムを使用してタスク情報を保存するため、このサービスを利用しなくてもタスクの列挙や準備が可能です。しかし、これを利用せずにできることには限りがあります。実際、タスク スケジューラの今後のバージョンでは保存の形式と場所が変更されると予想されるため、現在のそれに依存することはお勧めしません。現時点でも、ファイル システムに直接書き込まれたタスクはタスク スケジューラによって認識されない可能性があるため、また、改ざんされたタスクの実行が拒否される可能性が高いため、記憶域への直接アクセスに依存しないようにすることが重要です。タスク スケジューラは既に Windows Vista の不可欠な一部であり、管理者が単純にこれを無効化することはできなくなりました。つまり、バックグラウンド操作の実行とタスク記憶域の抽出に利用しても安全だということです。これは開発者にとって朗報です。
タスクは原則として、社名、製品名、およびコンポーネント名によってグループ化されます。たとえば、Windows のディスク デフラグ ツールでは、タスクが \Microsoft\Windows\Defrag サブフォルダに保存されます。各タスクは、タスク スケジューラ スキーマで定義された XML ドキュメントとして保存されます。このため、XmlLite などの XML パーサーを使用してタスクを直接作成したり (私の以前の MSDN® Magazine 記事 msdn.microsoft.com/msdnmag/issues/07/04/Xml/ を参照)、タスク スケジューラ API が提供するさまざまな COM インターフェイスを使用したりできます。COM インターフェイスを使用すると、タスクの XML 定義を直接提供したり照会したりもできます。そうすることにより、実際の記憶域にアクセスすることなく、XML を使用してタスクの作成と照会を行うメリットが得られます。タスク スケジューラにはリモートからアクセスすることもできます。

タスク サービスを使用する
ITaskService インターフェイスは、タスク スケジューラ API へのゲートウェイです。必要な定義は、すべて taskschd.h ヘッダー ファイル内にあります。もちろん、Windows Vista に対応した最新の Windows SDK も必要です。まず、次のようにローカルのインプロセス インスタンスを作成します。
CComPtr<ITaskService> service;
HR(service.CoCreateInstance(__uuidof(TaskScheduler)));
(これらのサンプルでは、確認を必要とする HRESULT がメソッドから返される場所を明確に特定するために、HR マクロを使用しています。これを、例外をスローするか HRESULT を返すようなエラー処理に置き換えてもかまいません。)
次に、Connect メソッドを呼び出して、任意のコンピュータ上にあるタスク スケジューラへの接続を確立します。Connect メソッドは次のように定義されています。
HRESULT Connect(
    VARIANT computer, VARIANT user, 
    VARIANT domain, VARIANT password);
VARIANT 型を使用しているのが残念ですが、便利な Active Template Library (ATL) の CComVariant 派生クラスを使用すれば処理は簡単です。ローカル コンピュータに接続するには、コンピュータ名を省略します。呼び出し元の ID または実効トークンを使用して接続するには、ユーザー名の指定を省略します。ローカル コンピュータの現在のドメインを使用するには、ドメイン名の指定を省略します。最後に、ユーザー名を指定した場合はパスワードだけを指定します。よって、ローカル コンピュータのタスク スケジューラ サービスに接続する場合、次のような最も簡単な形式で Connect メソッドを呼び出します。
HR(service->Connect(
    CComVariant(),   // local computer
    CComVariant(),   // current user
    CComVariant(),   // current domain
    CComVariant())); // no password
これで、タスクの作成、既存のフォルダやタスクの列挙など、さまざまな操作を実行できるようになりました。タスクはフォルダに格納しなければ使用できないため、まず ITaskFolder インターフェイスについて説明します。ITaskService の GetFolder メソッドからは、指定したフォルダに対する ITaskFolder インターフェイス ポインタが返されます。次に示すように、バックスラッシュはルート タスク フォルダを表します。
CComPtr<ITaskFolder> folder;
HR(service->GetFolder(CComBSTR(L"\\"), &folder));
次に、アプリケーション用のフォルダを次のように作成できます。
CComPtr<ITaskFolder> newFolder;
HR(folder->CreateFolder(
    CComBSTR(L"Company\\Product"),
    CComVariant(), &newFolder));
CreateFolder に対する 2 つ目のオプション パラメータでは、新しく作成するファイル システム フォルダのセキュリティ記述子を指定します。省略した場合、フォルダには親のセキュリティ記述子が継承されます。セキュリティ記述子定義言語 (SDDL) を使用すると、既定のアクセス制御をオーバーライドできます。たとえば、ローカル システムと管理者とに完全な制御を許可するには、次のような SDDL を使用します。
HR(folder->CreateFolder(
    CComBSTR(L"Company\\Product"),
    CComVariant(L"D:(A;;FA;;;BA)(A;;FA;;;SY)"),
    &newFolder));
簡単に言うと、D: に続くアクセス制御エントリ (ACE) は、随意アクセス制御リスト (DACL) の一部となります。最初のエントリは、すべてのファイル (FA) へのアクセス許可 (A) が組み込みの管理者 (BA) に対して付与されることを意味します。2 番目のエントリは、同様のアクセス許可がローカル システム (SY) に対して付与されることを意味します。このセキュリティ記述子定義が使用されるのは、Product フォルダの作成時のみです。親の Company フォルダは、継承されたセキュリティ記述子を使用して作成されます。なお、Local System アカウントに対してアクセスを拒否しないようにしてください。この ID はタスク スケジューラ サービスによって使用されます。スケジュール対象のタスクにタスク スケジューラがアクセスできないと、予期しない動作が発生します。
フォルダが存在するようになったら、ITaskService の GetFolder メソッドを使用して、ルート タスク フォルダから相対指定したフォルダを開くことができます。ITaskFolder の同じメソッドを次のように使用すると、インターフェイス インスタンスによって表されるフォルダから相対指定したフォルダを開くことができます。
CComPtr<ITaskFolder> productFolder;
HR(service->GetFolder(
    CComBSTR(L"Company\\Product"),
    &productFolder));

CComPtr<ITaskFolder> componentFolder;
HR(productFolder->GetFolder(
    CComBSTR(L"Component"),
    &componentFolder));
このコラムのダウンロードに含まれている、タスク スケジューラ エクスプローラのサンプル アプリケーションを、図 1 に示します。これによってタスクを概観でき、タスク スケジューラ API を使い始める際に役立ちます。
図 1 タスク スケジューラ エクスプローラ (画像を拡大するには、ここをクリックします)

タスク定義
タスクを作成するには、まず、タスク定義でタスクをモデル化する必要があります。タスク定義を構成するコンポーネントについて、図 2 で説明します。タスク定義は複雑であるうえ、タスク作成において必要とされるため、すぐにタスク作成に取りかかることはお勧めしません。基本的な構成要素について前もって理解しておくと役立ちます。アクションとトリガの定義の詳細を検討する前に、タスク定義の作成方法について簡単に説明します。
最初に、タスク スケジューラ サービスを使用して、設定に使用する空のタスク定義を作成します。
CComPtr<ITaskDefinition> definition;
HR(service->NewTask(0, // reserved
                    &definition));
タスク定義を特定のフォルダに登録する前に、少なくともアクションを 1 つ設定する必要があります。オプションで、トリガやその他の情報を設定することもできます。準備ができたら、RegisterTaskDefinition メソッドを次のように使用して、フォルダに登録します。
CComPtr<IRegisteredTask> registeredTask;
HR(folder->RegisterTaskDefinition(
    CComBSTR(L"Task"),
    definition,
    TASK_CREATE_OR_UPDATE,
    CComVariant(), // user name
    CComVariant(), // password
    TASK_LOGON_INTERACTIVE_TOKEN,
    CComVariant(), // sddl
    &registeredTask));
新しく登録されたタスクを表す IRegisteredTask インターフェイス ポインタが返されます。このインターフェイスを使用して、タスクの開始や停止のほか、タスクに関するランタイム情報の取得も行います。
RegisterTaskDefinition の最初のパラメータでは、新しいタスクの名前を指定します。この値は、フォルダに保存されるファイルの名前としても使用されるため、ファイル システムの名前付け規則に準拠する必要があります。このパラメータを NULL に設定すると、メソッドによって GUID が生成され、名前として使用されます。しかしこれは、コンピュータの管理者にとってわかりやすいとは言えないため、お勧めしません。2 番目のパラメータでは、作成するタスクを記述するタスク定義を指定します。これについては、以下のセクションで詳しく説明します。3 番目のパラメータでは、TASK_CREATION 列挙からの値を指定します。よく使用される値は、TASK_CREATE および TASK_UPDATE です。TASK_CREATE_OR_UPDATE は、これら 2 つのビット単位の OR です。
続く 3 つのパラメータでは、登録資格情報を指定します。RegisterTaskDefinition を使用すると、後続のパラメータで指定する DACL で明示的に付与しなくても、登録するタスクの少なくとも読み取りアクセス権が、指定したユーザーに必ず付与されます。タスク スケジューラは、何種類ものログオン方法をサポートしています。上の例で使用している TASK_LOGON_INTERACTIVE_TOKEN は、指定したユーザーの対話型ログオン セッションでのみタスクが実行されることを示します。ユーザー名とパスワードを指定しない場合、呼び出し元の ID が使用されます。対話型ログオン セッションを必要とするため、パスワードは保存されません。
代わりに TASK_LOGON_PASSWORD を使用すると、タスク用のバッチ ログオン セッションを作成するようタスク スケジューラに指示できます。この場合、ユーザー名とパスワードの両方を指定し、アカウントには "バッチ ジョブとしてログオン" 権限を付与する必要があります。
さらに安全性の高いオプションとして、TASK_LOGON_S4U があります。S4U (service for user) ログオンを利用し、指定したユーザーに代わってタスクを実行しますが、パスワードの保存は不要です。ローカル システム アカウント内でタスク スケジューラが実行されるため、S4U ログオン セッションを作成し、ID として使用されるだけでなくローカル コンピュータにおける偽装にも使用されるトークンを受け取ることができます。通常、S4U トークンは ID としてのみ有効です。
タスクには、登録時に指定した資格情報に加え、セキュリティ コンテキストに対する制御が IPrincipal インターフェイスによってさらに提供されます。具体的に言うと、IPrincipal は、タスク スケジューラ エンジンをホストするプロセスの実行レベルを、タスクに合わせて制御するための便利な方法です。まず、関連付けられたプリンシパル オブジェクトのタスク定義を照会した後、RunLevel プロパティを必要に応じて設定します。これは、タスク定義の登録前に行う必要があります。次に例を示します。
CComPtr<IPrincipal> principal;
HR(definition->get_Principal(&principal));
HR(principal->put_RunLevel(TASK_RUNLEVEL_HIGHEST));
TASK_RUNLEVEL_HIGHEST は、そのユーザーにとって最も制約が緩いセキュリティ コンテキストでタスクを実行することを表します。ユーザーが管理者である場合、ユーザー アカウント制御 (UAC) の制約を受けないトークンがプロセスに与えられます。代わりに TASK_RUNLEVEL_LUA を使用すると、制限された (昇格されない) トークンが与えられます。

タスク アクション
タスク スケジューラ .NET
タスク スケジューラ用の Microsoft® .NET Framework ラッパーはありませんが、共通言語ランタイム (CLR) のランタイム呼び出し可能ラッパー (RCW) 機能のおかげで、ラッパーを使用することは難しくありません。
タスク スケジューラには、スクリプト作成に役立つ COM インターフェイスが用意されているため、API をマネージ コードから簡単に使用できます。Visual Studio® の [参照の追加] ダイアログ ボックスを使用して、タイプ ライブラリを参照するだけです。わかりにくいのですが、タスク スケジューラ 2.0 のタイプ ライブラリには、TaskScheduler1.1 タイプ ライブラリという名前が付いています。ともあれ、Visual Studio によって作成される相互運用アセンブリが、すべてのマネージ定義を COM インターフェイスに提供します。このため、RCW を使用することにより、マネージ コードで直接、さまざまな COM オブジェクトを構築および参照できます。
このコラムの最初のセクションで使用したコード サンプルに相当する、C# の例を次に示します。タスク スケジューラ サービスに接続し、製品のタスク用にフォルダを作成するコードです。
ITaskService service = new TaskSchedulerClass();
service.Connect(null, // local computer
                null, // current user
                null, // current domain
                null); // no password

ITaskFolder folder = service.GetFolder("\\");
ITaskFolder newFolder = folder.CreateFolder(
    "Company\\Product", "D:(A;;FA;;;BA)(A;;FA;;;SY)");
この後も、.NET Framework を対象とする好みの言語を利用して、タスク定義、アクション、トリガなどの作成に進むことができます。

基礎的な説明が済んだので、タスク スケジューラに用意されているさまざまなアクションの種類を見てみましょう。アクションの作成とタスク定義への追加には、タスク定義の Actions プロパティから返される IActionCollection インターフェイス ポインタを使用します。
CComPtr<ITaskDefinition> definition;
HR(service->NewTask(0, // reserved
                    &definition));

CComPtr<IActionCollection> actions;
HR(definition->get_Actions(&actions));
IActionCollection が提供する Create メソッドは、新しいアクション オブジェクトを作成してコレクションに追加します。アクション自体は、IAction から派生するインターフェイスを通じて公開されます。次に例を示します。
CComPtr<IAction> action;
HR(actions->Create(TASK_ACTION_EXEC, &action));
TASK_ACTION_EXEC は、コマンドライン操作を記述し、あらゆるプログラムの起動に使用できるため、最もよく使用される種類のアクションです。Windows シェルに登録されたドキュメントやその他の種類のファイルを起動することもできます。アクション固有のプロパティを設定するには、まず、その種類に固有のインターフェイスを照会する必要があります。CComQIPtr は、この動作だけをうまくやってのけます。
CComQIPtr<IExecAction> execAction(action);
IExecAction インターフェイス ポインタを取得したら、任意のコマンドを実行するアクションを構成できます。次の例では、仮想ハード ドライブ イメージを最適化する Sysinternals Contig ツールを起動します。
HR(execAction->put_Path(CComBSTR(L"g:\\Tools\\contig.exe")));
HR(execAction->put_Arguments(CComBSTR(L"-s g:\\VirtualMachines")));
コマンドの実行は、管理者にとっては便利ですが、開発者にとって最適な解決策であるとは限りません。コマンドは、タスク内でどのようなアクションを意味するのかを認識しないばかりか、スケジュールされたタスクの一部であることすら関知しないからです。さいわい、タスク スケジューラには、まさにこの問題に対処するために設計された、別の種類のアクションが用意されています。そのアクションの種類 TASK_ACTION_COM_HANDLER は、COM サーバーを作成し、実装が必要な ITaskHandler インターフェイスをこのサーバー上で照会します。このため、アクションとタスク スケジューラ エンジンの間に通信チャネルが確立され、アプリケーション固有の操作がより明快にタスク スケジューラに統合されます。
COM アクションの作成方法を次に示します。
CComPtr<IAction> action;
HR(actions->Create(TASK_ACTION_COM_HANDLER, &action));

CComQIPtr<IComHandlerAction> comAction(action);
HR(comAction->put_ClassId(CComBSTR(
    L"{25C6DB11-4ADC-4e89-BA47-04576C7AA46A}")));
もちろん、指定したクラス識別子 (CLSID) で登録され ITaskHandler インターフェイスを実装する COM サーバーが必要です。図 3 に、COM クラスで ATL を利用して ITaskHandler を実装する例を示します。
もう 1 つ、追加の手順を実行する必要があります。これを執筆している時点ではどのドキュメントにも記載されていませんが、この手順を実行しないと COM アクションの読み込みに失敗します。タスク スケジューラ エンジンは、CoCreateInstance 関数に CLSID を指定して呼び出す際、CLSCTX_LOCAL_SERVER コンテキストを使用して COM サーバーを別個のプロセスに読み込もうとします (ただし、アクションが Windows 自体の一部である場合は、インプロセスで読み込まれることがあります)。これを成功させるには、代理プロセスでのアクティブ化を許可するよう COM サーバーを構成する必要があります。技術的には、従来のアウトプロセス コンポーネントを使用することもできますが、この方法は、多くの場合、一般的でも実際的でもありません。これを簡単に解決するには、登録のコードを更新します。ATL 登録を更新して DllSurrogate 値を含めます。次に例を示します。
HKCR
{
    NoRemove AppID
    {
        '%APPID%' = s 'SampleTask'
        {
            val DllSurrogate = s ''
        }
        'SampleTask.DLL'
        {
            val AppID = s '%APPID%'
        }
    }
}
COM アクションは、いくつもの点で、他の種類のアクションよりも優れています。特に、正常かつ予測可能な方法でアクションを停止できるのは、COM アクションだけです。COM クラスのインスタンスを作成した後、タスク スケジューラ エンジンは Start メソッドを呼び出し、タスク スケジューラとの通信に使用できるインターフェイス ポインタを提供します。次に Start メソッドで ITaskHandlerStatus インターフェイスを照会できます。これにより、タスクの進捗状況と最終的な完了をタスク スケジューラに通知する簡単なメカニズムが実現します。アクションが終了する方法は 2 つあります。結果として COM クラスの Stop メソッドが呼び出されるようなさまざまなメソッドを使用して、ユーザーがタスクを終了する場合があります。また、ITaskHandlerStatus の TaskCompleted メソッドを呼び出すことによって、COM クラスが処理の完了を報告する場合もあります。
タスクから電子メール メッセージを送信するための、便利なアクションの種類も用意されています。これまでに説明したアクションの種類とは異なり、操作や管理タスクの実行にはそれほど役立ちませんが、通知メカニズムとしての使用に最適です。次のセクションでトリガについて解説しますが、今のところは、従来のカレンダーベースや時間ベースのトリガ以外に、イベントによってもタスクの開始が可能であるとだけ申し上げておきましょう。電子メール アクションの作成方法を次に示します。
CComPtr<IAction> action;
HR(actions->Create(TASK_ACTION_SEND_EMAIL, &action));

CComQIPtr<IEmailAction> emailAction(action);
HR(emailAction->put_From(CComBSTR(L"kenny@example.com")));
HR(emailAction->put_To(CComBSTR(L"karin@example.com")));
HR(emailAction->put_Subject(CComBSTR(L"subject")));
HR(emailAction->put_Body(CComBSTR(L"body")));
HR(emailAction->put_Server(CComBSTR(L"mail.example.com")));

タスク トリガ
タスク スケジューラには、ユーザー操作なしにタスクを開始できる、さまざまなトリガが用意されています。通常の時間ベースやカレンダーベースのトリガのほか、便利なイベントベースのトリガがいくつもあります。
タスクの作成とタスク定義への追加には、タスク定義の Triggers プロパティから返される ITriggerCollection インターフェイス ポインタを使用します。
CComPtr<ITriggerCollection> triggers;
HR(definition->get_Triggers(&triggers));
ITriggerCollection が提供する Create メソッドは、新しいトリガ オブジェクトを作成してコレクションに追加します。トリガ自体は、ITrigger から派生するインターフェイスを通じて公開されます。前のセクションの例で、最適化操作を開始するトリガの例を次に示します。
CComPtr<ITrigger> trigger;
HR(triggers->Create(TASK_TRIGGER_WEEKLY, &trigger));

CComQIPtr<IWeeklyTrigger> weeklyTrigger(trigger);
HR(weeklyTrigger->put_StartBoundary(CComBSTR(
    L"2007-01-01T02:00:00-08:00")));
HR(weeklyTrigger->put_DaysOfWeek(0x01)) // Sunday
新しいタスク スケジューラの初期リリースでは、TASK_TRIGGER_WEEKLY を含む 11 種類のトリガを使用できます。使用可能なトリガの種類と、それぞれに関連付けられた COM インターフェイスを、図 4 にまとめて示します。StartBoundary プロパティは、タスクがトリガされる最も早い日付と、タスクが開始される時刻を表します。DaysOfWeek プロパティは、タスクを実行する曜日を表します。ビットマスクを使用して、任意の曜日を組み合わせることができます。上の例のトリガでは、2007 年の元日以降、毎週日曜日の午前 2 時 (太平洋標準時) にタスクが実行されます。

次のステップ
Windows Vista 以降、新しいタスク スケジューラには、使用せずにいられない理由が数多くあります。Windows の以前のバージョンでタスク スケジューラを使用していた読者は、間違いなくすべての新機能に満足することでしょう。実際、今日のアプリケーション用に記述された多くのカスタムビルドのスケジューラが、間もなくタスク スケジューラに置き換わるものと予想されます。
タスク スケジューラの機能のすべてについては、このコラムで扱いきれませんでした。ぜひ、Windows SDK (msdn2.microsoft.com/en-us/library/aa383614.aspx) のドキュメントも参照してください。XML を直接使用するタスク作成、タスクが実行されるセキュリティ コンテキストに対する制御の強化、実行中のタスクの列挙と管理など、その他の機能について情報を得ることができます。

ご質問は、

Kenny mmwincpp.

まで英語でお送りください。
Kenny Kerr は、Windows のソフトウェア開発を専門にしているソフトウェア設計者です。彼はプログラミングおよびソフトウェア設計に関して執筆を行い、開発者を指導しています。連絡先は weblogs.asp.net/kennykerr です。

© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; reproduction in part or in whole without permission is prohibited.
Page view tracker