Painful, painful, painful.
That was my experience when a WPF application I was creating would display a MessageBox on startup. For efficiency many things were going on simultaneously, and most was tripped off with Dispatcher.BeginInvoke. If something needed user interaction at startup, a MessageBox would display to get the user's attention. The problem was, it was not modal, so the user would see the MessageBox flash and disappear, with the default value selected (which was very problematic).
A google search finally revealed the answer. When using Dispatcher.Invoke, you need to pass the owning window to MessageBox:
MessageBox.Show(this, "message");
Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts
Monday, March 4, 2013
Tuesday, April 17, 2012
Perceived Types
Never could figure this one out complete. We have an application that looks in the ClassesRoot Registry for the extension of a file, looking for the "PerceivedType" entry, and rendering an image if the PerceivedType is "image". The problem for this particular computer was that its initial configuration was bad, and it had no extensions configured to image. No idea why, nor how to automatically fix it or prevent it going forward.
Simple solution was to create a Registry merge file that included all extensions and added the "PerceivedType"="image" to all of them. However, I stumbled onto a Windows Shell API call that would first check some hard-coded extensions for their perceived type, then check the registry, so there was potential that if our application used this call, AssocGetPerceivedType, the problem may not have surfaced in the first place.
But I could not find an example of the call defined in C# anywhere. What a pain! You mean no one has written C# that needs this call???????
I found C declaration for the call:
HRESULT AssocGetPerceivedType(
__in PCWSTR pszExt,
__out PERCEIVED *ptype,
__out PERCEIVEDFLAG *pflag,
__out_opt PWSTR *ppszType
);
Now the question was, how to get it to C#?
It wasn't too hard, but did take some digging. Below is the full code I used to get the perceived type of a file. Simply check the returned value from the GetPerceivedType function below, passing the extension:
[DllImport("Shlwapi", EntryPoint = "AssocGetPerceivedType")]
private static extern int AssocGetPerceivedType(IntPtr extension, out IntPtr PERCEIVED, out IntPtr flag, out IntPtr PerceivedType);
public string GetPerceivedType(string extension)
{
IntPtr result = IntPtr.Zero;
IntPtr dummy = IntPtr.Zero;
IntPtr intPtr_aux = Marshal.StringToHGlobalUni(extension);
AssocGetPerceivedType(intPtr_aux, out dummy, out dummy, out result);
string s = Marshal.PtrToStringAuto(result);
return s;
}
Labels:
C#,
PerceivedType
Tuesday, January 10, 2012
Filter for all supported Image file types
Nifty little trick: for the OpenFileDialog, I want to set a filter for all Image
file types supported by the PC, including ones that haven’t been invented yet.
My code will load it into some sort of Image control for displaying. I could
manually set my filter to something like “*.jpg;*.png”, etc., but then I’d have
to update it whenever a new format was introduced, and some PCs may support
types not supported by others, due to what has been installed on the PC.
This code below solves this problem. It uses the MIME types that are configured for the PC, as defined in the Windows Registry. Nice and simple solution.
This code below solves this problem. It uses the MIME types that are configured for the PC, as defined in the Windows Registry. Nice and simple solution.
public static string GetImageFormatsFileFilter()
{
string retVal= "*" + string.Join(";*", SupportedImageFormats());
return retVal;
}
public static string[] SupportedImageFormats()
{
List retVal = new List();
RegistryKey BaseKey = Registry.ClassesRoot.OpenSubKey("MIME").OpenSubKey("Database").OpenSubKey("Content Type");
foreach (string subkey in BaseKey.GetSubKeyNames())
{
if (subkey.ToUpperInvariant().StartsWith("IMAGE/"))
{
string ext = (string)BaseKey.OpenSubKey(subkey).GetValue("Extension");
if (ext != null && !retVal.Contains(ext.ToUpperInvariant()))
{
retVal.Add(ext.ToUpperInvariant());
}
}
}
return retVal.ToArray();
}
Tuesday, December 8, 2009
Updating WPF window from background thread
I like to do things in the background--you know, you've got a long-running process, so you don't want to bother the user while it runs.
But you want to notify the user when the process is done. Trouble is, since the background process is running in a different thread from the user interface, the process crashes if you make any attempt to update the user interface directly.
Here's some sample code to solve this with the Dispatcher--kind of well known, but nice to document anyhow:
void UpdateText(string text)
{
if (this.Dispatcher != System.Windows.Threading.Dispatcher.CurrentDispatcher)
{
this.Dispatcher.Invoke(new Action(Update), text);
}
else
{
this.sampleTextBox.Text = text;
}
}
But you want to notify the user when the process is done. Trouble is, since the background process is running in a different thread from the user interface, the process crashes if you make any attempt to update the user interface directly.
Here's some sample code to solve this with the Dispatcher--kind of well known, but nice to document anyhow:
void UpdateText(string text)
{
if (this.Dispatcher != System.Windows.Threading.Dispatcher.CurrentDispatcher)
{
this.Dispatcher.Invoke(new Action
}
else
{
this.sampleTextBox.Text = text;
}
}
Labels:
C#,
dispatcher,
thread,
WPF
Monday, December 7, 2009
C# Inheritance, Typecasting, and Reflection
Did you know that an inherited class cannot be cast into its base class so that reflection will think it's working with the base class?
This proved a minor nuisance as the code had a simplistic work-around, but this might not always be the case.
Below is an example of what I'm talking about:
using System.Reflection;
public static class UtilityClass
{
public static object GetResult(object workClass)
{
string ResultingClassName = "Result" + workClass.GetType().ToString();
Type provider = Type.GetType(ClassName, true);
ConstructorInfo constructor = provider.GetConstructor(new Type[0]);
return constructor.Invoke(new object[0]);
}
}
public class ResultClass
{
public ResultClass()
{
}
}
public class Class
{
public ResultClass GetResult()
{
return (ResultClass)UtilityClass.GetResult(this);
}
}
public class ChildClass : Class
{
public void DoTest()
{
ResultClass x = ((Class)this).GetResult();
}
}
The above code will fail with an exception when DoTest() in ChildClass is called, because it will try to create ResultChildClass, which does not exist. No matter how you cast, you can't get this to work, because the GetResult method of UtilityClass, using Reflection, will always identify the object for what it really is.
In my case, the solution was to simply create a new "Class" object and copy the base of the ChildClass object into it, then call the "GetResult" method to get my "ResultClass".
This proved a minor nuisance as the code had a simplistic work-around, but this might not always be the case.
Below is an example of what I'm talking about:
using System.Reflection;
public static class UtilityClass
{
public static object GetResult(object workClass)
{
string ResultingClassName = "Result" + workClass.GetType().ToString();
Type provider = Type.GetType(ClassName, true);
ConstructorInfo constructor = provider.GetConstructor(new Type[0]);
return constructor.Invoke(new object[0]);
}
}
public class ResultClass
{
public ResultClass()
{
}
}
public class Class
{
public ResultClass GetResult()
{
return (ResultClass)UtilityClass.GetResult(this);
}
}
public class ChildClass : Class
{
public void DoTest()
{
ResultClass x = ((Class)this).GetResult();
}
}
The above code will fail with an exception when DoTest() in ChildClass is called, because it will try to create ResultChildClass, which does not exist. No matter how you cast, you can't get this to work, because the GetResult method of UtilityClass, using Reflection, will always identify the object for what it really is.
In my case, the solution was to simply create a new "Class" object and copy the base of the ChildClass object into it, then call the "GetResult" method to get my "ResultClass".
Labels:
C#,
cast,
Reflection
Wednesday, September 30, 2009
WIA in C# Redux: for Vista!
Of all the insanity! The scanning code I posted earlier does not work with the default configuration of Vista! Vista does not have the wiascr.dll file. However, it does have wiaaut.dll. Code I found at http://www.eggheadcafe.com/community/aspnet/2/76650/heres-some-sample-code.aspx finally gave me the answer after bashing my head around. It was easy to find code that worked for a WebCam, but nearly impossible to find code that worked for the scanner I was using. I guess no one out there uses scanners. Anyway, here's the modified code. Note that I added a ScannerException class--this just inherits the Exception class--nothing special about it:
///
/// This is a simple wrapper around WIA.
///
public class Scanner
{
public class AcquireEventArgs : EventArgs
{
public Image Image { get; internal set; }
}
WIA.DeviceManager manager = new WIA.DeviceManagerClass();
///
/// Acquires the images.
///
public void AcquireImages()
{
WIA.CommonDialogClass diag = new WIA.CommonDialogClass();
System.Object Object1 = null;
System.Object Object2 = null;
WIA.Device dev = null;
try
{
dev = diag.ShowSelectDevice(WIA.WiaDeviceType.UnspecifiedDeviceType, true, false);
}
catch (Exception ex)
{
if (ex.Message.EndsWith("00153.") || ex.Message.EndsWith("21006A."))
{
throw new ScannerException("Scanner Not connected", ex);
}
else
{
throw new ScannerException("Scanner problem", ex);
}
}
if (dev != null)
{
WIA.Item Item1 = ItemObjectReturnedFromInitializingScanner(ref dev);
WIA.ImageFile Image1 = new WIA.ImageFile();
WIA.ImageProcess ImageProcess1 = new WIA.ImageProcess();
Object1 = (Object)"Convert";
ImageProcess1.Filters.Add(ImageProcess1.FilterInfos.get_Item(ref Object1).FilterID, 0);
Object1 = (Object)"FormatID";
Object2 = (Object)WIA.FormatID.wiaFormatTIFF;
ImageProcess1.Filters[1].Properties.get_Item(ref Object1).set_Value(ref Object2);
Object1 = (Object)"Compression";
Object2 = (Object)"CCITT4";
ImageProcess1.Filters[1].Properties.get_Item(ref Object1).set_Value(ref Object2);
Object1 = null;
Object2 = null;
try
{
WIA.ImageFile imagefile = Item1.Transfer(WIA.FormatID.wiaFormatTIFF) as WIA.ImageFile;
if (ImageScanned != null)
{
AcquireEventArgs e = new AcquireEventArgs();
using (MemoryStream ms = new MemoryStream((byte[])imagefile.FileData.get_BinaryData()))
{
e.Image = new Bitmap(ms);
}
ImageScanned(this, e);
}
}
catch (Exception ex)
{
throw new ScannerException("Problem with Scanner", ex);
}
}
}
private WIA.Item ItemObjectReturnedFromInitializingScanner(ref WIA.Device Scanner)
{
WIA.Item Item1 = null;
Object Object1 = null;
Object Object2 = null;
Int32 DPI = 200;
foreach (WIA.Item CurrentItem in Scanner.Items) // 'Scanner settings.
{
Item1 = CurrentItem;
try
{
Object1 = (Object)"6146";
Object2 = (Object)4;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6147";
Object2 = (Object)DPI;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6148";
Object2 = (Object)DPI;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6149";
Object2 = (Object)0;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6150";
Object2 = (Object)0;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6151";
Object2 = (Object)(8.5 * DPI);
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6152";
Object2 = (Object)(11.5 * DPI);
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
foreach (WIA.Property Prop in Scanner.Properties)
{
if (Prop.PropertyID == 3088) //
{
try
{
Object1 = (Object)5;
Prop.set_Value(ref Object1); //'This is my effort to enforce duplex. I
}
catch (Exception) { }
}
}
}
Object1 = null;
Object2 = null;
return Item1;
}
///
/// Occurs when [image scanned].
///
public event EventHandler ImageScanned;
}
///
/// This is a simple wrapper around WIA.
///
public class Scanner
{
public class AcquireEventArgs : EventArgs
{
public Image Image { get; internal set; }
}
WIA.DeviceManager manager = new WIA.DeviceManagerClass();
///
/// Acquires the images.
///
public void AcquireImages()
{
WIA.CommonDialogClass diag = new WIA.CommonDialogClass();
System.Object Object1 = null;
System.Object Object2 = null;
WIA.Device dev = null;
try
{
dev = diag.ShowSelectDevice(WIA.WiaDeviceType.UnspecifiedDeviceType, true, false);
}
catch (Exception ex)
{
if (ex.Message.EndsWith("00153.") || ex.Message.EndsWith("21006A."))
{
throw new ScannerException("Scanner Not connected", ex);
}
else
{
throw new ScannerException("Scanner problem", ex);
}
}
if (dev != null)
{
WIA.Item Item1 = ItemObjectReturnedFromInitializingScanner(ref dev);
WIA.ImageFile Image1 = new WIA.ImageFile();
WIA.ImageProcess ImageProcess1 = new WIA.ImageProcess();
Object1 = (Object)"Convert";
ImageProcess1.Filters.Add(ImageProcess1.FilterInfos.get_Item(ref Object1).FilterID, 0);
Object1 = (Object)"FormatID";
Object2 = (Object)WIA.FormatID.wiaFormatTIFF;
ImageProcess1.Filters[1].Properties.get_Item(ref Object1).set_Value(ref Object2);
Object1 = (Object)"Compression";
Object2 = (Object)"CCITT4";
ImageProcess1.Filters[1].Properties.get_Item(ref Object1).set_Value(ref Object2);
Object1 = null;
Object2 = null;
try
{
WIA.ImageFile imagefile = Item1.Transfer(WIA.FormatID.wiaFormatTIFF) as WIA.ImageFile;
if (ImageScanned != null)
{
AcquireEventArgs e = new AcquireEventArgs();
using (MemoryStream ms = new MemoryStream((byte[])imagefile.FileData.get_BinaryData()))
{
e.Image = new Bitmap(ms);
}
ImageScanned(this, e);
}
}
catch (Exception ex)
{
throw new ScannerException("Problem with Scanner", ex);
}
}
}
private WIA.Item ItemObjectReturnedFromInitializingScanner(ref WIA.Device Scanner)
{
WIA.Item Item1 = null;
Object Object1 = null;
Object Object2 = null;
Int32 DPI = 200;
foreach (WIA.Item CurrentItem in Scanner.Items) // 'Scanner settings.
{
Item1 = CurrentItem;
try
{
Object1 = (Object)"6146";
Object2 = (Object)4;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6147";
Object2 = (Object)DPI;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6148";
Object2 = (Object)DPI;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6149";
Object2 = (Object)0;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6150";
Object2 = (Object)0;
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6151";
Object2 = (Object)(8.5 * DPI);
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
try
{
Object1 = (Object)"6152";
Object2 = (Object)(11.5 * DPI);
CurrentItem.Properties.get_Item(ref Object1).set_Value(ref Object2);
}
catch
{ }
foreach (WIA.Property Prop in Scanner.Properties)
{
if (Prop.PropertyID == 3088) //
{
try
{
Object1 = (Object)5;
Prop.set_Value(ref Object1); //'This is my effort to enforce duplex. I
}
catch (Exception) { }
}
}
}
Object1 = null;
Object2 = null;
return Item1;
}
///
/// Occurs when [image scanned].
///
public event EventHandler
}
Monday, September 21, 2009
Mouse drawing in WPF
I was trying to build a simple control to allow mouse drawing via the WPF. I found one web site that seemed to make the process a bit more complicated than doing the same thing in Windows Forms--but I tried it anyhow, and I simply couldn't make it work. I don't remember the website, but it basically used a canvas, and attempted to draw shapes on it based on Mouse movements. I had implemented routines bound to MouseDown, MouseUp, and MouseMove events, but those events never seemed to execute.
Then I discovered the InkCanvas control--and that solved all my problems. That original code must have come from before the existance of the InkCanvas, or the programmer simply didn't know any better. After switching to use the InkCanvas code I could remove all event handling code so that I only needed the code to capture the resulting image and save it. Below is the XAML:
<
UserControl x:Class="RCO.Imaging.SignaturePad.MouseSignaturePad.SignaturePad"xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
HorizontalAlignment="Stretch" Width="Auto" Height="Auto" VerticalAlignment="Stretch" > <InkCanvas Name="canvas1" Width="Auto" Height="Auto" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ></InkCanvas>
</
UserControl>And here is the C# behind it:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace
MousePad{
/// <summary>
/// Interaction logic for SignaturePad.xaml
/// </summary>
public partial class SignaturePad : UserControl
{
public SignaturePad()
{
InitializeComponent();
} public static RenderTargetBitmap ToImageSource(FrameworkElement obj)
{ // Save current canvas transform
Transform transform = obj.LayoutTransform;
obj.LayoutTransform = null;
// fix margin offset as well
Thickness margin = obj.Margin;
obj.Margin = new Thickness(0, 0,
margIn.Right - margin.Left, margin.Bottom - margin.Top);
// Get the size of canvas
Size size = new Size(obj.ActualWidth, obj.ActualHeight);
// force control to Update
obj.Measure(size);
obj.Arrange(new Rect(size));
RenderTargetBitmap bmp = new RenderTargetBitmap(
(int)obj.ActualWidth, (int)obj.ActualHeight, 96, 96, PixelFormats.Pbgra32);
bmp.Render(obj);
// return values as they were before
obj.LayoutTransform = transform;
obj.Margin = margin;
return bmp;
}
public void AcceptImage()
{
using (System.IO.MemoryStream outStream = new System.IO.MemoryStream())
{
// Use png encoder for our data
PngBitmapEncoder encoder = new PngBitmapEncoder();
// push the rendered bitmap to it
encoder.Frames.Add(BitmapFrame.Create(ToImageSource(canvas1)));
// save the data to the stream
encoder.Save(outStream);
outStream.Position = 0;
// Do something with the MemoryStream here--save it to file or pass it back into system.
}
}
}
}
Thursday, September 17, 2009
WIA in C#
Been awhile. Ran into a problem of needing to write code to acquire an image from a scanner. I had done TWAIN coding, but I've found that TWAIN is now gone by the wayside--in otherwords, don't use it.
Instead, use WIA. I had found Microsoft's WIA SDK, but discovered that its examples are in VB6, to give you an idea how old the stuff is. And on top of it--it seemed a bit convoluted.
Then I ran into http://www.codeproject.com/KB/dotnet/wiascriptingdotnet.aspx, which had a good example, though a little on the incomplete side (he left off the variable declaration statements). It seemed too simple, but I tried it out.
And wouldn't you know it--that was all that was needed! The link also include video information, but that was beyond the scope of my project.
Below is my code which wraps the WIA (strongly based on the above link). All you need to do is create the Scanner object, assign the "ImageScanned" event, the call the AcquireImages method. This code works asynchronously, so you can have other things going on while you wait for the images:
using
System;using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using WIALib;
namespace WIAWrapper
{
/// <summary>
/// This is a simple wrapper around WIA.
/// </summary>
public class Scanner
{
public class AcquireEventArgs : EventArgs
{
public Image Image { get; internal set; }
}
object selectUsingUI = System.Reflection.Missing.Value;
ItemClass wiaRoot;
WIALib.WiaClass wiaManager;
public Scanner()
{
wiaManager = new WIALib.WiaClass();
wiaRoot = (ItemClass)wiaManager.Create(ref selectUsingUI);
}
/// <summary>
/// Acquires the images.
/// </summary>
public void AcquireImages()
{
List<Image> retVal = new List<Image>();
CollectionClass wiaPics = wiaRoot.GetItemsFromUI(WiaFlag.SingleImage, WiaIntent.ImageTypeColor) as CollectionClass;
wiaManager.OnTransferComplete += new _IWiaEvents_OnTransferCompleteEventHandler(wiaManager_OnTransferComplete);
foreach (object wiaObj in wiaPics)
{
ItemClass wiaItem = (ItemClass)Marshal.CreateWrapperOfType(wiaObj, typeof(ItemClass));
string imgFile = Path.GetTempFileName();
wiaItem.Transfer(imgFile, true);
}
} public event EventHandler<AcquireEventArgs> ImageScanned; /// <summary>
/// Wias the manager_ on transfer complete.
/// </summary>
/// <param name="Item">The item.</param>
/// <param name="Path">The path.</param>
void wiaManager_OnTransferComplete(Item Item, string Path)
{
if (ImageScanned != null)
{
AcquireEventArgs e = new AcquireEventArgs();
e.Image = new Bitmap(Path);
ImageScanned(this, e);
}
}
}
}
Wednesday, July 15, 2009
Using XPath to modify app.config on setup
Sample code to modify the app.config when executing a setup package:
This assumes it is in the "Committed" event of a projectinstaller class. This sample only modifies a connectionString, but can easily be used for anything:
string
assemblypath = Context.Parameters["assemblypath"];string appConfigPath = assemblyPath + ".config";
XmlDocument doc = new XmlDocument();
doc.Load(appConfigPath);
XmlNode aConnection = doc.SelectSingleNode("/configuration/connectionStrings/add[@name=\"aConnectionIdentifier\"]");
aConnection.Attributes["connectionString"].Value = "Data Source=.;Initial Catalog=MyDatabase;User Id=MyUser;Password=MyPassword;";
doc.Save(appConfigPath);
Wednesday, July 8, 2009
Great .NET Zip library
http://dotnetzip.codeplex.com is a super library for zip functionality in .NET. I had problems viewing the compiled help file that you can download, but there are so many examples on the website, it really isn't necessary. It offers functionality equivalent to what you can get with WinZip 9.0 (AES encryption, too).
Subscribe to:
Posts (Atom)