Friday, March 16, 2007

Global Events Hooking

WPF has really great engines for global hooking. Dependency Properties/Objects are only small part of those engines. Today, we'll look into Routed Events and EventManager

Let's take a scenario, where I want to handle OnClosing event of all windows in my application. The propose is clear - popup an exclamation asking me to approve this action.

The "legacy" way is to create kind of BaseWindow, derived from Window Class and override onClosing event to popup my message. This approach means, that I have to inherit BaseWindow in all windows or instead of creation of Window instance, create Basewindow one.

But, I want to do it easily, and I'm in WPF world, so let's start new WPF project and put into App.xaml.cs class following lines

 

protected override void OnStartup(StartupEventArgs e)
        {
            EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent, new RoutedEventHandler(WindowLoaded));
 
            base.OnStartup(e);
        }

Done. Now let's understand what we did. We register globally routed event Window.Loaded for each new instance of Window class, so each time this event will be fired (that not mention, if we have or will have an instance of window), EventManager will subscribe to it and execute WindowLoaded method. The rest is really simple. Let's implement WindowLoaded and subscribe the loaded instance to our message popping


 



void WindowLoaded(object sender, RoutedEventArgs e)
        {
            Window w = sender as Window;
            if (w != null)
            {
                w.Closing += new System.ComponentModel.CancelEventHandler(w_Closing);
            }
        }
 
void w_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (MessageBox.Show("Really [with EventManager]?", "Workaround window", MessageBoxButton.YesNo, MessageBoxImage.Exclamation) == MessageBoxResult.No)
                e.Cancel = true;
        }

That's all, folks. Now each window (or window derived class) in my system, even those how I do not know will ask me about closing each time, I'll try to close them.


Nice, don't you think?

Tuesday, March 13, 2007

How to set your mobile modem to work without dialer

So, all those happy owners of Orange GSM modem Novatel Merlin U740 and Windows Vista already paid their attention to bugs of it's software dialer MobiLink. Someone called to Orange customer service to get answers, and understand, that their are not officially support Windows Vista. Someone get new drivers (via YouSendIt.com - please someone tell my why Orange can not just put those drivers to their website). But even the new version of Mobilink is really junk

I believe, that  most of you have problem while entering Stand by or Hibernate mode after using the MobiLink dialer, while the dialer can not  properly close itself at all this what you see (after the dialer close) in process manager

So, how to solve it? How to set your modem work with access points you want without using their dialer. No problem. Let's do it.

All we have to do is to create two regular dialers for two possible orange 3G access point - UInternet and UWap (as well as configured in your mobile phone). But before creating a dialer let's put all setting inside the modem? How it's possible? Novatel Merlin U740 is very good hardware modem. It has it's own memory able to save upto 100 network locations.

So, open HyperTerminal (oh, my godness, there is not hyper terminal in Windows Vista, so open Putty, IMHO, the best open source terminal, SSH, and telnet client) and connect the COM port your modem sits in. Obvious, that you should have you modem in and connected (see in phone and modem options what com port it sits on)

Now in terminal windows type "at+cgdcont=?" (without quotes) to get your modem capabilities. You can see, that you have 1 upto 99 "IP" locations. Let's use slot one and two. Don't you want check what the modem has saved before usage? Sure, type "at+cgdcont?" to get this information.

Now let's put our location in slot 1 and 2. Type (case sensitive, two separate lines):
at+cgdcont=1,"IP","uinternet";
at+cgdcont=2,"IP","uwap.orange.co.il";

Done, now you have UINTERNET access point configures in slot 1 and UWAP in slot 2. Check this by typing "at+cgdcont?" (no quotes). If you see following - you did it!

The only thing we have to do is to tell your dialer use first or second (or both) slot. To do it add to default service center phone number ***X#, where X - your slot number. So to use UWAP, enter "*99***2#" (without quotes).  Please remember to have you modem in and selected for this connection while setting it.

Dunno. Don't forget to set proxy server (192.118.11.55:8080) in IE's Internet Options for UWAP AP. For UInternet you don't need to do it.

That's all folks, now plug your modem in and dial the required connection by using Windows Vista Connection Manager and forget the buggy MobiLink.

Dell story - part II

