SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

Visual C++を使ったカスタムMSBuildタスクの開発

ハードリンクを作成するカスタムのMSBuildタスクを開発する

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

 MSBuildがVisual C++ 2010で導入されたことにより、C++のコンパイルとリンクのプロセスに高度なカスタマイズと拡張の可能性が広がりました。今回は、前回の記事の復習として、カスタムMSBuildタスクをC++/CLIでビルドし、Visual C++ 2010プロジェクトで使用する手順から説明します。

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

はじめに

 MSBuildがVisual C++ 2010で導入されたことにより、C++のコンパイルとリンクのプロセスに高度なカスタマイズと拡張の可能性が広がりました。MSBuildが導入されるまで、ビルドプロセスを拡張するとしたら、ビルドの前後にプロセスを追加する以外に方法はありませんでした。このやり方は柔軟性に乏しく、他のビルドプロセスとの統合も不可能です。これとは対照的にMSBuildを利用する方法では、拡張した機能を正確に調整し、ビルドプロセス全体と統合することができます。新しい形式のVisual C++プロジェクトファイル(vcxproj)は、ビルド中に実行すべき任意のタスクを完了するようにカスタマイズできます。

 前回のVisual C++.NETの使用に関する記事では、MSBuildの基礎知識としてタスクについて学びました。タスクは、ビルドプロセスを作成するための建築ブロックです。タスクは、渡されたアイテムとプロパティをもとにアクションを完了します。タスクはターゲット内にチェーンされ、このターゲットがMSBuildファイルへのエントリポイントとなります。MSBuildとVisual C++には、あらかじめ定義された多数のタスクが付属します。ただし、MSBuildはその目的が拡張性の提供であることから、MSBuildアセンブリに用意されたヘルパークラスを使って、カスタムタスクの開発を非常に簡単に実行できます。前回の記事の復習として、カスタムMSBuildタスクをC++/CLIでビルドし、Visual C++ 2010プロジェクトで使用する手順から説明します。

ハードリンクタスクを作成する

 NTFS(NT File System)にはハードリンクと呼ばれる機能があり、複数のディレクトリエントリを同一のファイルにマップすることができます。ハードリンクには、ファイルを単にコピーした場合と比べて多くの利点があります。最大の利点は、すべてのディレクトリエントリが同一の物理ファイルを指すため、ファイルを更新すると、そのファイルにアクセスするためにどのディレクトリエントリを使ったかに関係なく、ファイルのすべてのコンシューマに更新が自動的に反映されることです。ハードリンクの使用はディスク領域の節約にもなります。同じファイルのコピーがディスクのランダムな場所にいくつも散在することがないからです。

 ハードリンクを作成するタスクはMSBuildに付属しません。また、ハードリンクを作成するマネージドAPIもないため、ハードリンクを作成するカスタムのMSBuildタスクを開発することは、ネイティブとマネージドの世界をシームレスに結び付けるC++/CLIの威力を示す理想的な実習です。

 ハードリンクを作成するWindows SDK関数は、以下のように簡単なものです。

BOOL WINAPI CreateHardLink(
   __in       LPCTSTR lpFileName,
   __in       LPCTSTR lpExistingFileName,
   __reserved LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

 CreateHardLinkを呼び出すときにLPSECURITY_ATTRIBUTESパラメータの値はNULLでなければなりません。したがって、MSBuildカスタムタスクからWindows SDK関数に渡す必要があるパラメータは、リンク元とリンク先のファイル名のみです。この2つのパラメータを指定しないとCreateHardLinkを呼び出せないため、カスタムタスクにこれらの情報を確実に渡す必要があります。カスタムMSBuildタスクでは、省略できないタスクプロパティをRequired属性を使って定義できます。このような要件は、C++/CLIクラスでは次のように定義されます。

public ref class HardLinkTask:
   public Microsoft::Build::Utilities::Task
{
public:
   virtual bool Execute() override;
 
   [Microsoft::Build::Framework::Required]
   property String^ SourceFileName;
 
   [Microsoft::Build::Framework::Required]
   property String^ TargetFileName;
};

 カスタムタスクを作成するプロセスを簡略化するために、Microsoft::Build::Utilities::Task基底クラスを使用します。カスタムタスクの実際の要件はMicrosoft::Build::Framework::ITaskインターフェイスを実装することですが、その場合にはタスクをビルドプロセスに統合するために決まりきったコードを大量に書く必要があります。Microsoft::Build::Utilities::Taskにはこのような標準インターフェイスメソッドが既に実装されているため、カスタムタスクのExecuteメソッドを実装するだけで作業は終了します。Executeは、タスクの実行時にビルドプロセスから呼び出されるメソッドです。Executeから返されるBoolean値は、タスクの実行が成功したか、失敗したかを示します。

 Executeを実装するには、タスクのマネージドSystem::StringプロパティをLPCTSTR変数に変換し、CreateHardLink関数を呼び出す必要があります。また、タスクのエンドユーザーがエラーを診断するために参照できるエラー情報を、MSBuildの標準ログインフラストラクチャを使って記録する必要もあります。このような要件を満たしてExecuteメソッドを実装したのが次のコードです。

using namespace System::Runtime::InteropServices;
using namespace msclr::interop;
 
bool HardLinkTask::Execute()
{
   marshal_context mc;
 
   if (CreateHardLink(
      mc.marshal_as<LPCWSTR>(TargetFileName),
      mc.marshal_as<LPCWSTR>(SourceFileName), NULL)){
         Log->LogMessage(String::Format(
            "Hard link successfully created from {0} to {1}",
            SourceFileName, TargetFileName));
         return true;
   }
   else{
      int errorHresult = Marshal::GetHRForLastWin32Error();
      Exception^ ex = Marshal::GetExceptionForHR(errorHresult);
      Log->LogErrorFromException(ex);
      return false;
   }
}

 C++/CLIマーシャリングライブラリ(以前の記事を参照)を使って文字列を変換し、エラー時にはSystem::Runtime::InteropServices::Marshalを使ってWin32エラーコードを.NET例外に変換します。.NET例外は、エンドユーザーに表示するためMicrosoft::Build::Utilities::Task.Logヘルパーオブジェクトに直接渡すことができます。前記の2つのコードブロックが、カスタムタスクの定義と実装に必要なコードのすべてです。

会員登録無料すると、続きをお読みいただけます

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

次のページ
HardLinkTaskを使用する

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Nick Wienholt(Nick Wienholt)

シドニーに拠点を置く独立系Windowsおよび.NETコンサルタント。著書に『Maximizing .NET Performance』、共著に『A Programmers Introduction to C# 2.0』(いずれもApress刊)。システムレベルソフトウェアアーキテクチャおよび開発を専門とし、パフォーマンス、セキュリティ、相互運用性、およびデバッグに精通。.NETコミュニティに精力的に参加。Sydney Deep .N...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/3823 2009/04/22 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング