kazuk は null に触れてしまった

C# / .NET 系技術ネタ縛りでお送りしております

月別アーカイブ: 3月 2013

Windows 8 & RT でのサイドローディング


年末年始辺りから調べ初めて、一応これで確定かなと思える段階になりましたので記事おば。

サイドローディングって何ですか?

一般的に Windows 8 / RT ではアプリケーションはマイクロソフトの運営する Windows アプリストアから入手するようになっています。( Windows 8 のデスクトップ環境はこの限りではありません)

Windows アプリストアは全世界に向けて公開されている物なので、企業内利用を前提とするアプリケーション(いわゆるインハウスアプリケーション)の配布と展開には向きません。特に企業秘密なロジックやその他が外部に漏れないように管理したいという場合には向きません。

これにたいする回答がサイドローディングという事になり、Windowsアプリストアを経由せずにアプリケーションをインストールする事ができます。

サイドローディングが可能なクライアントOS

Windows 8 の場合には家庭向けの位置づけがされている無印エディションのみサイドローディングができません。

Windows 8 Enterprise の場合にはドメイン参加時点でサイドローディングが可能になります。

Windows 8 Pro ではOSに追加で Sideloading Activation Key を入手、インストールする事により Sideloading が可能になります。(ただし 一般の Retail 版 Windows Pro ではできません、ボリュームライセンスプログラムによって入手されたWindows 8 Pro が必要という事です。 参考情報1 )

Windows RT は Pro と同様に Sideloading Activation Key を入手、インストールする必要があります。

Sideloading Activation Key の入手

以下のいずれかのライセンスプログラムに加入していれば、ライセンスプログラムの特典として無償入手が可能です。

  • Select / Select Plus による Windows ソフトウェアアシュアランス
  • Windows を含む Enterprise Agreement / Enterprise Subscription Agreement
  • 教育組織では Windows を含む Enrollment of Education Solutions ないしは Campas/School Agreement

上記ライセンスプログラムに加入していない場合には、 Select / Select Plus から購入する事ができます。

製品名 「WinSdLdH 8 … 100Lic EntSideload」 …部にはライセンスプログラム固有なワードが入ります。

WinSdLdH EntSideload の Bing 検索結果

会社として付き合いのあるオープンライセンスのリセラーにこれで問い合わせれば見積もりくれるでしょうし、売ってくれるはずです。

最低でも 100 ライセンスのパックですので、数台の物にインストールするのは結構割に合わないと思います。

Side Loading Activation Key はマシン単位です、1ライセンスは1台にインストールでき、マシンと完全に結び付けされますので、マシンを廃棄その他した場合には消尽する物と考えてください。

ポリシーによるサイドローディングの許可

グループポリシーの「信頼できるすべてのアプリのインストールを許可する」を有効にします。

Sidelading Activation Key のインストール

コマンドロンプトで管理者権限で Slmgr を実行します。

image

/ipk オプションで Sideloading Activation Key の 25桁のプロダクトキーを入力してください。

サイドローディングアプリケーションの展開

手動インストールを行う場合 add-appxpackage PoweShell コマンドレットを使います。

Windows インストールイメージに付属させてアプリケーションを展開するには DISM コマンドの /Add-ProvisionedAppxPackage オプションを使うか、Add-AppxProvisionedPackage PoweShell コマンドレットを使います。

System Centerその他、Windows でアプリケーション展開を行う為の各種システムがサイドローディングに対応しているようです。(そちらは私は調べていません。)

サイドローディングされるアプリケーションの開発

サイドローディングされるアプリケーションは適切な署名がされている必要があります。(以下は自己署名証明書を利用する例です、企業レベルでCAを持っている場合、そのCAで証明書を発行する事が望ましいです)

コードサインニング証明書を作成します /eku オプションの 1.3.6.1.5.5.7.3.3 がコードサインニング証明書を生成する事の指定になっており 1.3.6.1.4.1.311.10.3.13 で証明書が無効になってもコードサインニング署名を有効にするためのオプションです。(これを指定していないと証明書が期限切れで無効になった時にアプリケーションを再署名する必要があります)

