InfoPath 2010 または InfoPath 2007 で Visual C# を使用してプログラムで添付ファイルをエンコードおよびデコードする方法

概要

Microsoft InfoPath 2010または Microsoft Office InfoPath 2007 では、添付ファイル コントロールを使用して、InfoPath フォーム テンプレートにファイルを添付できます。 特定の状況では、ファイル添付コントロールに添付されているファイルをエンコードしてからデコードすることができます。 この場合、Microsoft Visual C# を使用してエンコーダークラスとデコーダークラスを作成できます。 その後、Encoderclass とデコーダークラスを使用して、添付ファイルをエンコードしてデコードできます。 この記事では、フォームへの添付ファイルをエンコードし、ファイル システムに保存するために添付ファイルをデコードする InfoPath フォーム テンプレートを設計する方法について説明します。  

InfoPath 2003 でこれを行う方法の詳細については、次の記事番号をクリックして、Microsoft サポート技術情報の記事を参照してください。

892730 InfoPath で Visual C# を使用してファイル添付ファイルをプログラムでエンコードおよびデコードする方法

詳細情報

サンプル プログラムは例示のみを目的として提供されており、商品性、特定目的に対する適合性その他について明示であると黙示であるとを問わず、マイクロソフトは一切保証をするものではありません。 サンプル プログラムの利用者には、使用するプログラミング言語、およびプロシージャの作成とデバッグに使用されるツールに精通しているユーザーを想定しています。 Microsoft Support 担当者は、サンプル プログラムを利用してある特定のプロシージャの機能を説明することがありますが、改変して機能を追加したり、ユーザーの要望に応じてプロシージャを作成したりすることはありません。

次の例では、次の手順に従います。

  1. Visual C# プロジェクトを含むフォームを作成します。
  2. Encoderclass を作成します。
  3. デコーダークラスを作成します。
  4. コードを呼び出すようにフォームを変更します。
  5. フォームでコード操作をテストします。

Visual C# プロジェクトを含むフォームを作成する

使用している InfoPath のバージョンの指示を使用して、フォーム テンプレートとプロジェクトを作成します。

InfoPath 2010

  1. InfoPath デザイナーで、空のフォーム テンプレートを作成し、[保存] アイコンをクリックします。
  2. メッセージが表示されたら、ファイル名を入力し、[保存] をクリックします。
  3. [**Developer **] タブをクリックし、[言語] をクリックします。
  4. フォーム テンプレートのコード言語で C# を選択し、[OK] をクリックします。

