Click here to Skip to main content
15,885,216 members
Articles / Programming Languages / C#
Article

Windows Vista TxF/TxR

Rate me:
Please Sign up or sign in to vote.
4.63/5 (11 votes)
30 Jan 20074 min read 72.2K   403   16   9
TxF and TxR are another great Vista technology that allows you to manipulate files and the registry in a transacted way in concert with other transactional operations on the system or the network
Sample image

Introduction

TxF and TxR are another great Vista technology that allows you to manipulate files and the registry in a transacted way, in concert with other transactional operations on the system or the network. The goal of this article is to show some key players and basic approaches in the TxF/TxR world, and also using KTM with the System.Transactions namespace.

KTM

NTFS and the Registry are now full members in the rich Windows transactional infrastructure. Create, Delete, and Update files and keys with the same atomicity, consistency, isolation, and durability that you get with SQL.

KTM stands for Kernel Transaction Manager. The word kernel, only refers to the fact the KTM's transaction engine is in the kernel. This doesn't imply the transaction can only run in kernel mode (i.e. KTM-transactions can be used in kernel and user mode) nor does it mean the transaction would be machine-local (i.e. the transaction is DTC-able).
On Vista , the KTM is in charge of TxF (Transactional NTFS) and TxR (Transactional Registry).

Advantages of Transactions

Transactions are about ACID: atomicity, consistency, isolation and durability.

  • Atomicity: Reduce the number of coding errors in exception handlers.
  • Isolation: Consistent view of data even if another thread is updating .
  • Consistent: Reduced software induced data corruption.
  • Durable: When commit completes, the change will happen even if there is a system failure.

ACID allow us to atomically coordinate file system operations with :

  • Other File System Operations
  • Registry Operations
  • Database Operations
  • Read-Committed Isolation
  • Ensure Data Consistency

What does TxF/TxR Provides

Create more reliable applications by ensuring atomic operations and consistent file data; Eases test burden by reducing the number of error conditions to test; Easy programming model which allows modification of existing applications with minimal changes; Assist multi-user environments by providing isolation.

How to use TxF

A transacted change is not seen by the other transactions unless the transaction is in progress.
TxF supports the ability to concurrently read a snapshot of a file even while it is locked by a transaction when one or more changes are being made.


When a transacted operation modifies a file, that file is locked for the duration of the transaction for generic write access. No other writers outside of this transaction can access this file. Normal sharing modes apply to all file users.

TxF File Handles

Transactional NTFS (TxF) binds a file handle to a transaction. For operations that work on a handle, the actual function does not change. For file operations that take a name, there are explicit transacted functions for these operations. For example, instead of calling CreateFile, call CreateFileTransacted. This creates a transacted file handle, which can then be used for all file operations requiring a handle. All operations using this handle are transacted operations. After a transaction is completed, any transacted file handles that are associated with that transaction are no longer usable.

Accessing Vista Transaction API

We need to use Interop to access Vista API

C#
[StructLayout(LayoutKind.Sequential)] 
public struct SECURITY_ATTRIBUTES { 
  int nLength; 
  IntPtr lpSecurityDescriptor; 
  int bInheritHandle;
}
 
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
public static extern bool CloseHandle(IntPtr handle); 
 
