/// <summary> /// Handle an image. a_bitmap is passed by reference so that this function can /// dispose and null it out to gain access to the file that's backing it. The /// calling toolkit function will never perform any action with a_bitmap after /// this function returns. /// </summary> /// <param name="a_szDg">Data group that preceeded this call</param> /// <param name="a_szDat">Data argument type that preceeded this call</param> /// <param name="a_szMsg">Message that preceeded this call</param> /// <param name="a_sts">Current status</param> /// <param name="a_bitmap">C# bitmap of the image</param> /// <param name="a_szFile">File name, if doing a file transfer</param> /// <param name="a_szTwimageinfo">data collected for us</param> /// <param name="a_abImage">a byte array of the image</param> /// <param name="a_iImageOffset">byte offset where the image data begins</param> public TWAINCSToolkit.MSG ReportImage ( string a_szTag, string a_szDg, string a_szDat, string a_szMsg, TWAINCSToolkit.STS a_sts, Bitmap a_bitmap, string a_szFile, string a_szTwimageinfo, byte[] a_abImage, int a_iImageOffset ) { // We're leaving... if (m_blClosing || (m_graphics1 == null) || (a_bitmap == null)) { return (TWAINCSToolkit.MSG.RESET); } // Let us be called from any thread... if (this.InvokeRequired) { // We need a copy of the bitmap, because we're not going to wait // for the thread to return. Be careful when using EndInvoke. // It's possible to create a deadlock situation with the Stop // button press. BeginInvoke(new MethodInvoker(delegate() { ReportImage(a_szTag, a_szDg, a_szDat, a_szMsg, a_sts, a_bitmap, a_szFile, a_szTwimageinfo, a_abImage, a_iImageOffset); })); return (TWAINCSToolkit.MSG.ENDXFER); } // Display the image... switch (m_iCurrentPictureBox) { default: case 0: LoadImage(ref m_pictureboxImage1, ref m_graphics1, ref m_bitmapGraphic1, a_bitmap); break; case 1: LoadImage(ref m_pictureboxImage2, ref m_graphics2, ref m_bitmapGraphic2, a_bitmap); break; case 2: LoadImage(ref m_pictureboxImage3, ref m_graphics3, ref m_bitmapGraphic3, a_bitmap); break; case 3: LoadImage(ref m_pictureboxImage4, ref m_graphics4, ref m_bitmapGraphic4, a_bitmap); break; case 4: LoadImage(ref m_pictureboxImage5, ref m_graphics5, ref m_bitmapGraphic5, a_bitmap); break; case 5: LoadImage(ref m_pictureboxImage6, ref m_graphics6, ref m_bitmapGraphic6, a_bitmap); break; case 6: LoadImage(ref m_pictureboxImage7, ref m_graphics7, ref m_bitmapGraphic7, a_bitmap); break; case 7: LoadImage(ref m_pictureboxImage8, ref m_graphics8, ref m_bitmapGraphic8, a_bitmap); break; } // Next picture box... if (++m_iCurrentPictureBox >= 8) { m_iCurrentPictureBox = 0; } // All done... return (TWAINCSToolkit.MSG.ENDXFER); }
/// <summary> /// Create and destroy our toolkit object, as needed... /// </summary> /// <param name="a_szDg">Data group</param> /// <param name="a_szDat">Data argument type</param> /// <param name="a_szMsg">Operation</param> private void ManageToolkit(string a_szDg, string a_szDat, string a_szMsg) { // Handle MSG_OPENDSM... if (a_szMsg == "MSG_OPENDSM") { // Init stuff... m_blClosing = false; // Validate... if (m_twaincstoolkit != null) { WriteTriplet(a_szDg, a_szDat, a_szMsg, "(already open)"); return; } // Create our image capture object... try { m_twaincstoolkit = new TWAINCSToolkit ( this.Handle, WriteOutput, ReportImage, SetMessageFilter, "TWAIN Working Group", "TWAIN Sharp", "TWAIN Sharp Test App", 2, 3, new string[] { "DF_APP2", "DG_CONTROL", "DG_IMAGE" }, "USA", "testing...", "ENGLISH_USA", 1, 0, m_checkboxUseTwain32.Checked, m_checkboxUseCallbacks.Checked, RunInUiThread, this ); } catch { WriteTriplet(a_szDg, a_szDat, a_szMsg, "(unable to start)"); m_twaincstoolkit = null; return; } WriteTriplet(a_szDg, a_szDat, a_szMsg, TWAINCSToolkit.STS.SUCCESS.ToString()); // Fix our controls... if (TWAINCSToolkit.GetPlatform() == "WINDOWS") { m_checkboxUseTwain32.Enabled = false; m_checkboxUseCallbacks.Enabled = false; } // Help the user... AutoDropdown(a_szDg, a_szDat, a_szMsg); } // Handle MSG_CLOSEDSM... else if (a_szMsg == "MSG_CLOSEDSM") { // Issue the command... WriteTriplet(a_szDg, a_szDat, a_szMsg, TWAINCSToolkit.STS.SUCCESS.ToString()); m_blClosing = true; m_twaincstoolkit.Cleanup(); m_twaincstoolkit = null; // Fix our controls... if (TWAINCSToolkit.GetPlatform() == "WINDOWS") { m_checkboxUseTwain32.Enabled = (TWAINCSToolkit.GetMachineWordBitSize() == 32); m_checkboxUseCallbacks.Enabled = true; } // Help the user... AutoDropdown(a_szDg, a_szDat, a_szMsg); } // Handle anything else... else { WriteTriplet(a_szDg, a_szDat, a_szMsg, TWAINCSToolkit.STS.BADPROTOCOL.ToString()); } }
// ================================================== // Methods // ================================================== private void InitTwain() { try { TwainToolkit = new TWAINCSToolkit ( Handle, WriteOutput, ReportImage, null, "TWAIN Working Group", "TWAIN Sharp", "TWAIN Sharp Scan App", 2, 3, new string[] { "DF_APP2", "DG_CONTROL", "DG_IMAGE" }, "USA", "testing...", "ENGLISH_USA", 1, 0, false, true ); var defaultSource = string.Empty; var sources = TwainToolkit.GetDrivers(ref defaultSource); if (!sources.Any()) { throw new Exception("TWAIN GetDrivers returned an empty list."); } ParseSources(sources); } catch (Exception error) { HandleError(Resources.ErrorCannotInitTwain, error); return; } }
/// <summary> /// Handle an image. a_bitmap is passed by reference so that this function can /// dispose and null it out to gain access to the file that's backing it. The /// calling toolkit function will never perform any action with a_bitmap after /// this function returns. /// </summary> /// <param name="a_szDg">Data group that preceeded this call</param> /// <param name="a_szDat">Data argument type that preceeded this call</param> /// <param name="a_szMsg">Message that preceeded this call</param> /// <param name="a_sts">Current status</param> /// <param name="a_bitmap">C# bitmap of the image</param> /// <param name="a_szFile">File name, if doing a file transfer</param> /// <param name="a_szTwimageinfo">data collected for us</param> /// <param name="a_abImage">a byte array of the image</param> /// <param name="a_iImageOffset">byte offset where the image data begins</param> private TWAINCSToolkit.MSG ReportImage( string a_szTag, string a_szDg, string a_szDat, string a_szMsg, TWAINCSToolkit.STS a_sts, Bitmap a_bitmap, string a_szFile, string a_szTwimageinfo, byte[] a_abImage, int a_iImageOffset ) { // Let us be called from any thread if (this.InvokeRequired) { // We need a copy of the bitmap, because we're not going to wait // for the thread to return. Be careful when using EndInvoke. // It's possible to create a deadlock situation with the Stop // button press. BeginInvoke(new MethodInvoker(delegate () { ReportImage(a_szTag, a_szDg, a_szDat, a_szMsg, a_sts, a_bitmap, a_szFile, a_szTwimageinfo, a_abImage, a_iImageOffset); })); return (TWAINCSToolkit.MSG.ENDXFER); } if (a_bitmap == null) { // Report errors, but only if the driver's indicators have // been turned off, otherwise we'll hit the user with multiple // dialogs for the same error if (!Settings.Default.ShowDriverMessages && (a_sts != TWAINCSToolkit.STS.SUCCESS)) { HandleError(string.Format("{0}: {1}", Resources.ErrorFromSource, a_sts)); } } else { AddPage(a_bitmap); } return (TWAINCSToolkit.MSG.ENDXFER); }
/////////////////////////////////////////////////////////////////////////////// // Public Functions. This is the stuff we want to expose to the // application... /////////////////////////////////////////////////////////////////////////////// #region Public Functions... /// <summary> /// Instantiate TWAIN and open the DSM. This looks like a ridiculously /// complex function, so lets talk about it for a moment. /// /// There are four groupings in the argument list (and wouldn't it be nice /// it they were all together): /// /// The Application Identity (TW_IDENTITY) /// a_szManufacturer, a_szProductFamily, a_szProductName, a_u16ProtocolMajor, /// a_u16ProtocolMinor, a_aszSupportedGroups, a_szTwcy, a_szInfo, a_szTwlg, /// a_u16MajorNum, a_u16MinorNum. /// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /// One of the goals of the TWAINWorkingGroupToolkit namespace is to make it /// unnecessary for the caller to include the TWAINWorkingGroup namespace. /// So there's no appeal to the TW_IDENTITY structure, instead it's broken /// out piecemeal. The structure has been unchanged since 1993, so I think /// we can trust that these arguments won't change. You can read about /// TW_IDENTITY in the TWAIN Specification, but essentially these arguments /// identify the application to the TWAIN DSM and the TWAIN driver. /// /// The Flags /// a_blUseLegacyDSM, a_blUseCallbacks, a_setmessagefilterdelegate /// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /// a_blUseLegacyDSM should be false on Windows and Linux and true on the /// Mac (until we get a new DSM). This causes the toolkit to invoke the /// open source DSM provided by the TWAIN Working Group, which can be found /// here: https://sourceforge.net/projects/twain-dsm/. a_blUseCallbacks /// should be true, since the callback system is easier to manage and less /// likely to cause an application's user interface to lock up while they /// are scanning (the alternative is the Windows POST message system). If /// the value is false, then a_setmessagefilterdelegate must point to a /// function that will filter Window's messages sent from the application /// to the driver. /// /// The Callback Functions /// a_writeoutputdelegate, a_reportimagedelegate /// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /// a_writeoutputdelegate is only used by the TWAINCStst application to show /// information in the status window. A regular application might find that /// useful for diagnostics, but it's not necessary, and the value can be set /// to null. a_reportimagedelegate is the really interesting function, this /// is what's called for every image while scanning. It receives both the /// metadata and the image. You'll want to carefully look at the function /// that's used for the TWAINCSscan application. /// /// Windows Cruft /// a_intptrHwnd, a_runinuithreaddelegate, a_objectRunInUiThreadDelegate /// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /// TWAIN has been around since 1992, and it's one architectural drawback /// comes from how it tied itself to the Windows message loop (which I'm /// sure seemed like a very good idea at the time). We have three functions, /// and the motivation for this is to avoid accessing System.Windows.Forms /// inside of TWAINCSToolkit, so that we can seamlessly work with other /// graphical windowing systems, such as are provided with Mono). I won't /// go into too much detail here. You must have a Form on Windows. The /// the this.Handle is passed to a_intptrHwnd, which is used by both the /// DAT_PARENT and DAT_USERINTERFACE operations. a_objectRunInUiThreadDelegate /// is the this value, itself, and is used by the a_runinuithreaddelegate to /// invoke DAT_USERINTERFACE and DAT_IMAGE*XFER calls into the form's main /// UI thread, where the Windows message loop resides. This is necessary, /// because some TWAIN driver's hook into that message loop, and will crash /// or hang, if not properly invoked from that thread. If you run into this /// kind of situation, take of note of the operation that caused the problem, /// and if it's clearly an invokation issue it can be fixed by adding new /// TWAIN CS operations to this kind of callback route. As for the function /// itself, just copy the RunInThreadUi function from TWAINCSscan, and use /// it as-is. /// /// </summary> /// <param name="a_intptrHwnd">Parent window (needed for Windows)</param> /// <param name="a_writeoutputdelegate">Optional text output callback</param> /// <param name="a_reportimagedelegate">Optional report image callback</param> /// <param name="m_setmessagefilterdelegate">Optional message filter callback</param> /// <param name="a_szManufacturer">Application manufacturer</param> /// <param name="a_szProductFamily">Application family</param> /// <param name="a_szProductName">Name of the application</param> /// <param name="a_u16ProtocolMajor">TWAIN protocol major (doesn't have to match TWAINH.CS)</param> /// <param name="a_u16ProtocolMinor">TWAIN protocol minor (doesn't have to match TWAINH.CS)</param> /// <param name="a_aszSupportedGroups">Bitmask of DG_ flags</param> /// <param name="a_szTwcy">Application's country code</param> /// <param name="a_szInfo">Info about the application</param> /// <param name="a_szTwlg">Application's language</param> /// <param name="a_u16MajorNum">Application's major version</param> /// <param name="a_u16MinorNum">Application's minor version</param> /// <param name="a_blUseLegacyDSM">The the legacy DSM (like TWAIN_32.DLL)</param> /// <param name="a_blUseCallbacks">Use callbacks (preferred)</param> /// <param name="a_runinuithreaddelegate">delegate for running in the UI thread</param> /// <param name="a_objectRunInUiThreadDelegate">the form from that thread</param> public TWAINCSToolkit ( IntPtr a_intptrHwnd, WriteOutputDelegate a_writeoutputdelegate, ReportImageDelegate a_reportimagedelegate, SetMessageFilterDelegate a_setmessagefilterdelegate, string a_szManufacturer, string a_szProductFamily, string a_szProductName, ushort a_u16ProtocolMajor, ushort a_u16ProtocolMinor, string[] a_aszSupportedGroups, string a_szTwcy, string a_szInfo, string a_szTwlg, ushort a_u16MajorNum, ushort a_u16MinorNum, bool a_blUseLegacyDSM, bool a_blUseCallbacks, TWAINCSToolkit.RunInUiThreadDelegate a_runinuithreaddelegate, Object a_objectRunInUiThreadDelegate ) { TWAIN.STS sts; uint u32SupportedGroups; // Init stuff... m_intptrHwnd = a_intptrHwnd; if (a_writeoutputdelegate == null) { WriteOutput = WriteOutputStub; } else { WriteOutput = a_writeoutputdelegate; } ReportImage = a_reportimagedelegate; SetMessageFilter = a_setmessagefilterdelegate; m_szImagePath = null; m_iImageCount = 0; m_runinuithreaddelegate = a_runinuithreaddelegate; m_objectRunInUiThreadDelegate = a_objectRunInUiThreadDelegate; // Convert the supported groups from strings to flags... u32SupportedGroups = 0; foreach (string szSupportedGroup in a_aszSupportedGroups) { TWAIN.DG dg = (TWAIN.DG)Enum.Parse(typeof(TWAIN.DG), szSupportedGroup.Remove(0, 3)); if (Enum.IsDefined(typeof(TWAIN.DG), dg)) { u32SupportedGroups |= (uint)dg; } } // Instantiate TWAIN, and register ourselves... m_twain = new TWAIN ( a_szManufacturer, a_szProductFamily, a_szProductName, a_u16ProtocolMajor, a_u16ProtocolMinor, u32SupportedGroups, (TWAIN.TWCY)Enum.Parse(typeof(TWAIN.TWCY), a_szTwcy), a_szInfo, (TWAIN.TWLG)Enum.Parse(typeof(TWAIN.TWLG), a_szTwlg), a_u16MajorNum, a_u16MinorNum, a_blUseLegacyDSM, a_blUseCallbacks, DeviceEventCallback, ScanCallback, RunInUiThread, m_intptrHwnd ); // Store some values... m_blUseCallbacks = a_blUseCallbacks; // Our default transfer mechanism... m_twsxXferMech = TWAIN.TWSX.NATIVE; // Our default file transfer info... m_twsetupfilexfer = default(TWAIN.TW_SETUPFILEXFER); m_twsetupfilexfer.Format = TWAIN.TWFF.TIFF; if (TWAIN.GetPlatform() == TWAIN.Platform.WINDOWS) { m_twsetupfilexfer.FileName.Set(Path.GetTempPath() + "img"); } else if (TWAIN.GetPlatform() == TWAIN.Platform.LINUX) { m_twsetupfilexfer.FileName.Set(Path.GetTempPath() + "img"); } else if (TWAIN.GetPlatform() == TWAIN.Platform.MACOSX) { m_twsetupfilexfer.FileName.Set("/var/tmp/img"); } else { Log.Assert("Unsupported platform..." + TWAIN.GetPlatform()); } // We've not been in the scan callback yet... m_blScanStart = true; // Open the DSM... try { sts = m_twain.DatParent(TWAIN.DG.CONTROL, TWAIN.MSG.OPENDSM, ref m_intptrHwnd); } catch (Exception exception) { Log.Error("OpenDSM exception: " + exception.Message); sts = TWAIN.STS.FAILURE; } if (sts != TWAIN.STS.SUCCESS) { Log.Error("OpenDSM failed..."); Cleanup(); throw new Exception("OpenDSM failed..."); } }
/////////////////////////////////////////////////////////////////////////////// // Public Methods... /////////////////////////////////////////////////////////////////////////////// #region Public Methods... /// <summary> /// Our constructor... /// </summary> public FormScan() { // Build our form... InitializeComponent(); // Open the log in our working folder, and say hi... Log.Open("TWAINCSScan", ".", 1); Log.Info("TWAINCSScan v" + System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString()); // Init other stuff... m_blIndicators = false; m_blExit = false; m_iUseBitmap = 0; this.FormClosing += new FormClosingEventHandler(FormScan_FormClosing); // Create our image capture object... try { m_twaincstoolkit = new TWAINCSToolkit ( this.Handle, WriteOutput, ReportImage, null, "TWAIN Working Group", "TWAIN Sharp", "TWAIN Sharp Scan App", 2, 3, new string[] { "DF_APP2", "DG_CONTROL", "DG_IMAGE" }, "USA", "testing...", "ENGLISH_USA", 1, 0, false, true, RunInUiThread, this ); } catch { m_twaincstoolkit = null; m_blExit = true; MessageBox.Show ( "Unable to start, the most likely reason is that the TWAIN\n" + "Data Source Manager is not installed on your system.\n\n" + "An internet search for 'TWAIN DSM' will locate it and once\n" + "installed, you should be able to proceed.\n\n" + "You can also try the following link:\n" + "http://sourceforge.net/projects/twain-dsm/", "Error Starting TWAIN CS Scan" ); return; } // Init our picture box... InitImage(); // Init our buttons... SetButtons(EBUTTONSTATE.CLOSED); }
/// <summary> /// Handle an image. a_bitmap is passed by reference so that this function can /// dispose and null it out to gain access to the file that's backing it. The /// calling toolkit function will never perform any action with a_bitmap after /// this function returns. /// </summary> /// <param name="a_szDg">Data group that preceeded this call</param> /// <param name="a_szDat">Data argument type that preceeded this call</param> /// <param name="a_szMsg">Message that preceeded this call</param> /// <param name="a_sts">Current status</param> /// <param name="a_bitmap">C# bitmap of the image</param> /// <param name="a_szFile">File name, if doing a file transfer</param> /// <param name="a_szTwimageinfo">data collected for us</param> /// <param name="a_abImage">a byte array of the image</param> /// <param name="a_iImageOffset">byte offset where the image data begins</param> private TWAINCSToolkit.MSG ReportImage ( string a_szTag, string a_szDg, string a_szDat, string a_szMsg, TWAINCSToolkit.STS a_sts, Bitmap a_bitmap, string a_szFile, string a_szTwimageinfo, byte[] a_abImage, int a_iImageOffset ) { // We're leaving... if (m_graphics1 == null) { return (TWAINCSToolkit.MSG.RESET); } // Let us be called from any thread... if (this.InvokeRequired) { // We need a copy of the bitmap, because we're not going to wait // for the thread to return. Be careful when using EndInvoke. // It's possible to create a deadlock situation with the Stop // button press. BeginInvoke(new MethodInvoker(delegate() { ReportImage(a_szTag, a_szDg, a_szDat, a_szMsg, a_sts, a_bitmap, a_szFile, a_szTwimageinfo, a_abImage, a_iImageOffset); })); return (TWAINCSToolkit.MSG.ENDXFER); } // We're processing end of scan... if (a_bitmap == null) { // Report errors, but only if the driver's indicators have // been turned off, otherwise we'll hit the user with multiple // dialogs for the same error... if (!m_blIndicators && (a_sts != TWAINCSToolkit.STS.SUCCESS)) { MessageBox.Show("End of session status: " + a_sts); } // Get ready for the next scan... SetButtons(EBUTTONSTATE.OPEN); return (TWAINCSToolkit.MSG.ENDXFER); } // Display the image... if (m_iUseBitmap == 0) { m_iUseBitmap = 1; LoadImage(ref m_pictureboxImage1, ref m_graphics1, ref m_bitmapGraphic1, a_bitmap); } else { m_iUseBitmap = 0; LoadImage(ref m_pictureboxImage2, ref m_graphics2, ref m_bitmapGraphic2, a_bitmap); } // All done... return (TWAINCSToolkit.MSG.ENDXFER); }
/// <summary> /// We're being closed, clean up nicely... /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void FormScan_FormClosing(object sender, FormClosingEventArgs e) { // Get rid of the toolkit... if (m_twaincstoolkit != null) { m_twaincstoolkit.Cleanup(); m_twaincstoolkit = null; } // This will prevent ReportImage from doing anything as we close... m_graphics1 = null; }
/////////////////////////////////////////////////////////////////////////////// // Public Methods... /////////////////////////////////////////////////////////////////////////////// #region Public Methods... /// <summary> /// Our constructor... /// </summary> /// <param name="a_twaincstool"></param> public FormSetup(ref TWAINCSToolkit a_twaincstoolkit, string a_szProductDirectory) { TWAINCSToolkit.STS sts; string szStatus; string szCapability; string szUsrUiSettings; // Init stuff... InitializeComponent(); // More init stuff... this.FormClosing += new FormClosingEventHandler(FormSetup_FormClosing); // Init more stuff (the order matters). ApplicationData means the following: // Windows: C:\Users\USERNAME\AppData\Roaming (or C:\Documents and Settings\USERNAME\Application Data on XP) // Linux: /home/USERNAME/.config (or /root/.config for superuser) // Mac OS X: /Users/USERNAME/.config (or /var/root/.config for superuser) m_twaincstoolkit = a_twaincstoolkit; m_szTwainscanFolder = Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal),"twain"),"twaincsscan"); m_szSettingsFolder = Path.Combine(m_szTwainscanFolder,"settings"); m_szSettingsFolder = Path.Combine(m_szSettingsFolder, a_szProductDirectory); if (!Directory.Exists(m_szTwainscanFolder)) { try { Directory.CreateDirectory(m_szTwainscanFolder); } catch { m_szTwainscanFolder = Directory.GetCurrentDirectory(); } } // Restore values... m_textboxFolder.Text = RestoreFolder(); m_textboxUseUiSettings.Text = ""; // Make sure we prime the value... m_twaincstoolkit.SetImagePath(m_textboxFolder.Text,0); // Check for support of Custom DS Data... szStatus = ""; szCapability = "CAP_CUSTOMDSDATA"; sts = m_twaincstoolkit.Send("DG_CONTROL", "DAT_CAPABILITY", "MSG_GETCURRENT", ref szCapability, ref szStatus); if ((sts != TWAINCSToolkit.STS.SUCCESS) || !szCapability.EndsWith(",1")) { m_labelUseUiSettings.Enabled = false; m_textboxUseUiSettings.Enabled = false; m_buttonSaveUiSettings.Enabled = false; m_buttonUseUiSettings.Enabled = false; } // Restore the last saved snapshot... else { m_textboxUseUiSettings.Text = RestoreSetting(); if (m_textboxUseUiSettings.Text != "") { szUsrUiSettings = Path.Combine(m_szSettingsFolder, m_textboxUseUiSettings.Text); if (File.Exists(szUsrUiSettings)) { m_twaincstoolkit.RestoreSnapshot(szUsrUiSettings); } else { m_textboxUseUiSettings.Text = ""; } } } }