Feeds:
Posts
Comments

I needed my WPF controls size in pixels to retrieve the correct sized image from a web service.  The answer hit me one night and it’s very simple:

Create a known size image (say 100 x 100 pixels), put it in a image control on some bit of WPF screen (Hidden not collapsed), ensure no stretching by putting Stretch=None and a non-stretch value for both Horizontal and Vertical alignment and make the calculation from the Image controls actual width and height.

This bit of xaml shows what I did:

<Grid>
    <Image x:Name="A100x100ImageControl"
    Source="/images/100x100.jpg" Stretch="None"
        HorizontalAlignment="Left" VerticalAlignment="Top"
        Visibility="Hidden"/>
    <Image x:Name="ImageControl" Stretch="Uniform"/>
</Grid>

A calculation with look something like this:

(In my case I wrapped it up in a UserControl with SizeTarget, a bound property, being a specific interface with just width and height that can be implemented elsewhere.)

SizeTarget.PixelWidth = (int)Math.Truncate(ActualWidth * 100 /
                A100x100ImageControl.ActualWidth);

My problem: A program was using 127.0.0.2 (an alias for 127.0.0.1) to make a local connection on a specific port. However, one Windows 2003 server box was configured so that this port was being listened to on a specific network adapter (and hence a specific IP address). Hence, my local connection failed even though the port was open for listening.

Background: Type “netstat -p tcp -a -n” at the command prompt to get details of listening ports. The “Local Address” is adapter specific; “0.0.0.0″ means it’s listening on all adapters (thus allowing connections to 127.0.0.1). In the case of this 2003 box, the port I wanted was specific to a particular IP address (adapter).

So, my program needed to connect to the adapter specific IP address and not 127.0.0.1. This is how to get the IP addresses and ports they’re listening on:


void DoItAgain()
{
   DWORD err;
   DWORD size = 0;
   // first get the size of the buffer required
   if((err=GetTcpTable (0,&size,FALSE))!=ERROR_INSUFFICIENT_BUFFER)
   {
      std::cerr << "Error " << err <<
         " getting tcp table size." << std::endl;
      return;
   }
   // next get the table
   std::vector buf(size);
   MIB_TCPTABLE *tbl = reinterpret_cast(&(*buf.begin()));
   if((err=GetTcpTable(tbl,&size,FALSE))!=NO_ERROR)
   {
      std::cerr << "Error " << err <<
         " getting tcp table." << std::endl;
      return;
   }
   // iterate through the entries
   for (DWORD dw = 0; dw < tbl->dwNumEntries; ++dw)
   {
      if(tbl->table[dw].dwState == MIB_TCP_STATE_LISTEN)
      {
         in_addr ad;
         ad.S_un.S_addr = tbl->table[dw].dwLocalAddr;
         std::cout << "Listening " << inet_ntoa(ad) <<
            ", port " << ntohs(tbl->table[dw].dwLocalPort) << std::endl;
      }
   }
}

To use an icon resource embedded into your assemply: 

1) Add icon to project and make it an “Embedded Resource” type (no need to copy to output directory).

2) Construct your System.Drawing.Icon like this:


new Icon(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("MyShinyApp.hammer.ico"));

Where MyShinyApp is the value specified in “Default namespace” property of your project (Application tab of project properties) and hammer.ico is the name of your icon.

I had to do a bit of searching so, here’s how to minimize your WPF app to a tray icon.  Assume your window is called Window1 for the code below.  Trap Closing, StateChanged and IsVisibleChanged (see xaml). 

xaml:

<window x:Class="MyApp.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="WCFAppVisualHost" Height="383" Width="680" Closing="OnClose" StateChanged="OnStateChanged" IsVisibleChanged="OnIsVisibleChanged"
  >

Associated cs:

private System.Windows.Forms.NotifyIcon m_notifyIcon;

public Window1()
{
    // initialise code here
    m_notifyIcon = new System.Windows.Forms.NotifyIcon();
    m_notifyIcon.BalloonTipText = "The app has been minimised. Click the tray icon to show.";
    m_notifyIcon.BalloonTipTitle = "The App";
    m_notifyIcon.Text = "The App";
    m_notifyIcon.Icon = new System.Drawing.Icon("TheAppIcon.ico");
    m_notifyIcon.Click += new EventHandler(m_notifyIcon_Click);
}

void OnClose(object sender, CancelEventArgs args)
{
    m_notifyIcon.Dispose();
    m_notifyIcon = null;
}

private WindowState m_storedWindowState = WindowState.Normal;
void OnStateChanged(object sender, EventArgs args)
{
    if (WindowState == WindowState.Minimized)
    {
        Hide();
        if(m_notifyIcon != null)
            m_notifyIcon.ShowBalloonTip(2000);
    }
    else
        m_storedWindowState = WindowState;
}
void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs args)
{
    CheckTrayIcon();
}

void m_notifyIcon_Click(object sender, EventArgs e)
{
    Show();
    WindowState = m_storedWindowState;
}
void CheckTrayIcon()
{
    ShowTrayIcon(!IsVisible);
}

void ShowTrayIcon(bool show)
{
    if (m_notifyIcon != null)
        m_notifyIcon.Visible = show;
}

I’ve always wondered (and again two days ago) what “irreversible loss of information” is being referd to when you reset a local user password from the “Computer Management” console.  Independantly, I’ve been tracking down a bug reported by one PMG Connect user in which the connection routine fails.

