One A Day Programming

Wednesday, April 27, 2011

How to Dismiss the Keyboard when using a UITextView

If you ever had a text view control in your iPhone program you may know that obvious task made ridiculously hard to do right for no apparent reason.  I bet there are must be one, but, if you do as one of the popular books on iPhone development recommend (adding a empty button to cover all your background and dismiss when it get clicked!) you will wonder how wacky is that.
Keyboard dismissal is one of the relay dumb thing on iPhone and developers hustle keep coming back. My search for latest techniques to fight this madness brought me to  http://iphonedevelopertips.com/cocoa/how-to-dismiss-the-keyboard-when-using-a-uitextview.html and while original post does not provide a proper solution, one of the commenter provided a very elegant solution that may just work for most folks. Here it is:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

UITouch *touch = [touches anyObject];
if ([textView isFirstResponder] && [touch view] != textView) {

[textView resignFirstResponder];
}
// My comment : If you have several text controls copy/paste/modify a block above and you are DONE!
}
Works for me and keyboard is gone when you tap outside without adding button or writing a lot of code.
Win!

Thursday, December 9, 2010

Android and common sense

There is no questions one should not use raw numbers and strings in the code, as it will surely backfire. Usually,  old-style (C) common sense and int/bool logic is used even for defines,  but you may be surprised to find out that when you use View.setVisibility(int state) in Android :



public static final int INVISIBLE

Since: API Level 1
This view is invisible, but it still takes up space for layout purposes. Use with setVisibility(int).
Constant Value: 4 (0x00000004)

public static final int VISIBLE

Since: API Level 1
This view is visible. Use with setVisibility(int).
Constant Value: 0 (0x00000000)

So, use defines, Luke :-)

Wednesday, February 3, 2010

Working with Outlook Interop or how to read your email messages from C#

It is very staight forward to send emails using .NET SmtpClient and MailMessage class, but how to read email you get?

If you use Outlook, it can be done via Outlook Interop:


http://msdn.microsoft.com/en-us/library/ms268893(VS.80).aspx


The use is simple, but there is important "gotcha": your Inbox folder have many objects and they can be of diferent types, so you have to check type before you cast. Like this:

if (item is Microsoft.Office.Interop.Outlook.MailItem)
{
   // This is email mesage
}

Note, that there are many folders and you can have subfolders inside inbox. To iterate all these you need to write a bit more code than bellow.

Here is just a simple example of how to print out all messages in your Inbox on just one level:


namespace EmailReader

{

       using System;
       using Microsoft.Office.Interop.Outlook;

        class Program
       {

             static void Main(string[] args)
           {

                   Application outlook = new Microsoft.Office.Interop.Outlook.ApplicationClass();

                  NameSpace mapiNameSpace = outlook.GetNamespace("MAPI");

                  MAPIFolder inbox = mapiNameSpace.GetDefaultFolder(OlDefaultFolders.olFolderInbox);

                  foreach (Object item in inbox.Items)
                 {
                         if (item is Microsoft.Office.Interop.Outlook.MailItem)
                        { 
                               MailItem mailItem = (MailItem)item;

                               Console.WriteLine(mailItem.Subject);
                               Console.WriteLine(mailItem.SentOn); 
                               Console.WriteLine(mailItem.Body); 
                               Console.WriteLine(mailItem.To); 
                               Console.WriteLine(mailItem.CC);
                               Console.WriteLine("*********************************");
                       }
                 }
               // outlook.Quit();
     }
  }
}

Friday, January 22, 2010

Treating properties as reference in C# or how to modify property of class you pass to function.

Technicaly you can not pass property by reference in C#.

DoSomething(ref MyClass.MyProperty);

will not even compile.

But sometimes you want to do it badly when you refactor your code and try to put repeating paterns to a neater functions. Yes, it may be better to design your classes using Dictionary or List or some thing you can iterate easly, but this may not be under your controll, say if you get this class automaticaly generated as in case of some Web service. So, puting high matters aside, how we can do it, so it will not look too ugly.

Naturaly there are a number of ways to trick the compiler. One of the reasons it does not compute is that property is actulay a couple of functions:

class Person
{
/// <summary>
/// Gets or sets user's name.
/// </summary>
public string Name
{
get;
set;
}
/// <summary>
/// Gets or sets user's email.
/// </summary>
public string Email
{
get;
set;
}
}



