Antoine.st 2010-12

2010-12-30

IME Pad

まずは、クラスとインターフェイスと構造体と列挙型やらなんやらを、こんな風に定義しておきます。これが面倒くさい。.idl があるので、MIDL で .tlb を作って読み込めばいいかなぁ、と思ったんですが、読み込めず。TLBIMP で .NET Framework なアセンブリを生成することはできるので、それを利用するのが便利かも。

↓は、一から書き下ろすのが面倒だったので、そんな風に作ったアセンブリを Reflector で逆アセして、必要な部分のみを取出し & 適宜調整、にしてます。手抜き。


  [ComImport,
   Guid("EBB08C45-6C4A-4FDC-AE53-4EB8C4C7DB8E")]
  public class TF_LangBarMgrClass
  {
    // 実装コードなし
  }

  [ComImport,
   InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
   Guid("87955690-E627-11D2-8DDB-00105A2799B5")]
  public interface ITfLangBarMgr
  {
    void AdviseEventSink(
      [In, MarshalAs(UnmanagedType.Interface)] object pSink,
      [In] ref object hwnd,
      [In] uint dwFlags,
      [In] ref uint pdwCookie);

    void UnadviseEventSink(
      [In] uint dwCookie);

    void GetThreadMarshalInterface(
      [In] uint dwThreadId,
      [In] uint dwType,
      [In] ref Guid riid,
      [MarshalAs(UnmanagedType.IUnknown)]
      out object ppunk);

    void GetThreadLangBarItemMgr(
      [In] uint dwThreadId,
      [MarshalAs(UnmanagedType.Interface)]
      out ITfLangBarItemMgr pplbi,
      out uint pdwThreadid);

    void GetInputProcessorProfiles(
      [In] uint dwThreadId,
      [MarshalAs(UnmanagedType.Interface)] out object ppaip,
      out uint pdwThreadid);

    void RestoreLastFocus(
      out uint pdwThreadid,
      [In] int fPrev);

    void SetModalInput(
      [In, MarshalAs(UnmanagedType.Interface)] object pSink,
      [In] uint dwThreadId,
      [In] uint dwFlags);

    void ShowFloating(
      [In] uint dwFlags);

    void GetShowFloatingStatus(
      out uint pdwFlags);
  }

  [ComImport,
   Guid("BA468C55-9956-4FB1-A59D-52A7DD7CC6AA"),
   InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
  public interface ITfLangBarItemMgr
  {
    void EnumItems(
      [MarshalAs(UnmanagedType.Interface)]
      out IEnumTfLangBarItems ppEnum);

    void GetItem(
      [In] ref Guid rguid,
      [MarshalAs(UnmanagedType.Interface)] out object ppItem);

    void AddItem(
      [In, MarshalAs(UnmanagedType.Interface)] object punk);

    void RemoveItem(
      [In, MarshalAs(UnmanagedType.Interface)] object punk);

    void AdviseItemSink(
      [In, MarshalAs(UnmanagedType.Interface)] object punk,
      out uint pdwCookie,
      [In] ref Guid rguidItem);

    void UnadviseItemSink(
      [In] uint dwCookie);

    void GetItemFloatingRect(
      [In] uint dwThreadId,
      [In] ref Guid rguid,
      out tagRECT prc);

    void GetItemsStatus(
      [In] uint ulCount,
      [In] ref Guid prgguid,
      out uint pdwStatus);

    void GetItemNum(
      out uint pulCount);

    void GetItems(
      [In] uint ulCount,
      [MarshalAs(UnmanagedType.Interface)] out object ppItem,
      out TF_LANGBARITEMINFO pInfo,
      out uint pdwStatus,
      [In, Out] ref uint pcFetched);

    void AdviseItemsSink(
      [In] uint ulCount,
      [In, MarshalAs(UnmanagedType.Interface)] ref object ppunk,
      [In] ref Guid pguidItem,
      out uint pdwCookie);

    void UnadviseItemsSink(
      [In] uint ulCount,
      [In] ref uint pdwCookie);
  }

  [ComImport,
   Guid("583F34D0-DE25-11D2-AFDD-00105A2799B5"),
   InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
  public interface IEnumTfLangBarItems
  {
    void Clone(
      [MarshalAs(UnmanagedType.Interface)]
      out IEnumTfLangBarItems ppEnum);

    void Next(
      [In] uint ulCount,
      [MarshalAs(UnmanagedType.Interface)]
      out ITfLangBarItem ppItem,
      [In, Out] ref uint pcFetched);

    void Reset();

    void Skip(
      [In] uint ulCount);
  }

  [ComImport,
   InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
   Guid("73540D69-EDEB-4EE9-96C9-23AA30B25916")]
  public interface ITfLangBarItem
  {
    void GetInfo(
      out TF_LANGBARITEMINFO pInfo);

    void GetStatus(
      out uint pdwStatus);

    void Show(
      [In] int fShow);

    void GetTooltipString(
      [MarshalAs(UnmanagedType.BStr)]
      out string pbstrToolTip);
  }

  [ComImport,
   InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
   Guid("28C7F1D0-DE25-11D2-AFDD-00105A2799B5")]
  public interface ITfLangBarItemButton : ITfLangBarItem
  {
    new void GetInfo(
      out TF_LANGBARITEMINFO pInfo);

    new void GetStatus(
      out uint pdwStatus);

    new void Show(
      [In] int fShow);

    new void GetTooltipString(
      [MarshalAs(UnmanagedType.BStr)]
      out string pbstrToolTip);

    void OnClick(
      [In] TfLBIClick click,
      [In] tagPOINT pt,
      [In] ref tagRECT prcArea);

    void InitMenu(
      [In, MarshalAs(UnmanagedType.Interface)] object pMenu);

    void OnMenuSelect(
      [In] uint wID);

    void GetIcon(
      out object phIcon);

    void GetText(
      [MarshalAs(UnmanagedType.BStr)] out string pbstrText);
  }

  [StructLayout(LayoutKind.Sequential,
                Pack = 4)]
  public struct tagRECT
  {
    public int left;
    public int top;
    public int right;
    public int bottom;
  }

  [StructLayout(LayoutKind.Sequential,
                Pack = 4)]
  public struct tagPOINT
  {
    public int x;
    public int y;
  }

  [StructLayout(LayoutKind.Sequential,
                Pack = 4,
                CharSet = CharSet.Unicode),
   Guid("12A1D29F-A065-440C-9746-EB2002C8BD19")]
  public struct TF_LANGBARITEMINFO
  {
    public Guid clsidService;
    public Guid guidItem;
    public uint dwStyle;
    public uint ulSort;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
    public string szDescription;
  }

  [Guid("8FB5F0CE-DFDD-4F0A-85B9-8988D8DD8FF2")]
  public enum TfLBIClick
  {
    TF_LBI_CLK_LEFT = 2,
    TF_LBI_CLK_RIGHT = 1
  }

ここまでの下準備ができたら、あとは呼び出すだけ。ITfLangBarMgr インターフェイス -> ITfLangBarItemMgr インターフェイス -> IEnumTfLangBarItems インターフェイス -> ITfLangBarItem インターフェイスときて、ITfLangBarItemButton インターフェイスにキャストして、最後に OnClick() メソッドを呼び出すと、ボタンを押したのと同じ動作になりますよと。

今回は、TF_LANGBARITEMINFO.szDescription メンバの文字列から『IME パッド』かどうかを判定していますが、ローカライズとか考えると GUID とかの方がいいかもしれません。ま、IME の種類に強く依存するわけで、設定ファイルとかで変えられるようにしとかないと厳しいでしょうけど。


  [DllImport("kernel32.dll")]
  static extern uint GetCurrentThreadId();

  const string IMEPAD_NAME = "IME パッド";

  private void showImePad()
  {
    TF_LangBarMgrClass tfLangBarMgr;
    ITfLangBarMgr iTfLangBarMgr;
    ITfLangBarItemMgr iTfLangBarItemMgr;
    IEnumTfLangBarItems iEnumTfLangBarItems;
    ITfLangBarItem iTfLangBarItem;
    TF_LANGBARITEMINFO info;
    ITfLangBarItemButton iTfLangBarItemButton;

    uint threadID;
    uint itemCount;
    uint fetched;
    tagPOINT pt;
    tagRECT rect;

    tfLangBarMgr = new TF_LangBarMgrClass();
    iTfLangBarMgr = (ITfLangBarMgr)tfLangBarMgr;

    iTfLangBarMgr.GetThreadLangBarItemMgr(
      GetCurrentThreadId(),
      out iTfLangBarItemMgr,
      out threadID);
    iTfLangBarItemMgr.GetItemNum(out itemCount);
    iTfLangBarItemMgr.EnumItems(out iEnumTfLangBarItems);
    for (uint i = 1; i <= itemCount; i++)
    {
      fetched = 0;
      iEnumTfLangBarItems.Next(
        1, out iTfLangBarItem, ref fetched);
      if (iTfLangBarItem != null)
      {
        iTfLangBarItem.GetInfo(out info);
        if (info.szDescription.StartsWith(IMEPAD_NAME))
        {
          iTfLangBarItemButton =
            (ITfLangBarItemButton)iTfLangBarItem;
          pt.x = 0;
          pt.y = 0;
          rect.top = 0;
          rect.bottom = 0;
          rect.left = 0;
          rect.right = 0;
          iTfLangBarItemButton.OnClick(
            TfLBIClick.TF_LBI_CLK_LEFT, pt, rect);
        }
      }
    }
  }

※ CoCreateInstance() 関数の代わりには、Type.GetTypeFromCLSID() メソッドとか使えたような気がするんですが、なぜかキャスト時にエラーが出るので、空のクラスを定義しておきました。よくわかりません。

参照リンク


2010-12-04

IMAPI v2 Sample - 2

  • v7.1\Samples\winbase\imapi\imapi2sample\RawWriter.cpp

ついでにこっちの方も。いわゆる普通の音楽 CD を作る際は、ここ の情報を見る限り、44.1 KHz、16 ビット、ステレオのファイルを突っ込む形になる模様。なんでもかんでも入るわけじゃない、って当然のこと。

  • IRawCDImageCreator インターフェイスの取得
  • SHCreateStreamOnFileW() でオーディオファイルをストリームに
  • IRawCDImageCreator->put_ResultingImageType() でイメージタイプを設定
  • IRawCDImageCreator->AddTrack() でトラック追加
  • IRawCDImageCreator->CreateResultImage() でイメージ作成

  • IDiscMaster2 インターフェイスの取得
  • IDiscRecorder2 インターフェイスの取得
  • IDiscFormat2RawCD インターフェイスの取得
  • IDiscRecorder2->InitializeDiscRecorder() で初期化
  • IDiscFormat2RawCD->put_Recorder() で disc recorder をアタッチ
  • IDiscFormat2RawCD->put_ClientName() で app name 設定
  • IDiscFormat2RawCD->PrepareMedia() でメディアを準備
  • IDiscFormat2RawCD->put_RequestedSectorType() セクタタイプを指定
  • IDiscFormat2RawCD->WriteMedia() でメディア書き込み
  • IDiscFormat2RawCD->ReleaseMedia() でメディアの解放

たいして変わらないですね。イメージタイプが微妙に違ったり、ってくらいでしょうか ( こっちは、PQ_ONLY で、下のサンプルは RAW )。あとは、2,352 バイト境界に並べなくてもいいらしく、こっちの方が楽な感じです。まー、なんというか、CComPtr って便利です。はい。

参照リンク

IMAPI v2 Sample

  • v7.1\Samples\winbase\imapi\imapi2sample\imapi2sample.cpp

のサンプル ( RawWriter()、GetDescRecorder() 関数 ) によりますと、次のような手順となってます。結構面倒といえば面倒。でも、これだけで CD / DVD の書き込みができる、と思えば、楽な時代になりましたね。

  • IDiscMaster2 インターフェイスの取得
  • IDiscMaster2->get_Item() で unique id を取得
  • IDiscRecorder2 インターフェイスの取得
  • IDiscRecorder2->InitializeDiscRecorder() で初期化

  • IDiscFormat2RawCD インターフェイスの取得
  • IDiscFormat2RawCD->put_Recorder() で disc recorder をアタッチ
  • IDiscFormat2RawCD->put_ClientName() で app name 設定
  • IDiscFormat2RawCD->IsRecorderSupported() でサポートチェック
  • IDiscFormat2RawCD->IsCurrentMediaSupported() でサポートチェック

  • IRawCDImageCreator インターフェイスの取得
  • IRawCDImageCreator->put_ResultingImageType() でイメージタイプを設定

  • SHCreateStreamOnFileW() で書き込みストリーム生成
  • IStream->SetSize() で 2,352 バイト境界に配置
  • IRawCDImageCreator->AddTrack() でストリームをトラックに追加
  • ファイル分繰り返し

  • IRawCDImageCreator->CreateResultImage() でディスクイメージ作成
  • IDiscFormat2RawCD->PrepareMedia() でメディアを準備
  • IDiscFormat2RawCD->put_RequestedSectorType() セクタタイプを指定

  • IDiscFormat2RawCD->WriteMedia() でメディア書き込み
  • IDiscFormat2RawCD->ReleaseMedia() でメディアの解放

参照リンク

補足 ( ↓は、音楽 CD の作り方っぽいです )

  • v7.1\Samples\winbase\imapi\imapi2sample\RawWriter.cpp


2010-12-03

Accessibility Memo

ちょっとメモ。accExplorer が見つからない...。


  [DllImport("oleacc.dll")]
  static extern int AccessibleObjectFromWindow(
    IntPtr hwnd,
    uint id,
    ref Guid iid,
    [MarshalAs(UnmanagedType.IUnknown)] out object ppvObject);

  const int NAVDIR_NEXT = 0x5;
  const int NAVDIR_FIRSTCHILD = 0x7;

  Guid guid;
  object obj;
  int result;
  IAccessible aGrid;
  IAccessible tGrid;

  guid  = new Guid("{618736E0-3C3D-11CF-810C-00AA00389B71}");
  result = AccessibleObjectFromWindow(hwnd, 0, ref guid, out obj);
  aGrid  = (IAccessible)obj;

  tGrid = aGrid.accNavigate(NAVDIR_FIRSTCHILD);