[Community Ring follow-up 2] Vista (RC1) の TxF をコードで体験する
(更新された情報を こちら に掲載しています 2007/02/23 追記)
2つ目のデモをアップします。
当日デモは致しませんでしたが、DB との同時トランザクション以外にも、トランザクションを複数作成(もしくは複数のアプリを起動するなどして複数プロセスから処理)した場合も正しく処理されません (この場合は、最初にトランザクションを作成した処理は常に勝ってしまいます)。
ですから、ご説明しました通り、インストール、移動、バックアップ、等々のプリミティブな処理の一貫性を保証するプログラムコードなどの形で活用して頂くと良いと思います。
尚、トランザクション管理用の新しい API については、以下を参照してください。(レジストリ関連は未だないようですが、Longhorn ではおそらく実装されてくるはずです。)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/file_management_functions.asp
以下、ソースを掲載します。
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using Microsoft.Win32.SafeHandles;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Transactions;
using System.EnterpriseServices;
using System.Windows.Forms;
namespace TxFProject
{
public class TranHandle
{
const ulong WRITE_DAC = (0x00040000L);
const ulong WRITE_OWNER = (0x00080000L);
const UInt32 FILE_SHARE_READ = 0x00000001;
const UInt32 FILE_SHARE_WRITE = 0x00000002;
const UInt32 FILE_SHARE_DELETE = 0x00000004;
const UInt32 FILE_ATTRIBUTE_NORMAL = 0x00000080;
const int CREATE_NEW = 1;
const int CREATE_ALWAYS = 2;
public void FireTrans(bool isCommited)
{
using (TransactionScope s = new TransactionScope())
{
SafeTransactionHandle txHandle;
IKernelTransaction kernelTx = (IKernelTransaction)TransactionInterop.GetDtcTransaction(Transaction.Current);
kernelTx.GetHandle(out txHandle);
// Update Win32 file 1
SafeFileHandle fileHandle1 = CreateFileTransacted(@"C:\TxF\hello1.txt",
(int)WRITE_DAC,
(int)(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
System.IntPtr.Zero,
CREATE_ALWAYS,
(int)FILE_ATTRIBUTE_NORMAL,
new SafeFileHandle(System.IntPtr.Zero, false),
txHandle,
System.IntPtr.Zero,
System.IntPtr.Zero);
#region FILE2
// Update Win32 file 2
SafeFileHandle fileHandle2 = CreateFileTransacted(@"C:\TxF\hello2.txt",
(int)WRITE_DAC,
(int)(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
System.IntPtr.Zero,
CREATE_ALWAYS,
(int)FILE_ATTRIBUTE_NORMAL,
new SafeFileHandle(System.IntPtr.Zero, false),
txHandle,
System.IntPtr.Zero,
System.IntPtr.Zero);
#endregion
#region DB
/*****
ここ↓は、どう頑張っても、同一トランザクションの配下に入れることはできません
(TransactionScope を RequiredNew にすれば無論動きますが、意味がありません、、、)
*****/
//// Update database
//SqlConnection conDB = new SqlConnection(@"Data Source=tsmatsuz31\SQLEXPRESS;Integrated Security=SSPI;Initial Catalog=HOL_DB");
//conDB.Open();
//SqlCommand cmdSql = new SqlCommand("insert into TestTbl (ID, Name) values (1, 'Test Data')", conDB);
//cmdSql.ExecuteNonQuery();
//conDB.Close();
#endregion
MessageBox.Show("更新完了");
if(isCommited)
s.Complete();
else
s.Dispose();
}
}
[DllImport("Kernel32.Dll",
CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Unicode)]
internal static extern SafeFileHandle CreateFileTransacted(
String lpFileName,
int dwDesiredAccess,
int dwShareMode,
IntPtr lpSecurityAttributes,
int dwCreationDisposition,
int dwFlagsAndAttributes,
SafeFileHandle hTemplateFile,
SafeTransactionHandle txHandle,
IntPtr miniVersion,
IntPtr extendedOpenInformation);
[ComImport]
[Guid("79427A2B-F895-40e0-BE79-B57DC82ED231")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IKernelTransaction
{
void GetHandle(out SafeTransactionHandle ktmHandle);
}
}
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
public sealed class SafeTransactionHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeTransactionHandle()
: base(true)
{
}
public SafeTransactionHandle(IntPtr preexistingHandle, bool ownsHandle)
: base(ownsHandle)
{
SetHandle(preexistingHandle);
}
[DllImport("Kernel32.dll", SetLastError = true)]
[ResourceExposure(ResourceScope.Machine)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
private static extern bool CloseHandle(IntPtr handle);
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
override protected bool ReleaseHandle()
{
return CloseHandle(handle);
}
}
}