It will not work like a field, but we can use Expression and Linq to work around it. We can define:

Expression<Func<Person, string>> fieldExpression


and instead of passing a field like person.Name we will pass Expression: x => x.Name
It does not looks too ugly, as yet.

The way to work with it is not too straight forward and adds some overhead to code:

First you need to "unpack it":

var expression = (MemberExpression)fieldExpression.Body;
var property = (PropertyInfo)expression.Member;



To get property you do:

string oldValue = (string)property.GetValue(person, null);


To set it:

property.SetValue(person, newValue, null);


Not too elegant and a lot of overhead. It will not work as fast as just assignemt:

person.Name = "New Name"


But it will do the job and can aid in code refactoring.

Here is a full working example that does this trick:


using System;
using System.Linq.Expressions;
using System.Reflection;

class Person
{
/// <summary>
/// Gets or sets user's name.
/// </summary>
public string Name
{
get;
set;
}
/// <summary>
/// Gets or sets user's email.
/// </summary>
public string Email
{
get;
set;
}
}

class PersonUpdater
{
static bool UpdatePersonField(
Person person,
Expression<Func<Person, string>> fieldExpression,
string newValue)
{
var expression = (MemberExpression)fieldExpression.Body;
var property = (PropertyInfo)expression.Member;
string oldValue = (string)property.GetValue(person, null);

if (string.Compare(
oldValue,
newValue,
StringComparison.OrdinalIgnoreCase) != 0)
{
property.SetValue(person, newValue, null);

return true;
}

return false;
}

static void Main()
{
Person person = new Person();

person.Name = "Old Name";
person.Email = "Old Email";

UpdatePersonField(person, x => x.Name, "New Name");
UpdatePersonField(person, x => x.Email, "New Email");
}
}

Calling LsaAddAccountRights from managed code: C# wrapper for Win32 securty API that is missed from .NET library

OK, so today we will learn about dealing with these nasty native code wrappers that you have to deal with eventualy, when you can not find your "favorite" win32 function and you can not think about alternatives. While .NET have System.Securty namespace, some how I was not able to google out the way of Adding Account Rights a "managed way". But no worries, it can be done. We just need a wrapper!

First we have to define the Win32 function so C# will understand how to call it:


[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
SuppressUnmanagedCodeSecurityAttribute]
internal static extern uint LsaAddAccountRights(
LSA_HANDLE PolicyHandle,
IntPtr pSID,
LSA_UNICODE_STRING[] UserRights,
int CountOfRights
);


This loooks awfuly fugly and this is not all. You need to define all structures we use as well as few others functions: Win32 functions like to come in groups.

Here is example:

///
/// LSA_UNICODE_STRING structure
///

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct LSA_UNICODE_STRING
{
internal ushort Length;
internal ushort MaximumLength;
[MarshalAs(UnmanagedType.LPWStr)]
internal string Buffer;
}

Now, if you think that calling would be easy after that, you wrong! You have to initalize everthing ourself, allocate memory and copy buffers. It looks at least twice as ugly as you would do it in old good C/C++.

Byte[] buffer = new Byte[sid.BinaryLength];
sid.GetBinaryForm(buffer, 0);

IntPtr pSid = Marshal.AllocHGlobal(sid.BinaryLength);
Marshal.Copy(buffer, 0, pSid, sid.BinaryLength);

LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];

LSA_UNICODE_STRING lsaRights = new LSA_UNICODE_STRING();
lsaRights.Buffer = rights;
lsaRights.Length = (ushort)(rights.Length * sizeof(char));
lsaRights.MaximumLength = (ushort)(lsaRights.Length + sizeof(char));

privileges[0] = lsaRights;

ret = LsaAddAccountRights(lsaHandle, pSid, privileges, 1);

This is a evil mix of "good" and "evil". Managed and unmanged(native) code come together in ugly embrace. Yaaaack...

Now, the code below is just a wraper on one function, you would most likly do it better with proper constractor and Dsipose() and more throws to handle all error conditions ... and add least LsaRemoveAccountRights e.t.c. But this simple exersize left to the reader :-)

Here is a stating point bellow (it works for me, btw) :


using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Principal;
using LSA_HANDLE = System.IntPtr;