These things are linked.  The bug was a call to cryptography API CryptAquireContext failing with error NTE_BAD_KEY_STATE.  (Ok, I admit, if the software was reporting faults better, this could have been determined ages ago.)  In short, it was attempting to open a key container that existed but couldn’t be used because the user had reset the password.  Checkin the web, this occurs with a lot of software (one suggested work-around was to create a new user account!).

So, that’s some of what loss of information occurs.  To fix this problem, the software attempts to open key containers with different names when that error is encounted.

Block Sock Block

WinHttpGetProxyForUrl also blocks.  This is despite the documentation saying that it won’t if you close the handle during it’s operation.  (Let’s face it, Microsoft programmers often have a very loose sense of the meaning of block, what’s a minute or two.)  Anyway, this called for a generic class for blocking things (see previous post re gethostbyname and getaddrinfo blocking).  Anyway, the class (as before Thread is a pretty basic personal thread class):

class CAbortableAction : public Thread
{
public:
    CAbortableAction() : m_abort(CreateEvent(0,TRUE,FALSE,0),0,CloseHandle) {}
    virtual void AbortAction() {SetEvent(m_abort);}
protected:
    virtual bool StartAction()
    {
        ResetEvent(m_abort);
        if(!Create().Valid())
            return false;
        HANDLE handles[] = {ThreadHandle(),m_abort};
        return (
            WaitForMultipleObjects(sizeof(handles)/sizeof(handles[0]),
                    handles,FALSE,INFINITE)=WAIT_OBJECT_0);
    }
    virtual void DoAction() = 0;
    bool IsAborted() { return EventHandle(m_abort).IsSet();}
private:
    auto_HANDLE m_abort;
    DWORD ThreadProc() {DoAction();return 0;}
};

The latest alpha build is on the Possemeeg Software site.  Interested parties should check from time to time for updates.

gethostbyname and getaddrinfo block.  There is no way to stop them once they’ve started.  (BTW, getaddrinfo is recommended over gethostbyname as it’s IPv6 compatible.)  This little class will provide a neat way to get the info without blocking.  Classes extra::Thread and extra::auto_HANDLE are thread and and auto handle closing classes respectivly (is that english?).  When the user requires to cancel the request or connect, call m_hostNameGetter.Abort() from within MySocketClass.

The Class:

class CGetAddrInfoThread : private extra::Thread
{
public:
    CGetAddrInfoThread();
    void Abort();
    struct addrinfo *GetAddrInfo(const extra::tstring &host, ULONG nPort);
private:
    extra::auto_HANDLE m_abort;
    extra::tstring m_host;
    ULONG m_port;
    struct addrinfo *m_ret;
    virtual DWORD ThreadProc();
};

The Implementation

CGetAddrInfoThread::CGetAddrInfoThread() :
        m_port(0), m_ret(0), m_abort(0,0,CloseHandle)
{
}
void CGetAddrInfoThread::Abort()
{
    SetEvent(m_abort);
}
struct addrinfo *CGetAddrInfoThread::GetAddrInfo(const extra::tstring &host, ULONG nPort)
{
    if(!m_abort.Valid())
        m_abort = CreateEvent(0,TRUE,FALSE,0);
    m_host = host;
    m_port = nPort;
    m_ret = 0;
    ResetEvent(m_abort
    if(!Create().Valid())
        return 0
    HANDLE handles[] = {ThreadHandle(),m_abort};
    return ((WaitForMultipleObjects(sizeof(handles)/sizeof(handles[0]),
                handles,FALSE,INFINITE)==WAIT_OBJECT_0) ? m_ret : 0);
}
DWORD CGetAddrInfoThread::ThreadProc()
{
    char port[16];
    if(_ultoa_s(m_port,port,10))
        return 0;
    struct addrinfo aiHints;
    memset(&aiHints, 0, sizeof(aiHints));
    aiHints.ai_family = AF_INET;
    aiHints.ai_socktype = SOCK_STREAM;
    aiHints.ai_protocol = IPPROTO_TCP;
    if (::getaddrinfo(CT2CA(m_host.c_str()), port, &aiHints, &m_ret))
        m_ret = 0;
    return 0;
}

Using the class:

void MySocketClass::MyConnectingMethod()
{
    // do stuff
    struct addrinfo *aiList = m_hostNameGetter.GetAddrInfo(host,nPort);
    if(!aiList)
        return 0;
    // do stuff
}

The docs for the .NET Dictionary class lead you to believe that implementing IEquatable for a dictionary key is good enough to get the dictionary to use your Equals method.  However, one must also override GetHashCode.  Given the way a dictionary works, this is logical but not documented.  The interesting part, is that the Remove method on the dictionary will use your Equals with or without GetHashCode being implemented.  In this way, you can add identical items and remove more than one with one remove.  Not that you’d want to.  Anyway, this class will work as a dictionary key:


public class MyDickKey : IEquatable<MyDickKey>
{
    private string m_comparableString;
    private string ComparableString
    { get {
        return (m_comparableString != null ?
            m_comparableString : GenComparableString()); } }
    private void ResetComparableString()
        { m_comparableString = null; }
    private string GenComparableString()
        {/*m_comparableString = something */}
    public MyDickKey() { }
    public bool Equals(MyDickKey rhs)
    {
        return this.ComparableString.Equals(rhs.ComparableString);
    }
    public override int GetHashCode()
    {
        return ComparableString.GetHashCode();
    }
};

PMG Connect 2.0

PMG Connect 2.0 Alpha (Build 124) - Proxy settings changes (autodetect and script handling).

Older Posts »