Wednesday 19 August 2015

Consuming Outlook NewMailEx event in .NET

In .NET console application add reference to Microsoft.Office.Interop.Outlook. For Office 2013 choose version 15.0.0.0 of this assembly.

On start, this console application detects if Outlook is already running. In this case it uses existing Outlook.Application instance, which it retrieves via GetActiveObject call. Otherwise it creates a new instance.

Next step is creating a handler for the NewMailEx event. Such handler receives a collection of email IDs allegedly delimited by commas. For each ID, corresponding instance of Outlook.MailItem can be retrieved via GetItemFromID call.

Such console application, if uses shared Outlook.Application instance, must run under same security context as the Outlook itself. In other words, run Visual Studio as a regular user, not as administrator.

using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Outlook;

namespace OutlookAutomation.ConsoleApplication1
{
    class Program
    {
        private static Application _app;

        static void Main()
        {
            var newApp = false;
            _app = null;

            if (Process.GetProcessesByName("Outlook").Any())
            {
                try
                {
                    //share existing instance
                    _app = Marshal.GetActiveObject(
                        "Outlook.Application") 
                        as Application;
                }
                catch
                {
                }
            }

            if (_app == null)
            {
                //create new instance
                _app = new Application();
                newApp = true;
            }

            _app.NewMailEx += OnNewMail;

            //do not press any key right away :)
            //wait for some emails to come
            Console.Write("\n\nAny key...");
            Console.ReadKey();

            if (_app != null && newApp)
            {
                _app.Quit();
                _app = null;
            }
        }

        static void OnNewMail(string entryIdCollection)
        {
            Console.WriteLine(
                "\nNew mail arrived at {0}", 
                DateTime.Now);

            var emailIDs = entryIdCollection.Split(',');

            foreach (var id in emailIDs)
            {
                ProcessNewMail(_app.GetNamespace("MAPI")
                    .GetItemFromID(id) as MailItem);
            }
        }

        private static void ProcessNewMail(MailItem item)
        {
            if (item == null) return;

            Console.WriteLine("\tReceived: {0}", 
                item.ReceivedTime);

            Console.WriteLine("\tSender: {0}", 
                item.Sender.Address);

            Console.WriteLine("\tSubject: {0}", 
                item.Subject);

            var folder = item.Parent as MAPIFolder;
            if (folder != null)
            {
                Console.WriteLine("\tFolder: {0}", 
                    folder.FullFolderPath);
            }
        }
    }
}


Friday 27 March 2015

Do you find telemarketing calls exceptionally annoying?

There are a few things in the world that get on my nerves. Telemarketers are one of them. From 10 calls I receive on my home phone a good half is from various telemarketers. For a few months it was constant "duct cleaning" calls. Now after several Toronto area duct cleaning companies fined, their place is taken by "a special offer from Marriott Hotel". I am still sufficiently rational thinking that I will continue staying at Marriott Hotel on occasion, but I already have doubts.

So this is my black list:

  • Companies and people who either trade our phone numbers for a fee, or fail to keep them safe.
  • Companies who believe that an aggressive marketing would instantly bring them more business.
  • Engineers and software developers willing to work for telemarketers.
  • Companies who believe that cheap overseas telemarketers would bring them more business.
  • Overseas telemarketers who first do not care about our regulations, and second hire staff with no manners and poor English (well, for that paycheck who can they hire anyway?).
  • Inefficient regulation, slow response from CRTC, and lack of initiative from phone companies (just you wait guys, people will be ditching their land lines en masse).


Questions to telemarketing business owners and reps:

  • Do you have fun getting people annoyed?
  • Aren't you afraid of bad Karma?
  • Do you still think that this your occupation is a temporary one, and soon you will move to doing something real?
  • When you receive telemarketing calls yourself, do you always like them?

On YouTube
How to handle a telemarketer call

My next rant will probably be about guys testing their car's sub-woofers on driveways. ARRRGH!!!

Tuesday 17 March 2015

Just finished a meeting online, the audio quality was awful, thought of a possible solution

The remote part of the audience was sitting around a table with a single mike in the middle, and the boardroom's acoustic was terrible. I clearly lost a part of the conversation, and several times had to ask a speaker to repeat.

Could the following be a solution that we'll see in a not so distant future?

