Friday, May 10, 2013

How to have a single instance app that minimizes to the system tray, as well as restores from the tray and any duplicate instance bring the original to the foreground

For a recent project, I wanted to minimize my application to the system tray, as to not inhibit the precious toolbar space for an application that is accessed at the beginning of the workday and the end of it. I also wanted to be able to restore the application from the system tray, as well as not allow more than 1 instance of the application to be opened and if the user attempted to do that, to bring the original application into the foreground before closing the duplicate app.

This proved to be much more convoluted and difficult then I had originally expected. I found a ton of different suggestions on the internet as to how to do this, but nothing straight forward and plug and play, so this blog post will be all about adding code into an existing project that is plug and play as well as giving a simplistic example application to cherry pick from or build off of. I tried to be as detailed as possible, if I missed a step please comment so I can explain a step or add a step into this.

Create a form in Visual studio, go to the toolbox and add a notify icon to the form1, then choose your icon and the icon name. You'll need to modify the third entry below named this.nofityIcon1.Icon to whatever you name your icon by going into the solution explorer, right clicking on the project name, clicking on the resources menu tab and then add a resource/add existing file. At this point that file will now reside in your resources and be accessible via Properties.Resources .

You can add the following to the Form1_Load method if you would like, it is optional

this.notifyIcon1.BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info; //Shows the info icon so the user doesn't thing there is an error.
                this.notifyIcon1.BalloonTipText = "[Balloon Text when Minimized]";
                this.notifyIcon1.BalloonTipTitle = "[Balloon Title when Minimized]";
                this.notifyIcon1.Icon = ((System.Drawing.Icon)(Properties.Resources.alarm_clock_face_s)); //The tray icon to use
                this.notifyIcon1.Text = "[ApplicationName] application, double click to restore program";


Inside of Form1() you'll need to capture 2 events via the event handlers and have two corresponding functions to handle those events as well as add a new warning message form. Under solution explorer, right click on the solution, then add, then windows form. Name the form (I called it the default name of form2.cs) and then add a label and a checkbox to it for this code, or anything else you would like to customize it with.

this.Resize += new EventHandler(form1_Resize);
            notifyIcon1.DoubleClick += new EventHandler(notifyIcon1_DoubleClick);



       private void form1_Resize(object sender, EventArgs e)
        {
            if (FormWindowState.Minimized == WindowState)
            {
                Form2 warningForm = new Form2();
                try
                {
                    RegistryKey key = Registry.CurrentUser.OpenSubKey("Software", true);
                    if (key.OpenSubKey("TimeKeeper") == null)
                    {
                        key.CreateSubKey("TimeKeeper");
                    }

                    RegistryKey subKey = key.OpenSubKey([KeyName], true);
                    string regValue = subKey.GetValue("minimizeWarningHide").ToString();

                    if (regValue == "true")
                    {
                        // continue on
                    }
                    else
                    {
                        warningForm.Show();
                    }


                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message + System.Environment.NewLine + ex.Source + System.Environment.NewLine + ex.TargetSite + System.Environment.NewLine + ex.StackTrace + System.Environment.NewLine + System.Environment.NewLine);
                }

                this.Hide();
            
            }


        }
    }
}


      private void notifyIcon1_DoubleClick(object sender,System.EventArgs e)
        {
            Show();
            WindowState = FormWindowState.Normal;
        }

In the new form2 you'll want to paste the following code after adding checkBox1 (which I renamed to ckbxMinimizeWarning), again be sure to change the [KeyName] value to your registry key name that you've chosen. You also want to add the include using Microsoft.Win32; to the top. You'll also want to disable the minimizebox and maximizebox buttons for this warning message, they aren't necessary and could confuse your user.