/// 
/// LSA_OBJECT_ATTRIBUTES structure
/// 
[StructLayout(LayoutKind.Sequential)]
struct LSA_OBJECT_ATTRIBUTES
{
    internal int Length;
    internal IntPtr RootDirectory;
    internal IntPtr ObjectName;
    internal int Attributes;
    internal IntPtr SecurityDescriptor;
    internal IntPtr SecurityQualityOfService;
}

/// 
/// LSA_UNICODE_STRING structure
/// 
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct LSA_UNICODE_STRING
{
    internal ushort Length;
    internal ushort MaximumLength; 
    [MarshalAs(UnmanagedType.LPWStr)]
    internal string Buffer;
}

/// 
/// Wraps LsaAddAccountRights call.
/// 
public sealed class LsaSecurityWrapper
{
    [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
    SuppressUnmanagedCodeSecurityAttribute]
    internal static extern uint LsaOpenPolicy( 
    LSA_UNICODE_STRING[] SystemName, 
    ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
    int AccessMask,
    out IntPtr PolicyHandle
);

[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
    SuppressUnmanagedCodeSecurityAttribute]
    internal static extern uint LsaAddAccountRights(
    LSA_HANDLE PolicyHandle,
    IntPtr pSID,
    LSA_UNICODE_STRING[] UserRights,
    int CountOfRights
);

[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
    SuppressUnmanagedCodeSecurityAttribute]
    internal static extern uint LsaRemoveAccountRights(
    LSA_HANDLE PolicyHandle,
    IntPtr AccountSid,
    bool AllRights,
    LSA_UNICODE_STRING[] UserRights,
    int CountOfRights
);

[DllImport("advapi32")]
internal static extern int LsaClose(IntPtr PolicyHandle);

enum Access : int
{ 
    POLICY_READ = 0x20006,
    POLICY_ALL_ACCESS = 0x00F0FFF,
    POLICY_EXECUTE = 0X20801,
    POLICY_WRITE = 0X207F8
}

// rights: (http://msdn.microsoft.com/en-us/library/bb545671(VS.85).aspx)
public static void AddAccountRights(SecurityIdentifier sid, string rights)
{
    IntPtr lsaHandle;

    LSA_UNICODE_STRING[] system = null;
    LSA_OBJECT_ATTRIBUTES lsaAttr;
    lsaAttr.RootDirectory = IntPtr.Zero;
    lsaAttr.ObjectName = IntPtr.Zero;
    lsaAttr.Attributes = 0;
    lsaAttr.SecurityDescriptor = IntPtr.Zero;
    lsaAttr.SecurityQualityOfService = IntPtr.Zero;
    lsaAttr.Length = Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES));
    lsaHandle = IntPtr.Zero;

    uint ret = LsaOpenPolicy(system, ref lsaAttr, (int)Access.POLICY_ALL_ACCESS,   out lsaHandle);
    if (ret == 0)
    {
        Byte[] buffer = new Byte[sid.BinaryLength];
        sid.GetBinaryForm(buffer, 0);

        IntPtr pSid = Marshal.AllocHGlobal(sid.BinaryLength);
        Marshal.Copy(buffer, 0, pSid, sid.BinaryLength);

        LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];

        LSA_UNICODE_STRING lsaRights = new LSA_UNICODE_STRING();
        lsaRights.Buffer = rights;
        lsaRights.Length = (ushort)(rights.Length * sizeof(char));
        lsaRights.MaximumLength = (ushort)(lsaRights.Length + sizeof(char));

        privileges[0] = lsaRights;

        ret = LsaAddAccountRights(lsaHandle, pSid, privileges, 1);

        LsaClose(lsaHandle);

        Marshal.FreeHGlobal(pSid);

        if (ret != 0)
        {
             throw new Win32Exception("LsaAddAccountRights failed with error code: " + ret);
        }
    }
    else
    {
        throw new Win32Exception("LsaOpenPolicy failed with error code: " + ret);
    }
  }
}

Counting letters in Microsoft Word files using C# and Office Interop

Today we will learn how to work with Office Interop. I never had a chance to try it, till some one asked me for a batch script that will count characters in a bunch of Word files. I choose to use C# instead, hoping I can coin some thing up in under 5 minutes. It took me a bit more, mainly because of deployment pain: both .NET 3.5 SP 1 had to be installed on other machine (with reboot) and I had to include interop DLL.