[DllImport("Ktmw32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
public static extern bool CommitTransaction(IntPtr transaction); 
 
[DllImport("Ktmw32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
public static extern bool RollbackTransaction(IntPtr transaction); 
 
[DllImport("Ktmw32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
public static extern IntPtr CreateTransaction( 
         SECURITY_ATTRIBUTES securityAttributes, 
         IntPtr guid, int options, int isolationLevel, int isolationFlags, 
         int milliSeconds, string description
); 

This small peace of code give us access to Create Transactions using low level windows API.

We still need to create the "Invoke" for the Transacted methods that we want to use. These methods are described in the MSDN site. I've written a small class that implements the managed code interface for the following methods:

  • CreateFileTransacted
  • DeleteFileTransacted
  • CreateHardLinkTransacted
  • GetCompressedFileSizeTransacted
  • GetFileAttributesTransacted
  • SetFileAttributesTransacted
  • GetLongPathNameTransacted
  • MoveFileTransacted
  • CopyFileTransacted
  • CreateDirectoryTransacted
  • RemoveDirectoryTransacted
  • RegDeleteKeyTransacted
  • RegCreateKeyTransacted
  • RegOpenKeyTransacted

Using TxF

Basically we need to create a transaction, use a Method (transactional) to perform an operation and finally commit the transaction. In the following peace of code I'll demonstrate the opening of a file in a transactional way.

C#
// Create the transaction using the API
IntPtr tx = MCKTM.CreateTransaction(new MCKTM.SECURITY_ATTRIBUTES(),
                                    IntPtr.Zero, 0, 0, 0, 0, null);

System.Text.StringBuilder sb = new StringBuilder(300);

// Opening the file...
Microsoft.Win32.SafeHandles.SafeFileHandle fh =
               MCKTM.CreateFileTransacted(@"c:\Test.txt",
               System.IO.FileAccess.Read,
               System.IO.FileShare.Read,
               new MCKTM.SECURITY_ATTRIBUTES(),
               System.IO.FileMode.Open, (new MCKTM.EFileAttributes()),
               IntPtr.Zero, tx, IntPtr.Zero, IntPtr.Zero);

if (fh != null) {
 // Passing to a file stream
 System.IO.FileStream fs = new System.IO.FileStream(fh,
                                System.IO.FileAccess.Read);
 ...
 ...
 fs.Close();
 //Commit the transaction
 MCKTM.CommitTransaction(tx);
} else {
 // Failed!!  Roolback
 MCKTM.RollbackTransaction(tx);
}

// Close
MCKTM.CloseHandle(tx);

Using TxR

Using Transactional Registry Operations is quite similar to TxF.

C#
 ...
 string key1 = "RegKey_01";
 ...
 
 // Create the transaction using the API
 IntPtr tx = MCKTM.CreateTransaction(new MCKTM.SECURITY_ATTRIBUTES(),  
                                     IntPtr.Zero, 0, 0, 0, 0, null); 
 
 bool rollback = false;
 if (MCKTM.RegDeleteKeyTransacted(MCKTM.HKEY_CURRENT_USER, key1, 
                MCKTM.RegSam.WOW64_32Key, 0, tx, IntPtr.Zero) != 0)
   rollback = true;
 
if (!rollback)
  //Commit the transaction
  MCKTM.CommitTransaction(tx); 
else
  // Failed!!  Roolback
  MCKTM.RollbackTransaction(tx); 
 
 // Close
 MCKTM.CloseHandle(tx); 

Using System.Transaction with DTC.

What's the difference between using KTM and DTC ?

If you start a transaction in .Net and work on a file in NTFS in that transaction you don't pay for the DTC overhead (process switch). DTC automatically gets enlisted in the transaction if non-kernel resources like SQL get included in the transaction.
This happens seamlessly from the application's point of view. KTM is a fairly lightweight transaction manager and is designed to serve the needs of the kernel resources directly, as well as interface with DTC for broad transaction support.

Ok, so you saw how to interact with the KTM in a very low level way through interop. Basically, we did deal with the transaction directly instead of relying on the System.Transactions namespace. Now I'll demonstrated how to do a transactional file delete, but this time using System.Transactions and the Distributed Transaction Coordinator (DTC).

Basically we want to :

C#
using (TransactionScope ts = new TransactionScope()) {
 DeleteFile(file1); 
 DeleteFile(file2); 
 tx.Complete(); 
}

Remember, this is useful because we might want to make a transaction spanning across TxF ... for instance, SQL Server database operations...

  1. Create some DeleteFile method
  2. In that method, see whether we are in a transaction scope or not (using Transaction.Current).
  3. If a transaction is in flight, we need to derive the KTM transaction handle from it (which is the most tricky part) and use it to call the transacted file delete function.
  4. Call the DeleteFile method inside a TransactionScope to make it transactional.

Lets write the DeleteFile (transacted) :

C#
// The tlbimp-like "thing" derived from transact.h (see Windows SDK).
// Basically it's an import of a COM interface with a specified GUID, 
// that derives from our pre-.NET friend IUnknown 
[ComImport] 
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
[Guid("79427A2B-F895-40e0-BE79-B57DC82ED231")] 
internal interface IKernelTransaction { 
         void GetHandle([Out] out IntPtr handle); 
} 
 
void DeleteFile(string file) { 
         
 // Is There a transaction on  DTC ??
 if (Transaction.Current != null) { 
  // Get the current transaction from DTC
  IKernelTransaction tx = 
   (IKernelTransaction)TransactionInterop.GetDtcTransaction(
                                                Transaction.Current); 
  IntPtr txh; 
                 
  // Transform
  tx.GetHandle(out txh); 
                 
  // If no success... trow exception.
  if (txh == IntPtr.Zero) 
    throw new Exception(); 
                          
  // If cant delete file (transacted operation)... trow exception.
  if (!DeleteFileTransacted(file, txh)) 
    throw new Exception(); 
 
  // Must close handle            
  CloseHandle(txh); 
 } else { 
  // No transaction on DTC... just delete file           
  File.Delete(file); 
 } 
} 


I've written a wrapper called GetTransactionFromDTC() that substitutes the (IKernelTransaction).

All you need to do is :

C#
void DeleteFile(string file) {          
// Is There a transaction on DTC ??
IntPtr tx = MCKTM.GetTransactionFromDTC();
if (tx!=IntPtr.Zero) { 
  if (!DeleteFileTransacted(file, txh)) 
   // If we cant delete file (transacted operation)... trow exception.
   throw new Exception(); 
 
   // Must close handle           
   CloseHandle(txh); 
  } else { 
    // No transaction    on DTC... just delete file                
   File.Delete(file); 
  } 
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Portugal Portugal
I first started in 1982, teaching myself Z80 assembler and BASIC.

I'm a customer engineer, working in software development industry.

I live in a small town in Portugal called BRAGA.

My favourite programming language is Perl.

I've a strong background in ANSI C, Java, C#,VB.NET, Linux, Mysql, Oracle, SQL Server, Web Development (JSP, ASP, CGI, PHP), ... and of course PERL Smile | :)

I'm always interested in solve complex problems, but unfortunely I don’t have much time to spent on research of what I consider interesting … maybe some day …

Comments and Discussions

 
GeneralSome Questions Pin
dennestorres18-Feb-07 10:02
dennestorres18-Feb-07 10:02 
GeneralRe: Some Questions Pin
inginheiiro18-Feb-07 23:12
inginheiiro18-Feb-07 23:12 
Tanks Smile | :)

for file writting (FileStream), try this:

IntPtr tx = MCKTM.GetTransactionFromDTC();
..
...

Microsoft.Win32.SafeHandles.SafeFileHandle handle=
MyFile.txt", System.IO.FileAccess.Write, System.IO.FileShare.Write, new MCKTM.SECURITY_ATTRIBUTES(), System.IO.FileMode.Create, new MCKTM.EFileAttributes(), IntPtr.Zero, tx, IntPtr.Zero, IntPtr.Zero);
System.IO.FileStream fs = new System.IO.FileStream(handle, System.IO.FileAccess.Write);
...
...
fs.Close();




I used to have a life ... but i bought a programmable machine in 1982 ...

QuestionRe: Some Questions Pin
nd127914-Jul-09 8:09
nd127914-Jul-09 8:09 
QuestionPInvokeStackImbalance error whilst executing on my Vista machine Pin
paoloden10-Feb-07 0:51
paoloden10-Feb-07 0:51 
AnswerRe: PInvokeStackImbalance error whilst executing on my Vista machine Pin
inginheiiro11-Feb-07 10:59
inginheiiro11-Feb-07 10:59 
JokeBom artigo! Pin
CarlosMMartins6-Feb-07 3:14
CarlosMMartins6-Feb-07 3:14 
GeneralRe: Bom artigo! Pin
inginheiiro6-Feb-07 3:19
inginheiiro6-Feb-07 3:19 
GeneralGreat Article Pin
moebious33346-Feb-07 2:26
moebious33346-Feb-07 2:26 
GeneralRe: Great Article Pin
inginheiiro6-Feb-07 2:47
inginheiiro6-Feb-07 2:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.