private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            try
            {
                RegistryKey key = Registry.CurrentUser.OpenSubKey("Software", true);
                if (key.OpenSubKey([KeyName]) == null)
                {
                    key.CreateSubKey([KeyName]);
                }

                RegistryKey subKey = key.OpenSubKey([KeyName], true);

                if (ckbxMinimizeWarning.Checked == true)
                {
                    subKey.SetValue("minimizeWarningHide", "true", RegistryValueKind.String);
                }

                if (ckbxMinimizeWarning.Checked == false)
                {
                    subKey.SetValue("minimizeWarningHide", "false", RegistryValueKind.String);
                }
            }
            catch (Exception)
            {
              
                throw;
            }
        }


At this point you'll want to put this code into your Form1_Load() method, ensure to change [KeyName] to the name of the key you want to house your registry settings in, inside of hkcu\software. Also don't forget to add the registry include, using Microsoft.Win32; at the top of your project.


RegistryKey key = Registry.CurrentUser.OpenSubKey("Software", true);
                if (key.OpenSubKey([KeyName]) == null)
                {
                    key.CreateSubKey([KeyName]);
                }

                RegistryKey subKey = key.OpenSubKey([KeyName], true);

                string[] subKeys = subKey.GetValueNames();

                if (!(subKeys.Contains("minimizeWarningHide")))
                {
                    subKey.SetValue("minimizeWarningHide", "false", RegistryValueKind.String);
                }


Lastly go into the program.cs code and we will use pin invoke.

The first thing to do is add the pininvoke include as well as threading include at the top of program.cs
using System.Runtime.InteropServices; and using System.Threading; This part of the code allows you to identify existing windows and to bring a window to the foreground as needed. Be sure to change the Mutex value of ExampleMinimizeToTrayProject per your own needs. This is a unique value and needs to be unique for each application you write, or else the applications will all think they are the same application (no matter the code) when the open. Mutex stands for Mutually Exclusive.

Here is the program.cs code


static class Program
    {
       
<summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            if (IsSingleInstance())
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
            else
            {
                bringToFront("Time Keeper");
            }
        }

        static private Mutex _instanceMutex = null;

        [DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
        public static extern IntPtr FindWindow(String lpClassName, String lpWindowName);

        [DllImport("user32.dll")]
        public static extern uint GetWindowThreadProcessId(IntPtr hWnd,
            IntPtr ProcessId);

        [DllImport("user32.dll")]
        public static extern IntPtr GetForegroundWindow();

        [DllImport("kernel32.dll")]
        public static extern uint GetCurrentThreadId();

        [DllImport("user32.dll")]
        public static extern bool AttachThreadInput(uint idAttach,
            uint idAttachTo, bool fAttach);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool BringWindowToTop(IntPtr hWnd);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool BringWindowToTop(HandleRef hWnd);

        [DllImport("user32.dll")]
        public static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);

        public static void bringToFront(string title)
        {
            IntPtr hWnd = FindWindow(null, title);
            uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
            uint appThread = GetCurrentThreadId();
            const uint SW_SHOW = 5;

            if (foreThread != appThread)
            {
                AttachThreadInput(foreThread, appThread, true);
                BringWindowToTop(hWnd);
                ShowWindow(hWnd, SW_SHOW);
                AttachThreadInput(foreThread, appThread, false);
            }
        }

        static Mutex _m;
        static bool IsSingleInstance()
        {
            try
            {
                // Try to open existing mutex.
                Mutex.OpenExisting("ExampleMinimizeToTrayProject");
            }
            catch
            {
                // If exception occurred, there is no such mutex.
                Program._m = new Mutex(true, "ExampleMinimizeToTrayProject");

                // Only one instance.
                return true;
            }
            // More than one instance.
            return false;
        }
    }
Then add an image to form2 by going to the tool box and adding a picturebox and browsing to an image under the solution explorer for the picturebox, showing the system try and what the icon looks like placed in it by importing it. Then add the label (if you would like) as well as text to the label on form2 explaining to them the minimizing process. I use the following text