Today sales manager from the distributor store called me to notice, that I can come there and get my upgrade to Windows Vista, arrived from Dell. The only thing he mentioned in our conversation is fee of $45. I asked him what I'm paying for, and he told me that is's for shipping and handling. The same sentence, I found in Dell Vista Upgrade FAQ web site, but if I'll come to take it, it's seemed him, that I should not pay anything. 

A minute later, he called me back, and told, that I should pay for it anyway. After my request to explain he told me, that those $45 actually they'll pay to Microsoft and don't earn a penny for it. So he do not really know what I should pay for. 

The upgrade price for Windows Vista Home Basic is around $100, complete package costs around $200 (including shipping and handling), so the question is what's for I'm going to pay a half of regular licence price, when my system is eligible and the licence for Windows XP Pro SP2 already paid? I'll check this next Sunday.

Monday, March 12, 2007

Text length measurement? It's really easy with WPF

Don't you remember how it was to measure the length of your text in pixels? Do you really remember methods named GetLineFromCharIndex, Bounds and MeasureText?

Let's do it in WPF:

TextBox myText = new TextBox();
Rect textRext = myText.GetRectFromCharacterIndex(myText.Text.Length);

That's all, folks. Now you have the boundaries of your text in pixels. You can even measure the size of text up to your cursor position by using CaretIndex property of TextBox. Don't it really easy?

 

<Window x:Class="TextMeasurement.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:m="clr-namespace:TextMeasurement"
        Name="myWindow" 
    Title="TextMeasurement" Height="300" Width="300"
    >
  <StackPanel>
    <StackPanel Orientation="Horizontal">
      <TextBlock>The text length is:  </TextBlock>
      <TextBlock Name="mySize" Text="{Binding ElementName=myWindow, Path=TextSize}"/>
    </StackPanel>
    <TextBox Name="myText" TextChanged="onChanged"/>
  </StackPanel>
</Window>

 


public partial class Window1 : System.Windows.Window

{

    public static readonly DependencyPropertyKey TextSizePropertyKey = DependencyProperty.RegisterReadOnly("TextSize",

        typeof(double), typeof(Window1),

        new UIPropertyMetadata((double)0));

    public static DependencyProperty TextSizeProperty = TextSizePropertyKey.DependencyProperty;

    public double TextSize

    {

        get { return (double)GetValue(TextSizeProperty); }

    }

 

 

    public Window1()

    {

        InitializeComponent();

 

    }

 

    void onChanged(object sender, TextChangedEventArgs e)

    {

        Rect textRext = myText.GetRectFromCharacterIndex(myText.Text.Length);

 

        SetValue(TextSizePropertyKey, textRext.Right);

    }

 

}

 

Have a nice day with WPF :)

Sunday, March 11, 2007

How to use IE authentication programmatically

So, there are two methods deals with credential dialog of IE

CredUIPromptForCredentials – for pop it up and CredUIConfirmCredentials for persist those settings in password manager (optional). So, in order to call it explicitly, you should implement them via P/Invoke like this

[DllImport("credui.dll", EntryPoint = "CredUIConfirmCredentialsW", CharSet = CharSet.Unicode)]

       private static extern CredUIReturnCodes CredUIConfirmCredentials(string targetName, [MarshalAs(UnmanagedType.Bool)] bool confirm);

[DllImport("credui.dll", EntryPoint = "CredUIPromptForCredentials", CharSet = CharSet.Ansi)]

       private static extern CredUIReturnCodes CredUIPromptForCredentials(ref CREDUI_INFO creditUR,

                                                                                                                       string targetName,

                                                                                                                       IntPtr reserved1,

                                                                                                                       int iError,

                                                                                                                       StringBuilder userName,

                                                                                                                       int maxUserName,

                                                                                                                       StringBuilder password,

                                                                                                                       int maxPassword,

                                                                                                                       [MarshalAs(UnmanagedType.Bool)] ref bool pfSave,

                                                                                                                       CREDUI_FLAGS flags);

Please pay attention, that you’ll need CREDI_INFO structure and CREDI_FLAG and CredUIReturnCodes enums, that those function using

public struct CREDUI_INFO

{

   public int cbSize;

   public IntPtr hwndParent;

   public string pszMessageText;

   public string pszCaptionText;

   public IntPtr hbmBanner;

}

[Flags]

enum CREDUI_FLAGS

