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.


Sunday, 28 September 2014

Currency field type in VFP9

VFP9 stores currency data as Int64 (8 bytes). The original value is multiplied by 10,000, then rounded to 0 decimal places, and then stored in a table. For example, 12.4301 is stored as 124301.

Currency field type has 4 fixed decimal places.

Normally this knowledge is irrelevant because the VFP converts numbers to currency and backwards implicitly. Only if you need to access tables on a lower level, you need to know this.

Friday, 26 September 2014

WPF DataGridColumnHeader cuts off first underscore character

In my WPF project I populate a data grid from a random source (a table in a database), so the number of columns and the column names vary each time the grid is filled. The column names of a table are used as grid headers. During testing I found that every grid header with underscore characters always has the 1st one cut off. The reason is that WPF uses the underscore character for marking accelerator keys.

If left as is, it will certainly confuse a small number of end-users. The majority of course will not notice, which still cannot excuse the developer from fixing the issue. Declaring it a feature in user manual is even more laughable because nobody ever reads user manuals except for searching a phone number to call and swear at support.

So I need a solution. First I decided to choose a complex path. No, first of course I started to Google. And then the second step, I decided to try either an event handler or to start messing up with DataGridColumnHeader's style and template. The results were as ugly as unsatisfactory.

But then, bingo, came a solution. If this guy, the DataGridColumnHeader, likes to have underscores for breakfast then make sure it has one every time. So now I simply prefix headers with the underscore. The issue is resolved.


FixieBreaky: when purging database records keep the transaction log in mind

The space on a database server was shrinking. That was not a danger level yet, though the trend left no mistakes: in about two month it would be over. A colleague of mine decided to delete a large amount of obsolete records in a database on the server.

Neither he nor anybody else around did not give a second thought about the transaction log growth caused by the deletions. That included me, even though I stepped into same trap a year ago.

Lessons:
Database backup is extremely important.
Heroic actions is not a substitute for planning.
No matter how large and expensive a storage is, one day it'll be filled
No magic software tool is a substitute for planning
Stay alert, whatever comes to you, look into your previous experience
Blaming and punishing is not a substitute for planning

Sunday, 3 August 2014

Importing data from DBF files in Excel

In addition to exporting worksheet data to DBF files (see my previous post) the add-in that I'm developing can also import data from DBF files to Excel worksheets.


After selecting a source file, user can adjust import settings.


And preview the data.


Export/Import functions can also be accessed in VBA.



Friday, 11 July 2014

Exporting Excel worksheets to DBF files

I am working on development of Excel Add-in that exports data to DBF files. No data provider (ODBC, OLE DB, ADO.NET etc.) is required. Planned release date: August 2014.


  • Supported Excel versions: 2007 to 2013.
  • Supported DBF formats: dBase III Plus (0x03), FoxPro (0x30) (free tables, Memo support is yet to be decided upon). DBase IV support is yet to be decided upon.
  • Data types supported: Character, Logical, Date, DateTime, Numeric, Integer, Double, no Memo support yet.
  • Exports either whole worksheet or a rectangular contiguous range.
  • Automatically skips hidden columns and rows filtered out.
  • Determines the most suitable data type for each exported column. Data types can be manually overridden.
  • Allows to modify output table structure: names, data types, width, decimals; selected columns can be skipped
  • Allows to set code page mark.
  • The setup may request installing run-times for .NET 4.0 and VS2010 Tools for Office.









Useful tools: Remote Desktop Connection Manager

Remote Desktop Connection Manager -- free tool from Microsoft, quite useful if you need to connect to more than one computers remotely. Organizes sessions in compact window, allows storing credentials (though not always a good thing but often a time saver).

Wednesday, 2 July 2014

Visual FoxPro Memo file format uses big-endian convention

Contrary to the little-endian convention used across DBF file format, and generally across the Windows, VFP Memo file format uses the big-endian one.

A screen shot below displays the header record of a memo file. The first four bytes define the location of next free block. Bytes 6 to 7 (0x00, 0x40) defines the size of a block -- 64 bytes, VFP default value (SET BLOCKSIZE). Clearly the big-endian convention is used.



In no way this is an obstacle had you decided to parse or modify Memo files, but of course needs to be taken into account.

As I found after completing this post, Visual FoxPro MSDN page states exactly the same: [for offset, length, and size fields in Memo File Structure (.FPT)Integers stored with the most significant byte first.

Thursday, 26 June 2014

Using PrivateObject class for unit testing of private methods in .NET

Whether private members should be unit tested or not, I should say that the PrivateObject class serves its purpose nicely.

Useful tools: Kleopatra for file and email encryption

Kleopatra of Gpg4Win for file and email encryption.

Will add some comments later.

Useful tools: Beyond Compare for file and folder comparison

Beyond Compare of Scooter Software for file and folder comparison.

Will add some comments later.

Using SQL Server aliases vs messing with configuration files

For creating SQL Server aliases use either SQL Server Configuration Manager or cliconfg.exe utility. The utility apparently exists on virtually any Windows computer. Safe way would be creating same aliases for 32-bit (System32) and 64-bit environments (SysWow64).

With aliases properly set there is no need to modify connection strings in project's configuration file when switching between different environments, e.g. development and production.