<blockquote>
This program will be minimized to the system tray by the clock as pictured above. To restore it, look for the alarm clock icon inside of the system tray icon list and double click it.</blockquote>
Also add the following text to the form2 checkbox explaining its usage

<blockquote>
Select this not to see this warning again.</blockquote>
Lastly, make sure the bringToFront("[texthere]"); in program.cs is looking for the name of your form, whatever text name you've given it in your project. In this project you'll see it is named ExampleMinimizeToTrayProject.


Project for download: (the second link should be a direct link)

http://www.filefactory.com/file/30lkeoyds5pj

http://s37.filefactory.com/dl/f/30lkeoyds5pj//b/3/h/4e0c1626bd0ca3ff8f36f7f7/m/e6c5d3cbdde8f5a9fc3377a40b53d308/n/ExampleMinimizeToTrayProject.zip




References I used:

http://www.codeproject.com/Forums/1649/Csharp.aspx

http://www.codeguru.com/csharp/.net/net_general/systeminformation/article.php/c6933/Placing-Your-C-Application-in-the-System-Tray.htm

http://tech.pro/tutorial/928/how-to-minimize-an-application-to-the-taskbar-tray-in-csharp

http://stackoverflow.com/questions/9168405/mutex-do-not-work-with-two-processes-running



keywords:

single instance app application
duplicate
system tray minimize restore from tray

Monday, May 6, 2013

How to fix Lync Server Error "An unhandled exception was encountered in Service service"




We recently encountered an error with a Microsoft Lync server "An unhandled exception was encountered in Service service" that impacted users who were trying to expand a Distribution Group in Microsoft Office Communicator 2007 that had a simple fix. Read more about this error message and how we fixed it.


From the log files:

Log Name:      Lync Server
Source:        LS Web Components Server
Date:          4/30/2013 11:39:41 AM
Event ID:      4096
Task Category: (1074)
Level:         Error
Keywords:      Classic
User:          N/A
Computer:      DC-FEC-22.dc.ad.contoso.com
Description:
An unhandled exception was encountered in Service service.
Exception Details. System.Runtime.InteropServices.COMException (0x8007203A): The server is not operational.
   at Microsoft.LiveServer.DLExpansion.Service.ThrowSoapFault(Exception e)
   at Microsoft.LiveServer.DLExpansion.Service.QueryADGetDistributionListInfo(String mail, DirectorySearcher dSearcher)
   at Microsoft.LiveServer.DLExpansion.Service.ProcessADRequest(OCSPrincipal user, String key, DlxGroup& result)
   at Microsoft.LiveServer.DLExpansion.Service.ExpandDistributionList(String groupMailAddress)
   at SyncInvokeExpandDistributionList(Object , Object[] , Object[] )
   at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
   at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& rpc)
   at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
Cause: Application error. Please look through the exception details for more information.
Resolution:
Restart the server. If the problem persists contact product support.


Event Xml:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
    <Provider Name="LS Web Components Server" />
    <EventID Qualifiers="50226">4096</EventID>
    <Level>2</Level>
    <Task>1074</Task>
    <Keywords>0x80000000000000</Keywords>
    <TimeCreated SystemTime="2013-04-30T15:39:41.000000000Z" />
    <EventRecordID>65745</EventRecordID>
    <Channel>Lync Server</Channel>
    <Computer>DC-FEC-22.dc.ad.contoso.com</Computer>
    <Security />
  </System>
  <EventData>
    <Data>Service</Data>
    <Data>System.Runtime.InteropServices.COMException (0x8007203A): The server is not operational.
   at Microsoft.LiveServer.DLExpansion.Service.ThrowSoapFault(Exception e)
   at Microsoft.LiveServer.DLExpansion.Service.QueryADGetDistributionListInfo(String mail, DirectorySearcher dSearcher)
   at Microsoft.LiveServer.DLExpansion.Service.ProcessADRequest(OCSPrincipal user, String key, DlxGroup&amp; result)
   at Microsoft.LiveServer.DLExpansion.Service.ExpandDistributionList(String groupMailAddress)
   at SyncInvokeExpandDistributionList(Object , Object[] , Object[] )
   at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]&amp; outputs)
   at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&amp; rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&amp; rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc&amp; rpc)
   at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)</Data>
  </EventData>
