【お知らせ】プログラミング記事の投稿はQiitaに移行しました。

クリップボードにコピーされたオートシェイプ

Excelなどでクリップボードにコピーしたオートシェイプの画像データを、Excel外のアプリケーションから操作することを試みていました。データはClipboard.GetData("Office Drawing Shape Format")とすればMemoryStreamで取得できます。バイナリ構造は仕様書が公開されています。

取っ掛かりとして、大まかにMSOFBH構造体を辿るコードは以下の通りです。

using System;
using System.IO;
using System.Windows.Forms;

class Program
{
    [STAThread]
    static void Main()
    {
        var ms = Clipboard.GetData("Office Drawing Shape Format") as MemoryStream;
        if (ms == null)
            Console.WriteLine("MS Office 描画オブジェクトがコピーされていません。");
        else
        {
            var data = ms.ToArray();
            Parse(data, 0, data.Length, "");
        }
    }

    static void Parse(byte[] data, int p, int end, string indent)
    {
        if (p + 8 >= end || (data[p + 3] & ~1) != 0xf0) return;
        int size = BitConverter.ToInt32(data, p + 4);
        Console.WriteLine("{0}[{1:x8}] {2:x8} {3:x8}=>{4:x8}",
            indent, p, BitConverter.ToInt32(data, p), size, p + 8 + size);
        Parse(data, p + 8, p + 8 + size, indent + "  ");
        Parse(data, p + 8 + size, end, indent);
    }
}

実行してみると入れ子構造になっているのがよく分かります。

[00000000] f000000f 000116b2=>000116ba
  [00000008] f0060000 00000018=>00000028
  [00000028] f0160000 00000010=>00000040
  [00000040] f001001f 0001165a=>000116a2
    [00000048] f0070052 00011652=>000116a2
  [000116a2] f11e0040 00000010=>000116ba
[000116ba] f002000f 00000218=>000118da
  [000116c2] f0080010 00000008=>000116d2
  [000116d2] f003000f 000000b4=>0001178e
    [000116da] f004000f 00000028=>0001170a
      [000116e2] f0090001 00000010=>000116fa
      [000116fa] f00a0002 00000008=>0001170a
    [0001170a] f004000f 0000007c=>0001178e
      [00011712] f00a04b2 00000008=>00011722
      [00011722] f00b0023 0000001a=>00011744
      [00011744] f00e0000 00000010=>0001175c
      [0001175c] f0110000 0000002a=>0001178e
  [0001178e] f1200510 00000144=>000118da

この後はMSOFBH::fbtの値を仕様書の11〜12ページで調べながら解析していくことになります。