Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Monday, March 4, 2013

WPF and MessageBox in Dispatcher.Invoke

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");

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;
        }
        

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.




  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;
    }

}

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".

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;


}

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).