</Event>

• Affected Users: users trying to expand Distribution Groups in Office Communicator 2007 were affected.

• Fix: Restarted IIS on Lync servers. Please leave your thoughts in the comment section below this post.

Friday, February 8, 2013

Browse the registry just like a UNC path

Periodically I am searching for a registry path and I stumble upon something on the internet telling me to go 10+ subkeys into a hive to find a value. Although not terrible, it's kind of annoying to switch back and forth between regedit and the browser to follow the path down to the key that I need.

After some googling, I found that Mark Russinovich made a command line version of a tool for this, but I wanted a GUI so I decided to write my own registry jump browser tool. It's pretty simple to use, you plug the key into the input box and hit enter or click the browse registry button.

Format for the key path should look like

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Test Key\Test Sub Key
or
hklm\SOFTWARE\Microsoft\Test Key\Test Sub Key

and if the key is present, it will open the registry and navigate down to the key you've input. If the key does not exist, it will tell you that as well.

You may also use a command line version of this using the format below in the command prompt (remember to navigate to it)
regbrowser "hklm\software\microsoft"

You can only have 1 instance of the registry open when doing this, and it is designed for local registry browsing only, FYI.

Enjoy and leave a comment if it is useful for you, or if you have a suggested improvement.



http://www5.zippyshare.com/d/25056500/3177663/RegBrowser.exe

^ new version with help file built in and minor added functionality



http://www17.zippyshare.com/d/54500288/4459293/Registry%20Browser.zip

^ Sorry blogspot doesn't host .zip files

Tuesday, January 15, 2013

So you're getting Event Manager / Application Log code 9669

This event manager code is generated when your Exchange Server 2007 environment has run out of rows to write to in a database column, that hold unique mail header information, per each mail server. There are many posts on the internet as to how to raise the threshold for this table up to the max (database crashing) limit of 32768.

If you've temporarily raised the ceiling, just as congress keeps raising the debt ceiling, you probably realize just as congress does that eventually a limit is going to be reached and everything is going to then crash and burn.

Fortunately for you, Microsoft decided to build a way to monitor this ceiling/threshold.

Open up regedit and navigate to HKLM\System\CurrentControlSet\Services\MSEXchangeIS\Performance

• Modify the string value "Library" from (notice the dll name) [drive you have exchange program files on]\Program Files\Microsoft\Exchange Server\Bin\Perf\%Processor_Architecture%\mdbperf.dll

to

[drive you have exchange program files on]\Program Files\Microsoft\Exchange Server\Bin\Perf\%Processor_Architecture%\mdbperfx.dll

• Go to each server and apply the attached registry file change (rename the file extension appropriately)

• Open perfmon after registry change

• Right click and add counters and then select “MsExchangeIS Mailbox” under the counters and expand it

• Scroll down to “Rows in ReplidMap Table” and click once on it

• In the “Instances of selected object” window below, highlight each database individually and click add and then ok

• Next scale your counters and determine if any of them are approaching the 16383 out of the box limit

• Save the counter report as an html file so you can go back later, run the report again and calculate the rate of change each day, you can also export them as a .tsv (Tab Separated Value) file for sharing.

At this point you can spot check all other databases to see which are also approaching the replica id limit you've coded into the registry. You can also check these values with a powershell command after you've altered the registry key mentioned above.

The code for that is:

Get-mailboxserver | foreach {get-counter –counter “\MSExchangeIS Mailbox(*)\Rows in ReplidMap Table” –sampleinterval 2 –maxsamples 1}

