トップ 差分 一覧 ソース 検索 ヘルプ PDF RSS ログイン

Visual Studio .NET 2003 C#、PDF関連

[カテゴリ:言語]
[カテゴリ:C#]
[カテゴリ:メモ]

PDFの指定ページを表示する。

概要

AcrobatReader または、Writerが起動した状態で
DDEのコマンドを送ることで、指定ページを表示する。

こんな感じ。

Client                                              Server
  |                                                    |
  |  Connect                                           |
  |  Service="Acroview", Topic="Control"               |
  |--------------------------------------------------->|
  |                                                    |
  |  Transaction                                       |
  |  XTYP_EXECUTE, Data="[DocGoTo(NULL,1)]"            |
  |--------------------------------------------------->|---> 指定ページを表示
  |                                                    |

ということで、C#上での実装となるのだが、
C#はDDEをサポートしていないそうだ。ショック・・・
ということでWin32APIを呼ぶことにする。

DDEMLのAPIを以下の順番でCallする。
1.DdeInitialize
2.DdeConnect
3.DdeClientTransaction
4.DdeDisconnect
5.DdeUninitialize

DdeClient.cs

DDEクライアント、クラス

using System;
using System.Runtime.InteropServices;

namespace WindowsApplication1
{
  /// <summary>
  /// DdeClient の概要の説明です。
  /// </summary>
  public class DdeClient : IDisposable
  {
    private bool _initialized = false;
    private bool _connected = false;
    private int _instance_id;
    private IntPtr _conversation_handle;

    public DdeClient()
    {
      // 
      // TODO: コンストラクタ ロジックをここに追加してください。
      //
    }

    public void Dispose()
    {
      this.Disconnect();
      this.Uninitialize();
    }

    public void Initialize(int afCmd)
    {
      int instanceId = 0;
      Ddeml.DdeCallback pfnCallback = new Ddeml.DdeCallback(this._dde_call_back);
      Ddeml.DdeInitialize(ref instanceId, pfnCallback, afCmd, 0);
      if (instanceId == 0)
      {
        throw new Exception( string.Format("err!! DdeInitialize()") );
      }
      this._instance_id = instanceId;
      this._initialized = true;
    }

    public void Connect(string service, string topic)
    {
      if (this._initialized == false || this._connected == true)
      {
        throw new Exception( string.Format("err!!") );
      }

      int instanceId = this._instance_id;

      // ハンドル作成
      IntPtr serviceHandle = Ddeml.DdeCreateStringHandle(instanceId, service, Ddeml.CP_WINANSI);
      IntPtr topicHandle = Ddeml.DdeCreateStringHandle(instanceId, topic, Ddeml.CP_WINANSI);

      // 接続
      IntPtr handle = Ddeml.DdeConnect(instanceId, serviceHandle, topicHandle, IntPtr.Zero);

      // ハンドル開放
      Ddeml.DdeFreeStringHandle(instanceId, topicHandle);
      Ddeml.DdeFreeStringHandle(instanceId, serviceHandle);

      if (handle == IntPtr.Zero)
      {
        int error = Ddeml.DdeGetLastError(this._instance_id);
        throw new Exception( string.Format("err!! DdeConnect() error={0}", error) );
      }
      this._conversation_handle = handle;
      this._connected = true;
    }

    public void Execute(string command)
    {
      this.Execute(command, 1000);
    }

    public void Execute(string command, int timeout)
    {
      if (this._initialized == false || this._connected == false)
      {
        throw new Exception( string.Format("err!!") );
      }
      if (command.Length > Ddeml.MAX_STRING_SIZE)
      {
        throw new Exception( string.Format("err!! command.Length={0}", command.Length) );
      }
      if (timeout <= 0)
      {
        throw new Exception( string.Format("err!! timeout={0}", timeout) );
      }

      // コマンドのバByte配列化
      byte[] data = System.Text.Encoding.GetEncoding("shift_jis").GetBytes(command + "\0");
            
      // コマンド送信
      int returnFlags = 0;
      IntPtr result = Ddeml.DdeClientTransaction(
        data, 
        data.Length, 
        this._conversation_handle, 
        IntPtr.Zero, 
        Ddeml.CF_TEXT, 
        Ddeml.XTYP_EXECUTE, 
        timeout, 
        ref returnFlags);

      if (result == IntPtr.Zero)
      {  
        int error = Ddeml.DdeGetLastError(this._instance_id);
        throw new Exception( string.Format("err!! DdeClientTransaction() error=0x{0:x}", error) );
      }
    }

    public void Disconnect()
    {
      if (this._initialized == false || this._connected == false)
      {
        throw new Exception( string.Format("err!!") );
      }
      Ddeml.DdeDisconnect(this._conversation_handle);
      this._connected = false;
    }
    
    public void Uninitialize()
    {
      if (this._initialized == false)
      {
        throw new Exception( string.Format("err!!") );
      }
      Ddeml.DdeUninitialize(this._instance_id);
      this._initialized = false;;
    }

    private IntPtr _dde_call_back(int uType, int uFmt, IntPtr hConv, IntPtr hsz1, IntPtr hsz2, IntPtr hData, IntPtr dwData1, IntPtr dwData2)
    {
      return IntPtr.Zero;
    }
  }

  public class Ddeml
  {
    public const int MAX_STRING_SIZE                = 255;

    public const int APPCMD_CLIENTONLY              = unchecked((int)0x00000010);
    public const int APPCMD_FILTERINITS             = unchecked((int)0x00000020);
    public const int APPCMD_MASK                    = unchecked((int)0x00000FF0);
    public const int APPCLASS_STANDARD              = unchecked((int)0x00000000);
    public const int APPCLASS_MONITOR               = unchecked((int)0x00000001);
    public const int APPCLASS_MASK                  = unchecked((int)0x0000000F);

    public const int CF_TEXT                        = 1;
        
    public const int CP_WINANSI                     = 1004;
    public const int CP_WINUNICODE                  = 1200;
        
    public const int DDE_FACK                       = unchecked((int)0x8000);
    public const int DDE_FBUSY                      = unchecked((int)0x4000);
    public const int DDE_FDEFERUPD                  = unchecked((int)0x4000);
    public const int DDE_FACKREQ                    = unchecked((int)0x8000);
    public const int DDE_FRELEASE                   = unchecked((int)0x2000);
    public const int DDE_FREQUESTED                 = unchecked((int)0x1000);
    public const int DDE_FAPPSTATUS                 = unchecked((int)0x00ff);
    public const int DDE_FNOTPROCESSED              = unchecked((int)0x0000);
        
    public const int DMLERR_NO_ERROR                = unchecked((int)0x0000);
    public const int DMLERR_FIRST                   = unchecked((int)0x4000);
    public const int DMLERR_ADVACKTIMEOUT           = unchecked((int)0x4000);
    public const int DMLERR_BUSY                    = unchecked((int)0x4001);
    public const int DMLERR_DATAACKTIMEOUT          = unchecked((int)0x4002);
    public const int DMLERR_DLL_NOT_INITIALIZED     = unchecked((int)0x4003);
    public const int DMLERR_DLL_USAGE               = unchecked((int)0x4004);
    public const int DMLERR_EXECACKTIMEOUT          = unchecked((int)0x4005);
    public const int DMLERR_INVALIDPARAMETER        = unchecked((int)0x4006);
    public const int DMLERR_LOW_MEMORY              = unchecked((int)0x4007);
    public const int DMLERR_MEMORY_ERROR            = unchecked((int)0x4008);
    public const int DMLERR_NOTPROCESSED            = unchecked((int)0x4009);
    public const int DMLERR_NO_CONV_ESTABLISHED     = unchecked((int)0x400A);
    public const int DMLERR_POKEACKTIMEOUT          = unchecked((int)0x400B);
    public const int DMLERR_POSTMSG_FAILED          = unchecked((int)0x400C);
    public const int DMLERR_REENTRANCY              = unchecked((int)0x400D);
    public const int DMLERR_SERVER_DIED             = unchecked((int)0x400E);
    public const int DMLERR_SYS_ERROR               = unchecked((int)0x400F);
    public const int DMLERR_UNADVACKTIMEOUT         = unchecked((int)0x4010);
    public const int DMLERR_UNFOUND_QUEUE_ID        = unchecked((int)0x4011);
    public const int DMLERR_LAST                    = unchecked((int)0x4011);

    public const int XTYPF_NOBLOCK                  = unchecked((int)0x0002);
    public const int XTYPF_NODATA                   = unchecked((int)0x0004);
    public const int XTYPF_ACKREQ                   = unchecked((int)0x0008);
    public const int XCLASS_MASK                    = unchecked((int)0xFC00);
    public const int XCLASS_BOOL                    = unchecked((int)0x1000);
    public const int XCLASS_DATA                    = unchecked((int)0x2000);
    public const int XCLASS_FLAGS                   = unchecked((int)0x4000);
    public const int XCLASS_NOTIFICATION            = unchecked((int)0x8000);
    public const int XTYP_ERROR                     = unchecked((int)(0x0000 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK));
    public const int XTYP_ADVDATA                   = unchecked((int)(0x0010 | XCLASS_FLAGS));
    public const int XTYP_ADVREQ                    = unchecked((int)(0x0020 | XCLASS_DATA | XTYPF_NOBLOCK));
    public const int XTYP_ADVSTART                  = unchecked((int)(0x0030 | XCLASS_BOOL));
    public const int XTYP_ADVSTOP                   = unchecked((int)(0x0040 | XCLASS_NOTIFICATION));
    public const int XTYP_EXECUTE                   = unchecked((int)(0x0050 | XCLASS_FLAGS));
    public const int XTYP_CONNECT                   = unchecked((int)(0x0060 | XCLASS_BOOL | XTYPF_NOBLOCK));
    public const int XTYP_CONNECT_CONFIRM           = unchecked((int)(0x0070 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK));
    public const int XTYP_XACT_COMPLETE             = unchecked((int)(0x0080 | XCLASS_NOTIFICATION));
    public const int XTYP_POKE                      = unchecked((int)(0x0090 | XCLASS_FLAGS));
    public const int XTYP_REGISTER                  = unchecked((int)(0x00A0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK));
    public const int XTYP_REQUEST                   = unchecked((int)(0x00B0 | XCLASS_DATA));
    public const int XTYP_DISCONNECT                = unchecked((int)(0x00C0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK));
    public const int XTYP_UNREGISTER                = unchecked((int)(0x00D0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK));
    public const int XTYP_WILDCONNECT               = unchecked((int)(0x00E0 | XCLASS_DATA | XTYPF_NOBLOCK));
    public const int XTYP_MONITOR                   = unchecked((int)(0x00F0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK));
    public const int XTYP_MASK                      = unchecked((int)0x00F0);
    public const int XTYP_SHIFT                     = unchecked((int)0x0004);

    public delegate IntPtr DdeCallback(
      int uType, int uFmt, IntPtr hConv, IntPtr hsz1, IntPtr hsz2, IntPtr hData, IntPtr dwData1, IntPtr dwData2);

    [DllImport("user32.dll", EntryPoint="DdeClientTransaction", CharSet=CharSet.Ansi)]
    public static extern IntPtr DdeClientTransaction(
      IntPtr pData, int cbData, IntPtr hConv, IntPtr hszItem, int wFmt, int wType, int dwTimeout, ref int pdwResult);

    [DllImport("user32.dll", EntryPoint="DdeClientTransaction", CharSet=CharSet.Ansi)]
    public static extern IntPtr DdeClientTransaction(
      byte[] pData, int cbData, IntPtr hConv, IntPtr hszItem, int wFmt, int wType, int dwTimeout, ref int pdwResult);

    [DllImport("user32.dll", EntryPoint="DdeConnect", CharSet=CharSet.Ansi)]
    public static extern IntPtr DdeConnect(int idInst, IntPtr hszService, IntPtr hszTopic, IntPtr pCC);

    [DllImport("user32.dll", EntryPoint="DdeCreateStringHandle", CharSet=CharSet.Ansi)]
    public static extern IntPtr DdeCreateStringHandle(int idInst, string psz, int iCodePage);

    [DllImport("user32.dll", EntryPoint="DdeDisconnect", CharSet=CharSet.Ansi)]
    public static extern bool DdeDisconnect(IntPtr hConv);

    [DllImport("user32.dll", EntryPoint="DdeFreeStringHandle", CharSet=CharSet.Ansi)]
    public static extern bool DdeFreeStringHandle(int idInst, IntPtr hsz);

    [DllImport("user32.dll", EntryPoint="DdeGetLastError", CharSet=CharSet.Ansi)]
    public static extern int DdeGetLastError(int idInst);

    [DllImport("user32.dll", EntryPoint="DdeInitialize", CharSet=CharSet.Ansi)]
    public static extern int DdeInitialize(ref int pidInst, DdeCallback pfnCallback, int afCmd, int ulRes);

    [DllImport("user32.dll", EntryPoint="DdeUninitialize", CharSet=CharSet.Ansi)]
    public static extern bool DdeUninitialize(int idInst);
  }
}

DdeClient を使ってみる。

DdeClient dde = new DdeClient();
using (dde)
{
  dde.Initialize(Ddeml.APPCMD_CLIENTONLY);
  dde.Connect(this.textBox_Service.Text, this.textBox_Topic.Text);
  dde.Execute(this.textBox_Command.Text);
}

参考

Acrobat Reader でPDFの指定されたページを開く
http://vlog.blog32.fc2.com/blog-entry-48.html
|ServiceName:Acroview
|Topic:Control
|Data:[DocOpen("PDFファイルのパス")][DocGoTo(NULL,ページ番号-1)]

nsisDDE 1.0
# C++ による DDE Client
http://wiz0u.free.fr/prog/nsisDDE/

DDEクライアントを作る
http://hp.vector.co.jp/authors/VA016117/ddecli.html

GotDotNet User Sample: Dynamic Data Exchange (DDE)
# C# による DDE Client / Server
http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=2C8C36CF-A974-4B7B-8924-2ED516B75181

DDEListener Component (open your Document Files with Explorer)
# C# による DDE Server
http://www.codeproject.com/cs/miscctrl/ddelistener.asp

第150章 DDEでエクセルよりデータを読む
http://www.kumei.ne.jp/c_lang/sdk2/sdk_150.htm
|1.DdeInitialize関数でDDEを初期化します。
|2.DdeConnect関数で通信開始。
|3.DdeClientTransaction関数でトランザクションをサーバーに転送
|4.DdeGetData関数などでデータを取得
|5.DdeDisconnect関数で通信終了
|6.DdeUninitialize関数でDDEアプリケーションではなくなったことを
|  サーバーに通知

最終更新時間:2006年12月21日 00時25分44秒