{

   INCORRECT_PASSWORD = 0x1,

   DO_NOT_PERSIST = 0x2,

   REQUEST_ADMINISTRATOR = 0x4,

   EXCLUDE_CERTIFICATES = 0x8,

   REQUIRE_CERTIFICATE = 0x10,

   SHOW_SAVE_CHECK_BOX = 0x40,

   ALWAYS_SHOW_UI = 0x80,

   REQUIRE_SMARTCARD = 0x100,

   PASSWORD_ONLY_OK = 0x200,

   VALIDATE_USERNAME = 0x400,

   COMPLETE_USERNAME = 0x800,

   PERSIST = 0x1000,

   SERVER_CREDENTIAL = 0x4000,

   EXPECT_CONFIRMATION = 0x20000,

   GENERIC_CREDENTIALS = 0x40000,

   USERNAME_TARGET_CREDENTIALS = 0x80000,

   KEEP_USERNAME = 0x100000,

}

public enum CredUIReturnCodes

{

   NO_ERROR = 0,

   ERROR_CANCELLED = 1223,

   ERROR_NO_SUCH_LOGON_SESSION = 1312,

   ERROR_NOT_FOUND = 1168,

   ERROR_INVALID_ACCOUNT_NAME = 1315,

   ERROR_INSUFFICIENT_BUFFER = 122,

   ERROR_INVALID_PARAMETER = 87,

   ERROR_INVALID_FLAGS = 1004,

}

Now, when you have those calls, you may want to make some wrappers (like those)

const int MAX_USER_NAME = 100;

const int MAX_PASSWORD = 100;

const int MAX_DOMAIN = 100;

static CredUIReturnCodes PromptForCredentials(ref CREDUI_INFO creditUI, string targetName, int netError, ref string userName, ref string password, ref bool save, CREDUI_FLAGS flags)

{

                         StringBuilder user = new StringBuilder(MAX_USER_NAME);

                         StringBuilder pwd = new StringBuilder(MAX_PASSWORD);

                         creditUI.cbSize = Marshal.SizeOf(creditUI);

                         CredUIReturnCodes result = CredUIPromptForCredentials(ref creditUI, targetName,IntPtr.Zero, netError,user, MAX_USER_NAME, pwd, MAX_PASSWORD, ref save, flags);

                                                  userName = user.ToString();

                                                  password = pwd.ToString();

                         return result;

}

CredUIReturnCodes AskCredit(ref string username, ref string password)

{

                         string host = url.Host;

                         CREDUI_INFO info = new CREDUI_INFO();

                         info.pszCaptionText = host;

                         info.pszMessageText = "The server "+host+" requires a username and password. \r\n\r\n\r\nWarning: This server is requesting that your username and password be sent in an insecure manner (basic                                                                            authentication without a secure connection).";

                         CREDUI_FLAGS flags = CREDUI_FLAGS.GENERIC_CREDENTIALS |

                                                  CREDUI_FLAGS.SHOW_SAVE_CHECK_BOX |

                                                  CREDUI_FLAGS.ALWAYS_SHOW_UI |

                                                  CREDUI_FLAGS.EXPECT_CONFIRMATION;

                         bool savePwd = false;

                         CredUIReturnCodes result = PromptForCredentials(ref info, host, 0, ref username,

                         ref password, ref savePwd, flags);

return result;

}

After it, you should call AskCredit to get the credit window pop up and get secured username and password from them. Something like this

CredUIReturnCodes code = AskCredit(ref user, ref pwd);

                         if (code == CredUIReturnCodes.NO_ERROR)

                         {

//Do something useful

                         }

The next part is to provide those credentials to your HTTPRequest. See the sample doing that

//create some string to get response into

string str = string.Empty;

HttpWebRequest req = HttpWebRequest.Create(url) as HttpWebRequest;

HttpWebResponse res = null;

//while you don’t OK keep trying

while (res == null || res.StatusCode != HttpStatusCode.OK)