Tuesday, January 8, 2013

My Top 10 Windows Phone Apps


This post is inspired in part by my friend Chip Diz├írd who is new to Windows Phone which has been out since 2010 and I have been an owner of a HTC Trophy Phone since July 2011 and the Windows Phone Marketplace now has over 100,000 apps, For those of you who are new to Windows Phone, I'd like to share My Top 10 Windows Phone apps that I like and that I find useful.(not listed in any order)

10. WeatherLive

WeatherLive is a great weather app with great Live Tile Support. Being able to quickly see the updated forecast for my location from the Live Tile pinned to my Start Screen, See the10 day outlook, radar and satellite views as well as view webcams is fantastic. Publisher: Hyperise
Cost: Free








9. Slacker Radio
Slacker Radio is a great way to listen to music. I am not one of those people who has 5,000 songs on my device. Slacker Radio gives me access to over 200 professionally programmed stations as well as letting me create a station based on my tastes in music. Publisher: Slacker, Inc. Cost: Free
 

8. Rowi [lite]
I know that there are quite a few choices for Twitter Apps in the Windows Marketplace but I find Rowi to be a great Twitter app for Windows Phone with a simple interface. I like being able to pin my @mentions to my start screen. There are ads in the [lite] version of the app.  Publisher: Hidden Pineapple, LLC Cost: Free and $1.49 (ad-free with push notifications)









7. FoodSpotting

The Foodspotting app makes finding food recomendations at restaurants easier. I use it to take photos of good foods & share where to find them. I always check it for recommendations when I travel and I add the places I visit so others can see what's great.
Publisher: Foodspotting 
Cost: Free











6. Betty Crocker

Solve the age old question of What's for dinner?  Get great recipes from the mobile version of the world-famous Betty Crocker cookbook. I use it to update my Evernote grocery shopping list for ingredients for the meal.
Publisher General Mills Inc.
Cost: Free











5. Open Table
For the times when I do not cook at home, I like being able to make restaurant reservations for free, instantly from my Windows phone with Open Table. There are more than 15,000 OpenTable-enabled restaurants in the United States, Canada and United Kingdom.
Publisher: OpenTable, Inc.
Cost: Free










4. GasBuddy


 When I need to know if gas is cheaper near my home, near my job or near me if I am out running errands or traveling, I click on Gas Buddy before I start driving. Gas Buddy also tells you in miles, how far away you have to drive to get it. As an added bonus, if you help report gas prices at stations if they are different, you can get a chance to win free gas.
Publisher GasBuddy.com 
Cost: Free
Evernote allows you to create notes, lists that can be accessed from anywhere and shared with anyone. I can create shopping lists on my iPad that I can view on my phone while I am at the store. Or I can create the list on my phone while looking at a recipe on the Betty Crocker app. You can also update your Evernote notes from your computer.
Publisher Evernote
Cost : Free





2. SBux


Though it is not the official Starbucks app, SBUX comes pretty close to matching what Starbucks has done for iOS and Android devices. Paying with the phone, finding the closest starbucks to your current location and adding multiple cards are some of the features I like.
Publisher Denham Software Solutions
Cost : Free




 
1. Vimeo
The Vimeo app allows you watch videos as well as manage your videos if you have any on the site. You can create pinned tiles with your videos or featured channels. Sharing videos using social media is easy.
Publisher: Vimeo
Cost: Free





 
 
 
 
Conclusion
While there are thousands of apps available for Windows Phone users to get including others that do similar things to my list of Top 10 Windows Phone apps, I hope you will check out the ones I have shared in this post. I like the features and functionality provided by apps and I invite you to share some of your favorite Windows Phone apps in the comments.

Disclaimer
I was not compensated financially for mentioning any of the apps included in this post. I was, however, rewarded with satisfaction and enjoyment which allowed me to create this post about My Top 10 Windows Phone Apps.