First, I created a simple command line project for C#. You will need to add a reference to Microsoft.Office.Interop.Word to your project and I would recommend choose TRUE in properties to copy it to your project: this way it will be easy for you just to provide EXE and DLL when you distribute, also automatic publish option in VS 2008 will pack it up for you. Your application will not run if this DLL is not present on target system.


Now, working with Word is easy. All you need is




    Word.ApplicationClass wordApp = new ApplicationClass();


and do not forget to call






    doc.Close(ref falseObj, ref nullobj, ref nullobj);

or you will end up with many "ghost" WINWORD.EXE in memory.

Now to get your hands on Word file DOM, you need just call this function with 16 parameters! :-) If you want to edit your file or do other fancy things, read MSDN help. 

Word.Document doc = wordApp.Documents.Open(ref fileObj, ref falseObj, ref trueObj,
                         ref falseObj, ref nullobj, ref nullobj,
                         ref nullobj, ref nullobj, ref nullobj,
                         ref nullobj, ref nullobj, ref falseObj,
                         ref nullobj, ref nullobj, ref nullobj, ref nullobj);


I open doc file in read only, no show mode here. If you like diferent options, check MSDN and good luck counting these arguments!

All I need for my task is

long count = doc.Characters.Count;

but you can have as much fun as you like with doc object. Do not forget to call

doc.Close(ref falseObj, ref nullobj, ref nullobj);

when you done. Again, if you would like to Edit file, you will need use a diferent set of flags. Click F1 on fucntion and read MSDN help.

File enumeration part is not as interesting: I just read all doc files in one folder: that was my task.

Below is a full text of this small utilty:


//-----------------------------------------------------------------------
// <copyleft file="WordFilesLetterCount.cs">
// Do what you wilt with this code and have fun on your own risk!
// </copyleft>
//-----------------------------------------------------------------------
namespace WordFilesLetterCount
{
   using System;
   using System.IO;
   using Microsoft.Office.Interop.Word;
   using Word = Microsoft.Office.Interop.Word;

   class Program
   {
       static void Main(string[] args)
       {
           if (args.Length == 1)
           {
               long totalCount = 0;
               long fileCount = 0;

               Word.ApplicationClass wordApp = new ApplicationClass();

               object nullobj = System.Reflection.Missing.Value;
               object trueObj = true;
               object falseObj = false;
              
               DirectoryInfo di = new DirectoryInfo(args[0]);
               FileInfo[] rgFiles = di.GetFiles("*.doc*");
               foreach (FileInfo fi in rgFiles)
               {
                   if (fi.Attributes != FileAttributes.Temporary &amp;&amp;
                       fi.Attributes != FileAttributes.Hidden &amp;&amp;
                       fi.Attributes != FileAttributes.System)
                   {
                       if (!(fi.FullName.Contains("~") &amp;&amp; fi.FullName.Contains("$")))
                       {
                           try
                           {
                               object fileObj = fi.FullName;
                               Word.Document doc = wordApp.Documents.Open(ref fileObj, ref falseObj, ref trueObj,
                                          ref falseObj, ref nullobj, ref nullobj,
                                          ref nullobj, ref nullobj, ref nullobj,
                                          ref nullobj, ref nullobj, ref falseObj,
                                          ref nullobj, ref nullobj, ref nullobj, ref nullobj);

                               //doc.ActiveWindow.Selection.WholeStory();
                               //doc.ActiveWindow.Selection.Characters.Count;

                               long count = doc.Characters.Count;
                               totalCount += count;

                               Console.WriteLine("File: {0} Character Count: {1}", fi.Name, count);

                               doc.Close(ref falseObj, ref nullobj, ref nullobj);

                               fileCount++;
                        }
                        catch (Exception ex)
                        {
                           Console.WriteLine("Error {0} with file: {1}", ex.Message, fi.Name);
                        }
                    }
                 }
               }

               wordApp.Quit(ref falseObj, ref nullobj, ref nullobj);

               Console.WriteLine(
                   "Total: {0} letters counted in {1} files ((*.doc*) only in one directory {2}",
                   totalCount,
                   fileCount,
                   args[0]);
           }
           else
           {
               Console.WriteLine("Usage: WordFilesLetterCount [directoryWithWordFiles]");
           }
       }
   }
}