{

                         try

                         {

//you are fine, do the rest

                         res = req.GetResponse() as HttpWebResponse;

                         using (Stream s = res.GetResponseStream())

                         {

                                                  using (StreamReader sr = new StreamReader(s))

                                                  {

                                                                           str = sr.ReadToEnd();

                                                                           sr.Close();

                                                  }

                         s.Close();

                         }

                         res.Close();

                         }

//You got an exception

                         catch (WebException e)

{

//If this exeption is not security one, you have nothing to do, the only thing is, maybe, check you network connection

                         if (e.Status == WebExceptionStatus.ProtocolError)

                                                  {

                                                                           res = e.Response as HttpWebResponse;

//Now check what the problem and if it’s security, threat it

                                                                           if (res.StatusCode == HttpStatusCode.Unauthorized)

                                                                           {

                                                                                                    string user = "";

                                                                                                    string pwd = "";

//pop you window and get information

                                                                                                    CredUIReturnCodes code = AskCredit(ref user, ref pwd);

                                                                                                    if (code == CredUIReturnCodes.NO_ERROR)

                                                                                                    {

//create new credential set and use it as required

                                                                                                                             CredentialCache creds = new CredentialCache();

                                                                                                                             creds.Add(url, "Basic", new NetworkCredential(user,pwd));

                                                                                                    //creds.Add(url, "Digest", new NetworkCredential(user, pwd));

                                                                                                    //creds.Add(url, "Negotiate", CredentialCache.DefaultNetworkCredentials);

                                                                                                                             req.Credentials = creds;

                                                                                                    }

                                                                           }

                                                  }

                         }

}

Well done. Now you have an application, that pops Internet Explorer authentication window and optionally saves your passwords into security password store within the browser

Israel? It's beside our propose... The Dell story

I got my new Dell Latitude D820 a couple of month ago (after the announcement about Dell's Express Upgrade to Windows Vista. Right after I got it, I checked the site with the computer service tag to be sure eligible for upgrade program. So, I was. Working fluently with my new Dell with Beta and RTM versions (first internals and then MSDN) I was really happy (the first thing I did, after purchase is to format disks with pre-installed Windows XP Pro SP2, which I paid for). So, some way after the official announcement about Windows Vista release, I called the retailer, I purchased the laptop to ask about upgrade. The first answer was: "We do not know anything about it, please contact local Dell office for additional information".

I called them and, sure, was redirected to distributor. I sent a message (using my google account) to Dell's local office and wait for about a month for them to reply, that I never got. So, after another call, I sent another mail (this time using my work address in Microsoft) with the same question. Hurrah!, I got an answer from Shlomy Quarter from Dell as following (hebrew):

 

תמיר שלום,

מדיניות השדרוג אינה חלה על ישראל בשלב זה, מכיוון שהמידע לא הגיע אליך במעמד הרכישה חברת אומניטק תשדרג לך תוך כדי חיוב בדמי המשלוח בלבד כפי שמתוארים באתר.

אנא פנה אל מאיר או עמית בחברת אומניטק בנושא.

Best Regards,

                   Shlomy

Wow, why you, Shlomo, did not sent me the same email to @gmail.com account? The regular client, paid for new Dell computer is not important enough? The client should come from big company to get any response for his after-purchase query?

A couple of hours after this email, I checked another time my Dell service tag for eligibility of the upgrade. Sure it was not, but I have a screenshot a month ago, where the same service tag was eligible. Strange, don't you think? Another computer, purchased earlier in US is still eligible system for this upgrade, I tell you more, I got a disk with an upgrade to my Israel postal address about two weeks after global lunch of Windows Vista.

So, according Dell, all those who purchased new Dell computer here, is Israel are really different customers, then all those who purchased in USA? Don't this seemed a bit strange, or, maybe Dell is really different here? Don't them? All of us are beside there propose, or not?

P.S. I'm really do not need this upgrade, due? I have both internals and MSDN versions, but the Principe is matter... 

Thursday, March 08, 2007

UAC strikes again - flash fix for IE

Until recently, we all saw flash content from Vista in IE, however about a week ago we do not. What's the problem? The new version of Macromedia Flash Player, that do not leaves well with Vista's User Account Control (UAC). So how to fix it?

Great thank to Frank, that investigated the problem and found the solution. You should authorize flash installer to run with elevated rights. How to do it?

Go to "Your Windows Directory\System32\Macromed\Flash", right click FlashUtil9b.exe and select "Run as administrator". The program will install new flash player with elevated security settings.

How you can see any flash content. So, what do you think, UAC still good or bad for Jews?