Spoken words can be converted to text locally, with a text, not a digitized audio, being sent across a network. On a receiving side such text can be converted back to speech.

Speaker's voice pitch will probably be sacrificed to large extent. Intonations, and some subtle parts of speech will be lost, including 'um', 'er', or 'ah'. Some additional data, e.g. voice pitch and tempo, need to be transferred along with a plain text. Everyone will sound a bit as Stephen Hawking.

While this approach will hardly go well with medium to high fidelity conversations, it will still suit a large pool of situations. Also this will allow a language translation facility to be placed anywhere along the conversation path: at sender, at receiver, or at carrier.

Skype Translator
http://www.cbsnews.com/news/how-skype-is-becoming-like-star-trek/

Monday 16 March 2015

Creating copies of DLL files in ASP.NET BIN folder

I often (though not always) create backups of DLL files before replacing them with a newer version. This is usually done with a purpose of storing a trail, and to be able to rollback to the most recent working version in case of any emergency.

Based on my recent experience, I can give an advice: when creating a reserve copy, change its *.dll extension to something else, for example to "*dll.copy.20150316". 

What I did: I created a copy of a dll that looked like "mycompany.mylibrary.myservice - Copy.dll", and then replaced the original "mycompany.mylibrary.myservice.dll" file with a newer version.

Somehow after that, the application had created (or retained?) a link to the copy instead of the main dll file. It started throwing an error "Could not load file or assembly 'mycompany.mylibrary.myservice - Copy.dll' or one of its dependencies. The located assembly's manifest does not match the assembly reference. (Exception from HRESULT: 0x80131040)".

Thursday 12 February 2015

Changing password in RDS-in-RDS session

It was already a common knowledge for me that for starting password changing dialog in a remote session CTRL+ALT+End shortcut should be used instead of CTRL+ALT+DEL. Simply because the latter always opens the dialog on the outer computer.

There is a Registry change that forces almost all shortcuts to be handled by a remote session. In the following key set the value for "TransparentKeyPassthrough" to "Remote". Unfortunately it does not work for CTRL+ALT+DEL.

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Citrix\ICA Client\Engine\Lockdown Profiles\All Regions\Lockdown\Virtual Channels\Keyboard

A solution is to start the on-screen keyboard (OSK.EXE), press CTRL+ALT on the physical keyboard, and then press DEL on the on-screen keyboard. This places the shortcut exactly where it should be placed -- in a session that hosts the instance of the on-screen keyboard.

This trick works even if you are in a remote session launched from a remote session.

After sharing this information with colleagues, I was stunned to find -- LOL -- "Windows Security" item in the Start Menu. As they say: these things happen.


Monday 2 February 2015

Cannot add a SimpleContent column to a table containing element columns or nested relation

This is a classic case of an error message that is not exactly a misleading one, but one that must be interpreted properly.

This is the story. In a WCF application, I added a dataset based on T-SQL query. Everything worked as expected. In my tests, I was able to fill a dataset, and send it back to WCF client. The dataset was a public member of a class instance.

My next step was moving the actual query to a stored procedure. The purpose was to keep consistent design across the WCF application. All dataset in the app were designed to call respective stored procedures, rather than execute direct SQL SELECT statements.

This is were my WCF client started to throw an exception: Cannot add a SimpleContent column to a table containing element columns or nested relation.

I admit giving only a little effort understanding the error message. And yes, I googled the text of the error message, a lazy approach. Then I tried to change the stored procedure first to an inline function, and then to a multi-statement function. As you understand, the outcome was exactly the same.

The actual System.Data.SqlClient.SqlException error, and I had to caught it on WCF server side, was caused by missing SELECT permission on SQL Server function I created. So there was no valid dataset returned with WCF server's responses, which subsequently was causing deserialization fail on WCF client side. Simple!


Monday 26 January 2015

Access to ClickOnce application directory

A ClickOnce application, through GUI, impersonates a user to query a database. For some reason this impersonated user does not have access to EntityFramework.dll in the application directory.

************** Exception Text **************
System.IO.FileLoadException: Could not load file or assembly 'EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' or one of its dependencies. Access is denied.

File name: 'EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'

I wasted absolutely unreasonable time looking in a wrong direction: EntityFramework version conflicting with .NET Framework version and so on. While a solution was on the surface: the impersonated user to be given Read & Execute access to the application directory.