InfoPath 2007

  1. [**ファイル **] メニューの [ フォーム テンプレートのデザイン] をクリックします。
  2. **[フォーム テンプレートのデザイン] **作業ウィンドウで、[ 空白 ] をクリックし、[OK] をクリック します
  3. [ファイル] メニューで [保存] をクリックします。
  4. メッセージが表示されたら、ファイル名 InfoPathAttachmentEncoding を入力し、[ 保存] をクリックします。
  5. [ツール] メニューの [フォームのオプション] をクリックします。
  6. [**フォーム オプション **] ダイアログ ボックスの [ カテゴリ ] で、[ プログラミング] をクリックします。
  7. [プログラミング言語] の [フォーム テンプレート コード言語] ボックスの一覧で [C#] を選択し、[OK] をクリックします

Encoder クラスを作成する

使用している InfoPath のバージョンの指示を使用して Encoderclass を作成します。

InfoPath 2010

  1. [開発者] タブの [**コード エディター**] をクリックして、Visual Studio Tools for Applications (VSTA) エディターを起動します。
  2. [ プロジェクト ] メニューの [ 新しい項目の追加] をクリックします。
  3. クリックして [クラス] を選択します。
  4. [名前] フィールドで、名前を InfoPathAttachmentEncoder.cs に変更し、[保存] をクリックします。
  5. コード ウィンドウで、既存のコードを次の "エンコーダー コード" セクションのコードに置き換えます。

InfoPath 2007

  1. Visual Studio Tools for Applications (VSTA) エディターを起動します。 
  2. **プロジェクト エクスプローラー **ウィンドウで、 InfoPathAttachmentEncoding を右クリックし、[ 追加] をクリックして、[ 新しい項目] をクリックします。
  3. [ テンプレート ] セクションで、[ クラス] を選択し、名前を InfoPathAttachmentEncoder.cs に変更して、[ 追加] をクリックします。
  4. コード ウィンドウで、次の [エンコーダー コード] セクションのコードを貼り付けます。

エンコーダー コード

InfoPath 2010 または InfoPath 2007 で次のコードを使用します。

using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
using InfoPathAttachmentEncoding;

namespace InfoPathAttachmentEncoding
{
/// <summary>
/// InfoPathAttachment encodes file data into the format expected by InfoPath for use in file attachment nodes.
/// </summary>
public class InfoPathAttachmentEncoder
{
private string base64EncodedFile = string.Empty;
private string fullyQualifiedFileName;

/// <summary>
/// Creates an encoder to create an InfoPath attachment string.
/// </summary>
/// <param name="fullyQualifiedFileName"></param>
public InfoPathAttachmentEncoder(string fullyQualifiedFileName)
{
if (fullyQualifiedFileName == string.Empty)
throw new ArgumentException("Must specify file name", "fullyQualifiedFileName");

if (!File.Exists(fullyQualifiedFileName))
throw new FileNotFoundException("File does not exist: " + fullyQualifiedFileName, fullyQualifiedFileName);

this.fullyQualifiedFileName = fullyQualifiedFileName;
}

/// <summary>
/// Returns a Base64 encoded string.
/// </summary>
/// <returns>String</returns>
public string ToBase64String()
{
if (base64EncodedFile != string.Empty)
return base64EncodedFile;

// This memory stream will hold the InfoPath file attachment buffer before Base64 encoding.
MemoryStream ms = new MemoryStream();

// Obtain the file information.
using (BinaryReader br = new BinaryReader(File.Open(fullyQualifiedFileName, FileMode.Open, FileAccess.Read, FileShare.Read)))
{
string fileName = Path.GetFileName(fullyQualifiedFileName);

uint fileNameLength = (uint)fileName.Length + 1;

byte[] fileNameBytes = Encoding.Unicode.GetBytes(fileName);

using (BinaryWriter bw = new BinaryWriter(ms))
{
// Write the InfoPath attachment signature. 
bw.Write(new byte[] { 0xC7, 0x49, 0x46, 0x41 });

// Write the default header information.
bw.Write((uint)0x14);// size
bw.Write((uint)0x01);// version
bw.Write((uint)0x00);// reserved

// Write the file size.
bw.Write((uint)br.BaseStream.Length);

// Write the size of the file name.
bw.Write((uint)fileNameLength);

// Write the file name (Unicode encoded).
bw.Write(fileNameBytes);

// Write the file name terminator. This is two nulls in Unicode.
bw.Write(new byte[] {0,0});

// Iterate through the file reading data and writing it to the outbuffer.
byte[] data = new byte[64*1024];
int bytesRead = 1;

while (bytesRead > 0)
{
bytesRead = br.Read(data, 0, data.Length);
bw.Write(data, 0, bytesRead);
}
}
}

// This memorystream will hold the Base64 encoded InfoPath attachment.
MemoryStream msOut = new MemoryStream();

using (BinaryReader br = new BinaryReader(new MemoryStream(ms.ToArray())))
{
// Create a Base64 transform to do the encoding.
ToBase64Transform tf = new ToBase64Transform();

byte[] data = new byte[tf.InputBlockSize];
byte[] outData = new byte[tf.OutputBlockSize];

int bytesRead = 1;

while (bytesRead > 0)
{
bytesRead = br.Read(data, 0, data.Length);

if (bytesRead == data.Length)
tf.TransformBlock(data, 0, bytesRead, outData, 0);
else
outData = tf.TransformFinalBlock(data, 0, bytesRead);

msOut.Write(outData, 0, outData.Length);
}
}

msOut.Close();

return base64EncodedFile = Encoding.ASCII.GetString(msOut.ToArray());
}
}
}

デコーダー クラスを作成する

使用している InfoPath のバージョンの指示を使用してデコーダークラスを作成します。

InfoPath 2010

  1. コード エディターの [ プロジェクト ] メニューの [ 新しい項目の追加] をクリックし、クリックして [クラス] を選択します。
  2. [ 名前] フィールドで、名前を InfoPathAttachmentDecoder.cs に変更し、[ 保存] をクリックします。
  3. コード ウィンドウで、既存のコードを次の "デコーダー コード" セクションのコードに置き換えます。 

InfoPath 2007

  1. VSTA の **Project Explorer **ペインで、 InfoPathAttachmentEncoding を右クリックし、[ 追加] をクリックし、[ 新しい項目] をクリックします。
  2. [ テンプレート ] セクションで、[ クラス] を選択し、名前を InfoPathAttachmentDecoder.cs に変更し、[ 追加] をクリックします。
  3. コード ウィンドウで、次の "デコーダー コード" セクションのコードを貼り付けます。

デコーダー コード

InfoPath 2010 または InfoPath 2007 で次のコードを使用します。

using System;
using System.IO;
using System.Text;

namespace InfoPathAttachmentEncoding
{
/// <summary>
/// Decodes a file attachment and saves it to a specified path.
/// </summary>
public class InfoPathAttachmentDecoder
{
private const int SP1Header_Size = 20;
private const int FIXED_HEADER = 16;

private int fileSize;
private int attachmentNameLength;
private string attachmentName;
private byte[] decodedAttachment;

/// <summary>
/// Accepts the Base64 encoded string
/// that is the attachment.
/// </summary>
public InfoPathAttachmentDecoder(string theBase64EncodedString)
{
byte [] theData = Convert.FromBase64String(theBase64EncodedString);
using(MemoryStream ms = new MemoryStream(theData))
{
BinaryReader theReader = new BinaryReader(ms);
DecodeAttachment(theReader);
}
}

private void DecodeAttachment(BinaryReader theReader)
{
//Position the reader to obtain the file size.
byte[] headerData = new byte[FIXED_HEADER];
headerData = theReader.ReadBytes(headerData.Length);

fileSize = (int)theReader.ReadUInt32();
attachmentNameLength = (int)theReader.ReadUInt32() * 2;

byte[] fileNameBytes = theReader.ReadBytes(attachmentNameLength);
//InfoPath uses UTF8 encoding.
Encoding enc = Encoding.Unicode;
attachmentName = enc.GetString(fileNameBytes, 0, attachmentNameLength - 2);
decodedAttachment = theReader.ReadBytes(fileSize);
}

public void SaveAttachment(string saveLocation)
{
string fullFileName = saveLocation;
if (!fullFileName.EndsWith(Path.DirectorySeparatorChar.ToString())){
fullFileName += Path.DirectorySeparatorChar;
}

fullFileName += attachmentName;

if(File.Exists(fullFileName))
File.Delete(fullFileName);

FileStream fs = new FileStream(fullFileName, FileMode.CreateNew);
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(decodedAttachment);

bw.Close();
fs.Close();
}

public string Filename
{
get{ return attachmentName; }
}

public byte[] DecodedAttachment
{
get{ return decodedAttachment; }
}
}
}

フォームを変更する

添付ファイル コントロール、テキスト ボックス コントロール、および Button コントロールを InfoPath フォームに追加します。 これを行うには、次の手順を実行します。

  1. 使用している InfoPath のバージョンの指示を使用して、[ コントロール ] 作業ウィンドウを開きます。 

    • InfoPath 2010:InfoPathAttachmentEncoding InfoPath フォーム テンプレートの **Home **タブで、**Controls **gallery を展開します。
    • InfoPath 2007:InfoPathAttachmentEncoding InfoPath フォーム テンプレートで、**デザイン タスク **作業ウィンドウで [コントロール ] をクリックします。
  2. 使用している InfoPath のバージョンの指示を使用して、InfoPath フォームに添付ファイル コントロールを追加します。

    • InfoPath 2010:[コントロール] 作業ウィンドウの [オブジェクト] で、[添付ファイル] をクリックします。
    • InfoPath 2007: [コントロール ] 作業ウィンドウの [ ファイルと画像] で、[ 添付ファイル] をクリックします。
  3. **[添付ファイル] **コントロールを右クリックし、[ 添付ファイルのプロパティ] をクリックします。

  4. **[添付ファイルのプロパティ]**ダイアログ ボックスで、[**フィールド名**] ボックスにAttachmentField を入力し、[ OK] をクリックします。

  5. 使用している InfoPath のバージョンの指示を使用して、Text Box コントロールを InfoPath フォームに追加します。

    • InfoPath 2010: [コントロール ] 作業ウィンドウの [ 入力] で 、[ テキスト ボックス] をクリックします。
    • InfoPath 2007: [コントロール ] 作業ウィンドウの [ 標準] で 、[ テキスト ボックス] をクリックします。
  6. テキスト ボックス コントロールを右クリックし、[ テキスト ボックスのプロパティ] をクリックします。

  7. **テキスト ボックスのプロパティ **ダイアログ ボックスで、**フィールド名 **ボックスにAttachmentName を入力し、[OK] をクリック します

  8. 使用している InfoPath のバージョンの指示を使用して、InfoPath フォームに [アタッチ] ボタンを追加します。

    • InfoPath 2010: [コントロール ] 作業ウィンドウの [ オブジェクト] の [ ボタン] をクリックします。
    • InfoPath 2007: [コントロール ] 作業ウィンドウの [ 標準] の [ ボタン] をクリックします。
  9. 新しい Button コントロールを右クリックし、[ボタンの プロパティ] をクリックします。

  10. **ボタンのプロパティ **ダイアログ ボックスで、**Label **ボックスに「アタッチ」と入力し、 ID ボックスに「btnAttach」と入力して、[ フォーム コードの編集] をクリックします。

  11. コード ウィンドウの上部に移動し、次のコード行を追加します。

    using InfoPathAttachmentEncoding;
    
  12. "ここにコードを記述する" に戻り、次のコードを追加します。

     //Create an XmlNamespaceManager
     XmlNamespaceManager ns = this.NamespaceManager;
    
    //Create an XPathNavigator object for the Main data source
     XPathNavigator xnMain = this.MainDataSource.CreateNavigator();
    
    //Create an XPathNavigator object for the attachment node
     XPathNavigator xnAttNode = xnMain.SelectSingleNode("/my:myFields/my:theAttachmentField", ns);
    
    //Create an XPathNavigator object for the filename node
     XPathNavigator xnFileName = xnMain.SelectSingleNode("/my:myFields/my:theAttachmentName", ns);
    
    //Obtain the text of the filename node.
     string fileName = xnFileName.Value;
     if (fileName.Length > 0)
     {
      //Encode the file and assign it to the attachment node.
      InfoPathAttachmentEncoder myEncoder = new InfoPathAttachmentEncoder(fileName);
    
    //Check for the "xsi:nil" attribute on the file attachment node and remove it
      //before setting the value to attach the filerRemove the "nil" attribute
      if (xnAttNode.MoveToAttribute("nil", "http://www.w3.org/2001/XMLSchema-instance"))
       xnAttNode.DeleteSelf();
    
    //Attach the file
      xnAttNode.SetValue(myEncoder.ToBase64String());
     }              
    
    

InfoPath フォームに [保存] ボタンを追加する

  1. InfoPathAttachmentEncoding フォーム テンプレートに戻ります。

  2. 使用している InfoPath のバージョンの指示を使用して、[保存] ボタンを追加します。

    • InfoPath 2010: [コントロール ] 作業ウィンドウの [ オブジェクト] の [ ボタン] をクリックします。
    • InfoPath 2007: [コントロール ] 作業ウィンドウの [ 標準] の [ ボタン] をクリックします。
  3. 新しい Button コントロールを右クリックし、[ボタンの プロパティ] をクリックします。

  4. **ボタンのプロパティ **ダイアログ ボックスで、**ラベル **ボックスに「保存」と入力し、**ID **ボックスに「btnSave」と入力して、[ フォーム コードの編集] をクリックします。

  5. 次のコードを挿入します。

     //Create an XmlNamespaceManager
     XmlNamespaceManager ns = this.NamespaceManager;
    
    //Create an XPathNavigator object for the Main data source
     XPathNavigator xnMain = this.MainDataSource.CreateNavigator();
    
    //Create an XPathNavigator object for the attachment node
     XPathNavigator xnAttNode = xnMain.SelectSingleNode("/my:myFields/my:theAttachmentField", ns);
    
    //Obtain the text of the node.
     string theAttachment = xnAttNode.Value;
     if(theAttachment.Length > 0)
     {
         InfoPathAttachmentDecoder myDecoder = new InfoPathAttachmentDecoder(theAttachment);
         myDecoder.SaveAttachment(@"Path to the folder to save the attachment");
     }                                              
    
    

注:

このコードでは、添付ファイルを保存するフォルダーへのプレースホルダーパスは、ファイルを保存する場所を表します。

[保存] アイコンをクリックし、VSTA を閉じます。

フォームをテストする

このフォームでファイルを添付するには、InfoPath フォーム テンプレートが完全に信頼されている必要があります。 これを確認するには、次のいずれかの操作を実行します。

  • コード署名証明書を使用して、フォーム テンプレート ファイル (.xsn) にデジタル署名します。 これを行うと、ユーザーはフォームを開くときにフォームを信頼するように求められます。 これにより、フォームは完全に信頼されます。 そのため、完全信頼アクセス許可は Visual C# コードに付与されます。
  • インストール可能なテンプレートを作成します。

フォーム テンプレートが完全に信頼されていることを確認したら、それをテストする必要があります。 これを行うには、次の手順を実行します。

  1. 使用している InfoPath のバージョンの手順に従って、プレビュー モードでフォームを開きます。

    • InfoPath 2010 [ ホーム ] タブの [ プレビュー] をクリックします。
    • InfoPath 2007 Standardtoolbar で、[ プレビュー] をクリックします。
  2. InfoPath フォームで、テキスト ボックスに添付するファイルのパスを入力し、[ 添付] をクリックします。

    メモ [添付ファイル] コントロールをダブルクリックして、ファイルが正しくエンコードされていることを確認します。 

  3. [保存] をクリックします。

  4. "InfoPath フォームに保存ボタンを追加する" セクションのコードで指定したパスを探し、ファイルがそのフォルダーに保存されていることを確認します。 

  5. [プレビューを閉じる] をクリックします。 これでテストが終了します。