C:\Users\kazuk>MakeCert /n “CN=Kazuk” /r /h 0 /eku “1.3.6.1.5.5.7.3.3,1.3.6.1.4.1.311.10.3.13” /e “08/01/2013” /sv MyKey.pvk MyKey.cer
Succeeded

数回パスワードをどう設定するか聞いてきますのでパスワードを設定すると Succeeded 表示されファイルが作成されます。

Pvk2Pfx ユーティリティで pfx ファイルを作成します。

C:\Users\kazuk>Pvk2Pfx /pvk MyKey.pvk /pi 検閲削除 /spc MyKey.cer /pfx MyKey.pfx

/pi のパラメータは 証明書のパスワードです。 /po オプションで pfx を利用する際のパスワードを設定できます。

作成された MyKey.cer は展開されるマシンの証明書ストアに配置する必要があり、pfx はアプリケーションの開発に必要になりますので、pvk 含めてちゃんと保存、管理してください。

開発者はプロジェクトに pfx を配置するか証明書ストアに pfxをインポートします。

imageimage

ファイルを選択すると証明書のパスワードを要求されるので、これを入力すると署名が設定されます。

完全な証明書の表示を行うと、MakeCert 時に設定した日付までになっていますので、正しく署名がされる事が確認できます。

cer ファイルを展開先マシンの「信頼される発行元」の証明書ストアに登録する事で、このpfxで署名されたアプリケーションは展開先で信頼されます。(今回は自己署名証明書のため、ルート証明機関にも登録する必要があります)

サイドローディングされるアプリケーションで、Windows Runtime に存在しないAPIを利用する

ポータブルクラスライブラリでインターフェースを宣言し、それを実装する通常のクラスライブラリを作成してMEFでロードすればいけます。これを使うとLOBアプリケーションで SQL Server 等のRDBMSを利用する事も普通にできます。

 

参考情報

1. sideloading product activation key + Windows 8 : MSDN Forum

その他 MSDN や TechNet 見ろ

まとめ

個人事業主としてサイドローディングされるLOBアプリケーションの受注開発、ないしは開発プロジェクトに対しての技術支援等行っておりますので、ご相談ください。

Visual Studio で kindle 本をビルドする


ネタ的には msbuild と Visual Studio のカスタマイズネタでございます。

Kindle 本のソース

Kindle 本を書く上でのソースは、html と pdf, word 文書等が選べるようです。

細かい事はこっちを参照 Amazon.com: Kindle Direct Publishing: HelpType of Formats

んで、今回は Visual Studio の ASP.NET Web Application の csproj を魔改造して html から mobi 形式で kindle 本をビルドするという形にします。プロジェクトのドキュメントとか、ソリューション内に kindle 本のプロジェクト置けば電子書籍化できるという誰得な物ですね。

というわけで ASP.NET Web Application のプロジェクトを作ります。 MsBuildBook とか付けてますけど、こんな本が Amazon の Kindle ショップに並んでるはずがないよね!

目次を index.html として作ります。

imageimage

この目次はあくまでもコンテンツです、本の中身の目次だと思っても良いでしょう。そういう意味で好き勝手な事を書いて良いです。

目次情報ファイル ncx と opf の作成

とりあえず将来的には T4 とか msbuild カスタムタスクで吐かせるつもりでも一端手書きで書いておきます。

opf も書いておきましょう。

imageimage

ビルドツールの入手

Download KindleGen 2.8 から kindlegen を入手します。プロジェクト内に buildTools フォルダを作り exe を配置しました。

とりあえず opf を叩くとビルドされます。おめでとう。

ビルドされた mobi を kindle の doucments 以下に USB 接続で送り込むと実際に表示を確認する事ができます。

image  IMG_0040IMG_0041

表紙と目次をそれぞれ表示した所、ちゃんと表示できてますね。

目的は自動化だ!(いや、それ手段ですし

さて、手順は解ったという事で自動化していきましょう。

まず、 build そのものをプロジェクトのビルドでできるようにしましょう。

おもむろにプロジェクトをアンロードして 編集に入ります。とりあえず実行してたコマンドを Exec で叩きます。

  <Target Name="MobiBuild" AfterTargets="Build">
    <Exec Command="buildTools\kindlegen MSBuildBook.opf" 
          StdOutEncoding ="utf-8" 
          StdErrEncoding="utf-8"  />
  </Target>

AfterTargets で Build を指定しているので標準の build が動いた後でこのターゲットが実行されますね。

コマンドプロンプトで build したらちゃんと実行結果を得られました。プロジェクトを再読み込みし、リビルドすると、はいできたー。

imageimage

opf 書くのだるいよね

うん、だるいね。本体のHTMLをどんどん書いていけば出来上がるのが理想だね。

csproj には html の一覧あるし、これを元に出したいね。というわけで opf 作成の msbuild のカスタムタスクを書く。

using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Xml.Linq; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; namespace Build.Utilities { public class GenerateOpf : Task { [Required] public ITaskItem Metadata { get; set; } [Required] public ITaskItem[] Contents { get; set; } [Required] public string OutputFile { get; set; } public override bool Execute() { var metadata = XDocument.Load(Metadata.ItemSpec); var doc = new XDocument( new XElement( "package", new XAttribute("unique-identifier", "uid"), CreateMetadataElement(metadata), CreateManifestElement(Contents), new XElement("spine", new XAttribute("toc", "toc")), new XElement("guide") )); doc.Save(OutputFile, SaveOptions.OmitDuplicateNamespaces); return true; } private static XElement CreateManifestElement(IEnumerable<ITaskItem> contents) { var manifestElement = new XElement("manifest"); manifestElement.Add( new XElement( "item", new XAttribute("id", "toc"), new XAttribute("media-type", "application/x-dtbncx+xml"), new XAttribute("href", "toc.ncx"))); foreach (var item in contents.Where( i => Path.GetExtension(i.ItemSpec) == ".html")) { var itemSpec = item.ItemSpec; Debug.Assert(itemSpec != null, "itemSpec != null"); var idValue = Path.GetFileNameWithoutExtension(itemSpec); manifestElement.Add( new XElement( "item", new XAttribute("id", idValue), new XAttribute("media-type", "text/x-oeb1-document"), new XAttribute("href", itemSpec))); } return manifestElement; } private static XElement CreateMetadataElement( XDocument metadata) { return new XElement( "metadata", CreateDcMetadataElement(metadata), CreateXMetadataElement() ); } private static XElement CreateXMetadataElement() { return new XElement( "x-metadata", new XElement( "output", new XAttribute("encoding", "utf-8"), new XAttribute("content-type", "text/x-oeb1-document")), new XElement( "EmbeddedCover", new XText("images/Cover.jpg")) ); } private static XElement CreateDcMetadataElement( XDocument metadata) { XNamespace dc = "http://purl.org/metadata/dublin_core"; XNamespace obe = "http://openebook.org/namespaces/oeb-package/1.0/"; var dcMetadataElement = new XElement( "dc-metadata", new XAttribute(XNamespace.Xmlns + "dc", dc.NamespaceName), new XAttribute(XNamespace.Xmlns + "oebpackage", obe.NamespaceName) ); foreach (var element in metadata.Element("dc-metadata").Elements()) { dcMetadataElement.Add(element); } return dcMetadataElement; } } }

これを csproj に組み込むには以下のように。

  <UsingTask 
    TaskName="GenerateOpf" 
    TaskFactory="CodeTaskFactory" 
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
    <ParameterGroup>
      <Metadata ParameterType="Microsoft.Build.Framework.ITaskItem"
            Required="true" />
      <Contents ParameterType="Microsoft.Build.Framework.ITaskItem[]" 
            Required="true" />
      <OutputFile ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Reference Include="System.Xml" />
      <Reference Include="System.Xml.Linq" />
      <Code Type="Class" Language="cs"
          Source="..\Build.Utilities\GenerateOpf.cs" />
    </Task>
  </UsingTask>
  <Target Name="OpfGenerate" BeforeTargets="Build">
    <GenerateOpf 
         Metadata="Metadata.xml" 
         Contents="@(Content)" 
         OutputFile="MSBuildBook.opf" />
  </Target>

dublin core なメタデータだけ Metadata.xml に書けば、こんな opf が吐かれる。

<?xml version="1.0" encoding="utf-8"?>
<package unique-identifier="uid">
  <metadata>
    <dc-metadata xmlns:dc="http://purl.org/metadata/dublin_core" xmlns:oebpackage="http://openebook.org/namespaces/oeb-package/1.0/">
      <dc:Title>msbuild をこねる本</dc:Title>
      <dc:Language>en-us</dc:Language>
      <dc:Creator>kazuk</dc:Creator>
      <dc:Description>msbuildをこねてビルドの自動化とかを色々カスタマイズする本です</dc:Description>
      <dc:Date>26/03/2013</dc:Date>
    </dc-metadata>
    <x-metadata>
      <output encoding="utf-8" content-type="text/x-oeb1-document" />
      <EmbeddedCover>images/Cover.jpg</EmbeddedCover>
    </x-metadata>
  </metadata>
  <manifest>
    <item id="toc" media-type="application/x-dtbncx+xml" href="toc.ncx" />
    <item id="index" media-type="text/x-oeb1-document" href="index.html" />
    <item id="MSBuildProjects" media-type="text/x-oeb1-document" href="MSBuildProjects.html" />
    <item id="VSAndMSBuild" media-type="text/x-oeb1-document" href="VSAndMSBuild.html" />
  </manifest>
  <spine toc="toc" />
  <guide />
</package>

html の列挙とかは csproj にある Content のリストからやってるだけだから Web アプリケーションプロジェクトに HTML ページを突っ込んで行けば自動的に opf に組み込まれるので手間がかからない。

ncx も吐いてやろうか!

似たような方法を取れば ncx も吐けます。目次の順序とかは各HTMLからキー要素をなんか抽出してあげるとかすれば良いので手間は似たようなもんでしょう。

まとめ

今日のところはこんな感じ、普通に VS でHTMLを書いてビルドすれば kindle で読める mobi を生成するプロジェクトを作る事ができました。

多分 VS Express でも同じ事はできるはずなんで、無料のExpress でHTMLシコシコ書けば普通に kindle 本を書くのはできそうです。画像とかそういうのを使ったときにどうなるとか、その辺解ったら続編を書くかもしれません。

こんな事はだれもやらねーよかもしれませんけど、VS に markdown から HTML への変換のカスタムツールとか仕込めば、markdown とかでジャカジャカ書いたものを電子書籍にするのも簡単かもしれませんね。

まとめではないこと

自分が本書いて amazon の direct publishing 出したら誰か買いますか?>買うわけないよね!

NuGet パッケージの作成とローカルリポジトリへの発行


Gistしましたって事でお知らせ。

https://gist.github.com/kazuk/5089069

何をするものですか?

ビルドすると NuGet パッケージを作り、ローカルリポジトリに発行します。

使い方

  1. ソリューションを右クリックし、「NuGetパッケージの復元の有効化」を行います。(又は NuGet.exe をソリューション配下、 .nuget ディレクトリに置いてください)
  2. ソリューションにGistから取ったファイルを突っ込んでください。
  3. csproj の末尾で Import してください
  4. 必要に応じて NuGetRepository を PropertyGroup 定義してください(定義しないと \\nugetrepos.local\NuGetRepos にパッケージを発行します)
  5. プロジェクトに nuspec を加え、ビルドアクションに NuSpec を指定します。

nuspec 作るってどうやって?

csproj のある場所で NuGet.exe spec すればいいんじゃないかな?

そのままパッケージしようとすると author とか色々設定されてないよって言われるはずだけど、文句言われた所直せばいいと思うよ。

csproj の末尾でImportって?

プロジェクトを右クリックして「プロジェクトのアンロード」、もう一回右クリックで csproj の編集すればいいよ。

ファイル末尾の </Project> の前でローカルリポジトリの場所と targets ファイル置いた場所によって設定してね。

  <PropertyGroup>
    <NuGetRepository>\\FileServer.local\NuGetRepos</NuGetRepository>
  </PropertyGroup>
  <Import Project="..\Build.Utilities\CustomBuild.targets" />

発行って Copy してるだけに見えるけど

ファイルシステムフォルダをローカルリポジトリとして使ってるならコピーだけでいいんだよ。

NuGet.org とかに出す前に色々確認して欲しいからローカルにしか出さないよ。