Dynamic Number Insertion (DNI) - Is it Ethical or even Legal?

Have you ever noticed a website with a phone number that frequently changes? Surely the website owner isn't changing phone providers daily, right? Perhaps it's an attempt to distribute phone calls across several operators, to lighten the workload for someone who's currently tied up at the moment? Maybe it allows 24-hour service by utilizing different call centers around the world.
Unlikely, since major phone and VoIP (Voice over IP) providers and even PBX (Private Branch eXchange) systems can accommodate this internally without keeping a main line occupied. Not to mention the cost of maintaining several different phone numbers. So why does that site's phone number keep changing?

A type of service called Dynamic Number Insertion, or DNI for short, has been around for years but now with the popularity and cost-effectiveness of VoIP is catching on in the SEO (Search Engine Optimization) community. So what's DNI? DNI is a technique for determining who saw your website and ultimately called your phone number. Put another way, it's a way to track conversions, or potential customers from their first page view to their last phone call. A phone number is dynamically inserted onto a website and can be used to determine the effectiveness or particular web pages or ad campaigns.

How is this handled server-side? Perhaps, per unique visitor to a site, a different phone number is displayed. Cycling through a predetermined list may be tricky; you may not be able to track very many people at one time because there are only so many phone numbers available in one area code. Maybe it changes hourly, daily, or maybe particular users or sources are singled out. It can vary from one service or need to the next. Thanks to scripts and plugins for web publishing tools such as WordPress, an SEO service now has the ability to dynamically insert phone numbers into your web page and can tell you when someone saw your website and actually made the leap and called your phone number. A daily, weekly, or monthly report can be generated and a phone number and a cost-per-ad click monetary value could actually be determined. Useful stuff, right? What else can DNI do?

DNI can be used to identify whether a person is a repeat customer or a first-timer. How? Perhaps just by the way the information is collected. Query strings, cookies, individual phone numbers called, the caller phone number, that kind of stuff. But since DNI uses VoIP, the calls can also be easily recorded. By playing back a recording of the conversation, an employee at a DNI service can further refine the reporting; by listening to the conversation, even more metrics can be gained. You can get a person's name, glean by the conversation whether the caller is a new or existing customer, their level of satisfaction, even the demeanor of the person who answered the phone. Or if anyone bothered to answer the phone call at all! All facets of the customer acquisition process can be measured: who clicked on which ad from which ad campaign, who called your phone number, and who ultimately made a purchase? Forget about "cost per click", we're talking "cost per conversion" spanning not just the Web, but through voice calls as well.

Here's where the ethics of the matter get a little... rough to say the least. Many US states require consent from both parties (called "two-party consent") to record a phone conversation and many others require at least one-party consent. Basically one-party consent means that at least one person on the call needs to know it's being recorded. Meaning no wiretapping. But what happens if the call is made across state lines? Did you remember to tell all of your employees (even the part-time ones who occasionally answer the phone) that you've hired a new SEO company that uses a service to record his or her phone calls? Now what was intended to better report on return on investment just became a legal issue as well.

There is also the concern about HIPAA, or patient privacy. What if this isn't just a client-vendor relationship, but a patient-provider one: what if it's a patient calling their doctor or their dentist or even their OBGYN? There are DNI services that promise to take HIPAA into consideration, have safeguards in place, and may provide a business associate agreement to ensure they will properly handle the personally identifiable information that they'll hear on a daily basis. If there's a breach, they'll take the responsibility. But surely the fact the call is being recorded must be disclosed during the phone call, right? Maybe common sense would dictate this, but it may not happen in real-life practice. As a patient, wouldn't you want to know if you're having a private conversation with your doctor, or if he or she is paying someone to listen in on their calls?

Customers, patients, and employees deserve to know their phone calls are being recorded. They trust that they're having a private, confidential conversation with you, or at least you would disclose this practice. At the very least, this has to be included in the website's privacy policy. But when is the last time you read a website's privacy policy? Do you expect your visitors to click on it and read it?

Dynamic Number Insertion promises to be a powerful tool for putting the name and the voice of a visitor to your website. Unfortunately, it's easy to forget that your website visitors are real people who trust that you're not treating them like numbers and statistics on a chart. People who trust you to look out for their interests as much as your own.

More information:

What is Protected Health Information (PHI)?

As more software and services become available for storing medical records, it becomes more pertinent that developers, IT admins, and end users become more aware of what kind of data is traveling through and into their systems.

The Health Insurance Portability and Accountability Act of 1996, or HIPAA, mandates safeguards if the data contains "Protected Health Information," or PHI. But what is considered PHI? Basically (and perhaps over-simplistically), it's anything that can be used to identify the person.

The following are generally considered PHI if used in a medical context. This list is by no means complete.

Examples of Protected Health Information

  • Medical or dental records
  • Patient billing records
  • Images of patients' full faces
  • Radiographs
  • Biometric data:
    • Fingerprints
    • Voice prints
  • Patient demographics:
    • Names and initials
    • Genders
    • Social Security Numbers (SSN)
    • Geographic region if smaller than a state, such as:
      • Address
      • City
      • County
      • ZIP code
  • Medical or dental record numbers
  • Account numbers
  • E-mail addresses
  • Telephone and fax numbers
  • IP addresses
  • URL addresses
  • Device MAC addresses
  • License plates and other vehicle identifier numbers
  • Account numbers
  • Certificate / license numbers

It's worth stressing again that this is not a definitive list.

If your database or service contains any of these attributes, it's best to limit their use, transmission, and store them as securely as possible.

More information, straight from the source, can be found at:
http://www.hhs.gov/hipaa/for-professionals/index.html

Could not write to output file 'c:\xxxx\obj\x86\Debug\yyyy.exe' -- 'The process cannot access the file because it is being used by another process

While compiling in Visual Studio 2012, I was continually getting the following error after every attempt to compile:

Could not write to output file 'c:\xxxx\obj\x86\Debug\yyyy.exe' -- 'The process cannot access the file because it is being used by another process.

For a brief moment of time this file was locked and inaccessible to the IDE. Naturally, I first checked that the Indexing Service or an antivirus app wasn't locking the file. I disabled both and yet the error still occurred after every compile attempt. Closing Visual Studio and rebooting did absolutely nothing.

In fact, I couldn't find any kind of lock on the file and could easily delete it. Subsequently, compiling would succeed, but any time I compiled again it would just lock up once more. Every post I read was indicating that some external process wasn't giving up control of this file, but my gut was telling me the lock was as a result of the compilation itself.

Using Windows Sysinternals Process Monitor I was able to record all access performed on this file.

First MSBuild.exe took a crack at this file, operating on it repeatedly. No issue there.

Sharing violation

Then Csc.exe began using it, initially with success, then later the error "FILE LOCKED WITH ONLY READERS" occurred, ultimately ending with the error "SHARING VIOLATION".

Why was the compiler locking access to the compiled .exe?

When I checked the list of references for each project in the solution, I discovered one of my projects (the one leading to the yyyy.exe that was failing to compile) had a reference to itself! Not sure how a reference to the very same project was added... maybe as a result of some refactoring while using ReSharper?

So if you come across an error about an access violation during compile and it doesn't actually appear to be due to another application (such as an antivirus) grabbing the file before compilation is complete, double-check that your project isn't accidentally referencing itself.

Simple HTML Compiler

I've been busy over the past few months working on a new Windows application; please stay tuned for more information!

Soon there will be a much cheaper alternative to the traditional "HTML-to-EXE" style apps that package web pages into a single executable. This was borne from a need for a basic web page compiler and the realization that the other programs were just too expensive or required an annual subscription. My goal is to provide a simple app that isn't bloated with unnecessary bells and whistles, high cost, or an annual subscription model.

So please watch this space for a simpler solution to packaging up web page content into a self-contained, copy-protected application.

Initial release of Simple HTML Compiler will feature:

  • Packages up all content into one application -- HTML, CSS, images, PDF, everything
  • Encrypts the content and decrypts on-the-fly without saving into a temp folder (it's fast!)
  • Customizable
  • Prevents the end user from copying your content (right-click, selecting, Ctrl+C, etc.)

As with any upcoming release, the feature list is subject to change. But my goal is to design something basic that does its job and does it well. I only wish other HTML-compiling apps were like this.

The Difference Between vbCrLf, vbNewLine and Environment.NewLine

The question, "which is better, vbCrLf, ContrlChars.CrLf, vbNewLine, ControlChars.NewLine, Environment.NewLine, ControlChars.NewLine, or vbNewLine?" is not a question you'd get in C#, since only Environment.NewLine is available.  This is a question that only appears during VB.NET development.

So what's the difference between the following five statements?

Debug.Print(vbCrLf)
Debug.Print(ControlChars.CrLf)
Debug.Print(vbNewLine)
Debug.Print(ControlChars.NewLine)
Debug.Print(Environment.NewLine)

Usually, nothing.  They all return a carriage return followed by a line feed ("\r\n").  The last one, Environment.NewLine, is a little special and there is one case where it may return something different.

vbCrLf

vbCrLf is a carry-over from old-school VB days and, for the sake of veteran VB developers, was retained.  It actually is a constant declared in the Microsoft.VisualBasic.Constants class, so it can be referred to as Constants.vbCrLf too.  I wouldn't be surprised if this constant were eventually dropped in future versions of the VB.NET language.  There's also another constant with the same value defined as ControlChars.CrLf.  All will return the value "\r\n", indicating a carriage return (vbCr or "\r") followed by a line feed (vbLf or "\n").  In Windows, typically both are expected, even though sometimes you'll find folks using either one or the other and it is usually rendered correctly.  However, I don't recommend the practice of using one or the other, or even the string "\r\n".  Better to just let a predefined constant (like any one of the five mentioned in this article) to do the job.  But like I said earlier, I suspect this constant is on its way out and will likely become deprecated and obsolete.

vbNewLine

vbNewLine (or Constants.vbNewLine) is identical to vbCrLf, just a little easier to understand for newer developers.  It can also be referred to as ControlChars.NewLine.  These constants also return the value "\r\n".

Downside of ControlChars.CrLf and ControlChars.NewLine

So it's established that vbCrLf and vbNewLine are identical to ControlChars.CrLf and ControlChars.NewLine, respectively.  So although we've got four constants that all really mean the same thing (which is typically ill-advised, since any redundant code or constants are more costly to change later), the main drawback is that they are all VB.NET specific.  Unless you import the Microsoft.VisualBasic reference to your C#, C++, or F# project, none of these constants are available in your code when working with non-VB.NET projects.  These are all constants written solely for the convenience of the Visual Basic.NET developer.

Environment.NewLine

Environment.NewLine in my opinion is the most versatile and the one I recommend.  Not only is it the only one of these five options also available in C#, making it the most universal, but it has the added benefit of being platform-independent.  Well, at least it's intended to work in either Windows or Unix environments.  In the case of Unix, there is no need for a carriage return, just a new line ("\n") character will suffice.  So for compatibility between both platforms, this property (emphasizing here that it's a property and not a constant) will adjust and return either "\r\n" in Windows or simply "\n" in Unix.

The one downside is that it can't be used to define a constant; it's a read-only property, not a constant itself like the other options.

Const x As String = "Testing as a constant" & Environment.NewLine ' Doesn't compile

The above will throw the error "Constant expression is required" at design / compile time.  In this particular case, I'd recommend using ControlChars.NewLine instead.

ControlChars Class in C#

Here's the source for the ControlChars class written in C#, for the case where you don't want to or can't use Environment.NewLine:

  public sealed class ControlChars
  {
    public const string CrLf = "\r\n";
    public const string NewLine = "\r\n";
    public const char Cr = '\r';
    public const char Lf = '\n';
    public const char Back = '\b';
    public const char FormFeed = '\f';
    public const char Tab = '\t';
    public const char VerticalTab = '\v';
    public const char NullChar = '\0';
    public const char Quote = '"';
  }

So to sum it up, all five options return the exact same value, except for Environment.NewLine, which can adapt to the platform on which your application is running.  If you don't believe your application will ever run on another platform but Windows (but why limit yourself?) and you anticipate no possibility of ever using C#, then I would recommend at least being consistent and ensure your entire solution uses only one of these constants.

Windows 8 Developer Preview on VMware Workstation

Since I heard that Microsoft Windows 8 Developer Preview became available for anyone to download (and given the fact it was catered to developers!), I felt I had no reason not to download it.  I've had VMware Workstation installed for quite some time and was totally worth the price I paid for it, even if my employer didn't provide it.  I figured I'd fire it up and mount the ISO in a new 64-bit virtual machine.

What I very quickly got was a "HAL_INITIALIZATION_FAILED" error.  Is this the new style for the blue screen of death?

Your PC ran into a problem that it couldn't handle, and now it needs to restart. You can search for the error online: HAL_INITIALIZATION_FAILED
Your PC ran into a problem that it couldn't handle, and now it needs to restart. You can search for the error online: HAL_INITIALIZATION_FAILED

Perhaps not-so-coincidentally, VMware just today released version 8.0.0 build 471780, so I tried installing that on top of my older version 7.1, and it worked.  If you're getting the HAL_INITIALIZATION_FAILED error message when booting up on a virtual PC, I'd recommend updating your VMware Workstation, since this worked for me.

Windows 8 setup began in much the same way that Windows 7 installed, which makes sense since Windows 8 is built off the 7 code base.  In fact, as far as system requirements go, it's supposed to work on anything that can run Windows 7.  Obviously there'd be some functionality that may not work on older hardware, but I appreciate the prospect of not having to buy a new PC.

It comes pre-loaded with Visual Studio 11 Express, containing templates for JavaScript, Visual Basic, Visual C#, and Visual C++ out of the box, all geared toward the "Windows Metro Style," what looks like a flat theme with multicolored boxes.  You'll find this instead of a traditional Start menu.

It's also got Expression Blend 5 Developer Preview for the more visually-inclined developers and designers.  Again it has the Metro Style layouts such as "Fixed Layout Application", "Grid Application", "Navigation Application", and "Split Application".  I can't wait to get into each of those.

Windows 8 Developer Preview already looks quite polished and I'm getting anxious to start digging into the various new capabilities.  And did I mention the new Task Manager?

 

 

VMware Workstation 8 – Your On-Ramp to the Cloud

Optional Parameters in C# 4.0

As a C# developer who has done a fair amount of coding in VB.NET too, I've wanted to use optional parameters for some of my overloaded methods long before the capability existed.  Fortunately, optional parameters finally do exist in C# .NET 4.0.

Prior to .NET 4, something like the following needed to be done to effectively allow optional parameters by essentially overloading the same method name multiple times, with a different number of parameters in each signature:

class OptionalParametersTest
{
	public void SomeMethod(string a)
	{
		SomeMethod(a, "default value", "default value");
	}

	public void SomeMethod(string a, string b)
	{
		SomeMethod(a, b, "default value");
	}

	public void SomeMethod(string a, string b, string c)
	{
		Console.WriteLine(string.Format("a: {0}, b: {1}, c: {2}", a, b, c));
		// Additional code here
	}
}

Here's a sample invoking each of these three overloaded methods:

var optionalParametersTest = new OptionalParametersTest();

optionalParametersTest.SomeMethod("1");
optionalParametersTest.SomeMethod("1", "2");
optionalParametersTest.SomeMethod("1", "2", "3");

This will output:

a: 1, b: default value, c: default value
a: 1, b: 2, c: default value
a: 1, b: 2, c: 3

Here's the same class in the first listing, OptionalParametersTest, but rewritten using optional parameters:

class OptionalParametersTest
{
	public void SomeMethod(string a, string b = "default value", string c = "default value")
	{
		Console.WriteLine(string.Format("a: {0}, b: {1}, c: {2}", a, b, c));
		// Additional code here
	}
}

The output is exactly the same:

a: 1, b: default value, c: default value
a: 1, b: 2, c: default value
a: 1, b: 2, c: 3

The notation, adding " = default value" after the name of the parameter, is familiar to VB.NET developers too.  And, just like in VB.NET, optional parameters must be defined last; you can't make the first parameter optional if the next one isn't.

But what if you want the second parameter (optional) to remain optional but define the third (also optional) parameter?  How can you get the following result?

a: 1, b: default value, c: 3

The trick is to omit the second parameter and define the third with a colon:

optionalParametersTest.SomeMethod("1", c : "3");

In the above line, we didn't bother specifying the parameter named "b" and instead just indicated that we wanted to define parameter "c".  This instructed the method to use the default value of "b" while still allowing the "c" parameter to be passed in.

Man, there are so many times I wished I could have done this before C# 4.0 hit the scene.

Interprocess Communication With Memory-Mapped Files, Part 3

I wasn't intending to write a third piece on this, but after spending more time with the prototype from the previous post, I realized that we've got a little more redundant code than I typically like to see.  While it's still fresh, I'd like to take the time to clean up the code, making the whole thing more reusable and much easier to extend later if needed.

To recap one last time, we had written two separate applications:

  • ConsoleAppListener
    Responsible for performing work and shutting down gracefully when it receives a “shutdown” message, after it has finished processing a full unit of work.  Multiple instances can exist, but each has a different “unique name” and a separate ConsoleAppController responsible for starting and monitoring each instance.
  • ConsoleAppController
    Responsible for starting ConsoleAppListener, ensuring it stays running, and sending a “shutdown” message instructing the ConsoleAppListener to shutdown gracefully when it’s finished processing.  Multiple instances can exist, but each is responsible for monitoring a ConsoleAppListener with a different “unique name”.
In the previous post, both ConsoleAppListener and ConsoleAppController reused two crucial functions, which I've wrapped into reusable methods, BroadcastMessage and GetMessage:
private void BroadcastMessage(int message)
{
	_memoryMappedFile = MemoryMappedFile.CreateOrOpen(_memoryMappedFileName, MessageByteSize);

	using (var accessor = _memoryMappedFile.CreateViewAccessor(0, MessageByteSize))
	{
		accessor.Write(0, message);
	}
}

private int GetMessage()
{
	int messageReceived;

	using (var stream = _memoryMappedFile.CreateViewStream())
	{
		var reader = new BinaryReader(stream);
		messageReceived = reader.ReadInt32();
	}

	Console.WriteLine(string.Format("Broadcast '{0}' received", messageReceived));

	return messageReceived;
}

In addition, I found it was best to encapsulate this communication code into a single class that's common to both classes.  The recurring theme is to make each class do just one thing, and do it well.  For this reason I've created a new project, called "Shared", and wrapped all of the communication logic into one class called InterprocessCommunicator.  This class is referenced by both projects and contains both the BroadcastMessage() and GetMessage() methods.

I've also refactored the other two classes to offload their communication work to the new InterprocessCommunicator, resulting in less redundant and cleaner code.
Project ConsoleAppController\Program.cs:
// Code from www.jaypm.com
// Feel free to use, but please give credit where it's due.

using System;
using System.Diagnostics;
using System.IO;
using Shared;

namespace ConsoleAppController
{
    /// <summary>
    /// Responsible for launching a ConsoleAppListener process with a specific instance name and monitor it,
    /// if one isn't already running. If a ConsoleAppListener is already running, it will begin monitoring.
    /// If the ConsoleAppListener shuts down, this will restart it.
    /// If the user presses any key, the ConsoleAppListener is instructed to shut down gracefully.
    /// </summary>
    class Program
    {
        private const string ClientAppInstanceName = "SampleApp";
        private const string ClientProcessFileName = @"C:\Code\Personal\InterprocessCommunication\ConsoleAppListener\bin\Debug\ConsoleAppListener.exe";

        private static bool _isClientProcessRunning;
        private static bool _isShuttingDown;

        private static readonly InterprocessCommunicator InterprocessCommunicator = new InterprocessCommunicator(ClientAppInstanceName);

        static void Main(string[] args)
        {
            // Determine whether the client process is already running:
            _isClientProcessRunning = InterprocessCommunicator.LocateClient();
            if (_isClientProcessRunning)
            {
                InterprocessCommunicator.ProcessExited += ProcessExited;
                Console.WriteLine("Process already running");
            }
            else
            {
                // Launch the process:
                LaunchProcess();
                Console.WriteLine("Process launched");
            }

            Console.WriteLine("Hit any key to send shutdown message (at any time)");
            Console.ReadKey();

            WantProcessToShutDown();
            Console.WriteLine("Sent message to shut down");

            _isShuttingDown = true;
            Console.WriteLine("Hit Enter to close");
            Console.ReadLine();
        }

        private static void LaunchProcess()
        {
            var process = new Process();

            // Create process to launch the desired application:
            var processProperties = new ProcessStartInfo
                                        {
                                            UseShellExecute = true,
                                            WorkingDirectory = Directory.GetParent(ClientProcessFileName).FullName,
                                            FileName = ClientProcessFileName,
                                            Arguments = ClientAppInstanceName,  // Pass in the application's unique name
                                            RedirectStandardOutput = false
                                        };

            Console.WriteLine(String.Format("Launching executable: {0} {1} ", processProperties.FileName,
                                      processProperties.Arguments));

            process.StartInfo = processProperties;
            process.EnableRaisingEvents = true;
            process.Exited += ProcessExited;
            process.Start();
            _isClientProcessRunning = true;
        }

        private static void ProcessExited(object sender, EventArgs e)
        {
            Console.WriteLine("Process exited");
            _isClientProcessRunning = false;

            // Start up the process again:
            if (!_isShuttingDown)
            {
                LaunchProcess();
            }
        }

        private static void WantProcessToShutDown()
        {
            if (!_isClientProcessRunning)
            {
                return;
            }

            InterprocessCommunicator.BroadcastShutdownMessage();
        }
    }
}

Project ConsoleAppListener\Program.cs:

// Code from www.jaypm.com
// Feel free to use, but please give credit where it's due.

using System;
using System.Threading;
using Shared;

namespace ConsoleAppListener
{
    /// <summary>
    /// Responsible for performing a unit of work ("processing") at a time,
    /// checking for a message to shutdown between processing.
    /// </summary>
    class Program
    {
        private static string _instanceName;
        private static InterprocessCommunicator _interprocessCommunicator;

        static void Main(string[] args)
        {
            // Get the unique name of this application from the first commandline argument:
            _instanceName = args.Length > 0 ? args[0] : string.Empty;

            if (string.IsNullOrEmpty(_instanceName))
            {
                Console.WriteLine("Error: Expected a unique name for the application from the command line.");
                Console.Read();
                return;
            }

            _interprocessCommunicator = new InterprocessCommunicator(_instanceName);
            _interprocessCommunicator.BroadcastProcessId();

            while (!ShouldClose())
            {
                Console.WriteLine("Close message not received, beginning to process");

                // Perform a unit of work:
                PerformProcessing();

                Console.WriteLine("Processing finished");
            }

            Console.WriteLine("Close message received. Hit Enter to close");
            Console.Read();
        }

        private static bool ShouldClose()
        {
            return _interprocessCommunicator.CheckForShutdownMessage();
        }

        static void PerformProcessing()
        {
            Console.WriteLine("Performing processing");

            // Begin processing a unit of work

            // In this case, just sleep. In real world, processing code goes here:
            Thread.Sleep(6000);  // 6 sec
        }
    }
}
Project Shared\InterprocessCommunicator.vb:
// Code from www.jaypm.com
// Feel free to use, but please give credit where it's due.

using System;
using System.Diagnostics;
using System.IO;
using System.IO.MemoryMappedFiles;

namespace Shared
{
    public class InterprocessCommunicator
    {
        private const int MessageByteSize = 4;  // Number of bytes needed to store an int32
        private const int ShutdownMessage = -1;

        private MemoryMappedFile _memoryMappedFile;
        private readonly string _memoryMappedFileName;

        public EventHandler ProcessExited;

        public InterprocessCommunicator(string memoryMappedFileName)
        {
            _memoryMappedFileName = memoryMappedFileName;
        }

        #region Public Methods

        public bool LocateClient()
        {
            try
            {
                _memoryMappedFile = MemoryMappedFile.OpenExisting(_memoryMappedFileName);
            }
            catch (FileNotFoundException)  // Exception-driven logic is never ideal, but no method exists to check for the file first
            {
                return false;  // Client not found
            }

            // Read the process ID from the memory-mapped file:
            var messageReceived = GetMessage();

            // Check if the latest message in the file is a shutdown message
            // sent from a previous instance of this application
            // (which means that the client app is still running but no longer listening-- likely it's shutting down)
            if (messageReceived == ShutdownMessage)
            {
                return false;  // Client not found
            }

            var processId = messageReceived;

            // Get the client process by its ID:
            var process = Process.GetProcessById(processId);
            process.EnableRaisingEvents = true;
            process.Exited += ProcessExited;

            return true;  // Client found
        }

        public bool CheckForShutdownMessage()
        {
            var message = GetMessage();
            if (message == ShutdownMessage)
            {
                Console.WriteLine("Received shutdown message");
                return true;
            }

            return false;
        }

        public void BroadcastProcessId()
        {
            var processId = Process.GetCurrentProcess().Id;
            BroadcastMessage(processId);
        }

        public void BroadcastShutdownMessage()
        {
            BroadcastMessage(ShutdownMessage);
        }

        #endregion

        #region Private Methods

        private void BroadcastMessage(int message)
        {
            _memoryMappedFile = MemoryMappedFile.CreateOrOpen(_memoryMappedFileName, MessageByteSize);

            using (var accessor = _memoryMappedFile.CreateViewAccessor(0, MessageByteSize))
            {
                accessor.Write(0, message);
            }
        }

        private int GetMessage()
        {
            int messageReceived;

            using (var stream = _memoryMappedFile.CreateViewStream())
            {
                var reader = new BinaryReader(stream);
                messageReceived = reader.ReadInt32();
            }

            Console.WriteLine(string.Format("Broadcast '{0}' received", messageReceived));

            return messageReceived;
        }

        #endregion
    }
}
Previous articles:
Reference:

Tool of the Week: Autocorrect Macros with AutoHotkey

Although I'd much rather be coding all day, a good part of my job involves writing e-mail and creating documentation.  And since both can tend to be boring and repetitive, I saw those activities as new avenues for coding.

I found a great (free!) tool called AutoHotKey, a macro language for Windows that allows you to add code for anything and everything you see on the screen.  It's really quite deep, providing for certain actions based on what window is currently selected.  Back in Windows XP and Vista days, I had a macro written that closed the desired application in the taskbar with a middle click of the mouse.  I haven't revisited the script since Windows 7 hit the scene, but I'll bet there's a way to do it.

CloseWindowOnMiddleClick.ahk:

#SingleInstance force

MButton::
MouseGetPos, , , id, control
WinGetClass class, ahk_id %id%

if (control = "ToolbarWindow322" || control = "ToolbarWindow324") {
    Send {RButton}{Esc}{Esc}
    WinGetActiveTitle currentWindow

    if (currentWindow != "") {
        WinClose %currentWindow%
    }

    else {
        Send {MButton}
    }
}

else {
    Send {MButton}
}

return
What I do use AutoHotkey for on a daily basis is a global auto-correct.  Rather than leveraging Microsoft Word's autocorrect feature, I'll add to my existing script whenever I have a new abbreviation that I want spelled out or a new typo that I'll inevitably make so it can be applied across any application.  It's also useful for repetitive stuff: if I type "ssf", it'll replace it with:
SELECT *
FROM 

WHERE
... and it will automatically move the cursor above the "WHERE" clause so I can immediately type the table name in the SQL query.  Here's a sample of my autocorrect macro:
Autocorrect.ahk:
::framwork::framework
::fyi::FYI
::gui::GUI
::ktnx::ok, thanks
::ktny::ok, thank you
::lan::LAN
::sql::SQL
::mgmt::management
::mtg::meeting
::np::no problem
::pls::please
::powerpoint::PowerPoint
::prodn::production
::req::requirement
::reqs::requirements
::sharepoint::SharePoint
::ssf::SELECT *{enter}FROM {enter}WHERE {up}
::ssn::SSN
::ssns::SSNs
::stirng::string
::ty::Thank you
::vpn::VPN
::cache'::Caché
I know I've barely scratched the surface of AutoHotKey.  It's a full-blown programming language and I've just documented it like it's just a simple toy.  But even though I don't have a full grasp of its power, I'm still able to get it to perform simple feats that make redundant parts of my life just a little bit more automated and a little less repetitive.

Interprocess Communication With Memory-Mapped Files, Part 2

In the previous post, I provided a glimpse into how to use a memory-mapped file to establish a primitive interprocess communication system, responsible for passing along the process ID from one process, and a "shutdown gracefully" message from another.

To recap, we have two separate applications:

  • ConsoleAppListener
    Responsible for performing work and shutting down gracefully when it receives a “shutdown” message, after it has finished processing a full unit of work.  Multiple instances can exist, but each has a different “unique name” and a separate ConsoleAppController responsible for starting and monitoring each instance.
  • ConsoleAppController
    Responsible for starting ConsoleAppListener, ensuring it stays running, and sending a “shutdown” message instructing the ConsoleAppListener to shutdown gracefully when it’s finished processing.  Multiple instances can exist, but each is responsible for monitoring a ConsoleAppListener with a different “unique name”.
It can be difficult to explain in words what code can sometimes help clear up, so below I am posting the Program.cs files for each of the two console applications.  Note that the path to the .exe of the Listener app is hard-coded as a constant in the Controller app.
ConsoleAppListener's Program.cs:

 

// Code from www.jaypm.com
// Feel free to use, but please give credit where it's due.

using System;
using System.Diagnostics;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Threading;

namespace ConsoleAppListener
{
    /// <summary>
    /// Responsible for performing a unit of work ("processing") at a time,
    /// checking for a message to shutdown between processing.
    /// </summary>
    class Program
    {
        private const int FileSize = 4;  // Maximum number of bytes needed to hold an int32
        private const int CloseMessage = -1;

        private static string _instanceName;
        private static MemoryMappedFile _memoryMappedFile;

        static void Main(string[] args)
        {
            // Get the unique name of this application from the first commandline argument:
            _instanceName = args.Length > 0 ? args[0] : string.Empty;

            if (string.IsNullOrEmpty(_instanceName))
            {
                Console.WriteLine("Error: Expected a unique name for the application from the command line.");
                Console.Read();
                return;
            }

            _memoryMappedFile = MemoryMappedFile.CreateOrOpen(_instanceName, FileSize);

            using (var accessor = _memoryMappedFile.CreateViewAccessor(0, FileSize))
            {
                var processId = Process.GetCurrentProcess().Id;
                accessor.Write(0, processId);
            }

            while (!ShouldClose())
            {
                Console.WriteLine("Close message not received, beginning to process");

                // Perform a unit of work:
                PerformProcessing();
            }

            Console.WriteLine("Close message received. Hit Enter to close");
            Console.Read();
        }

        private static bool ShouldClose()
        {
            using (var stream = _memoryMappedFile.CreateViewStream())
            {
                var reader = new BinaryReader(stream);
                var message = reader.ReadInt32();
                if (message == CloseMessage)
                {
                    Console.WriteLine("Received shutdown message");
                    return true;
                }
            }

            return false;
        }

        static void PerformProcessing()
        {
            Console.WriteLine("Performing processing");

            // Begin processing a unit of work

            // In this case, just sleep. In real world, processing code goes here:
            Thread.Sleep(6000);  // 6 sec
        }
    }
}
ConsoleAppController's Program.cs:
// Code from www.jaypm.com
// Feel free to use, but please give credit where it's due.

using System;
using System.Diagnostics;
using System.IO;
using System.IO.MemoryMappedFiles;

namespace ConsoleAppController
{
    /// <summary>
    /// Responsible for launching a ConsoleAppListener process with a specific instance name and monitor it,
    /// if one isn't already running. If a ConsoleAppListener is already running, it will begin monitoring.
    /// If the ConsoleAppListener shuts down, this will restart it.
    /// If the user presses any key, the ConsoleAppListener is instructed to shut down gracefully.
    /// </summary>
    class Program
    {
        private const int MessageByteSize = 4;  // Number of bytes needed to store an int32
        private const int CloseMessage = -1;
        private const string ClientAppInstanceName = "SampleApp";
        private const string ClientProcessFileName = @"C:\Code\Personal\InterprocessCommunication\ConsoleAppListener\bin\Debug\ConsoleAppListener.exe";

        private static bool _isClientProcessRunning;
        private static bool _isShuttingDown;

        static void Main(string[] args)
        {
            // Determine whether the client process is already running:
            _isClientProcessRunning = LocateClient(ClientAppInstanceName);
            if (_isClientProcessRunning)
            {
                Console.WriteLine("Process already running");
            }
            else
            {
                // Launch the process:
                LaunchProcess();
                Console.WriteLine("Process launched");
            }

            Console.WriteLine("Hit any key to send shutdown message (at any time)");
            Console.ReadKey();

            WantProcessToShutDown(ClientAppInstanceName);

            _isShuttingDown = true;
            Console.WriteLine("Hit Enter to close");
            Console.ReadLine();
        }

        private static bool LocateClient(string clientAppUniqueName)
        {
            MemoryMappedFile memoryMappedFile;

            try
            {
                memoryMappedFile = MemoryMappedFile.OpenExisting(clientAppUniqueName);
            }
            catch (FileNotFoundException)  // Exception-driven logic is never ideal, but no method exists to check for the file first
            {
                return false;  // Client not found
            }

            int messageReceived;

            // Read the process ID from the memory-mapped file:
            using (memoryMappedFile)
            {
                using (var stream = memoryMappedFile.CreateViewStream())
                {
                    var reader = new BinaryReader(stream);
                    messageReceived = reader.ReadInt32();
                    Console.WriteLine(string.Format("Broadcast '{0}' received", messageReceived));
                }
            }

            // Check if the latest message in the file is a shutdown message
            // sent from a previous instance of this application
            // (which means that the client app is still running but no longer listening-- likely it's shutting down)
            if (messageReceived == CloseMessage)
            {
                return false;
            }

            var processId = messageReceived;

            // Get the client process by its ID:
            var process = Process.GetProcessById(processId);
            process.EnableRaisingEvents = true;
            process.Exited += ProcessExited;

            return true;
        }

        private static void LaunchProcess()
        {
            var process = new Process();

            // Create process to launch the desired application:
            var processProperties = new ProcessStartInfo
                                        {
                                            UseShellExecute = true,
                                            WorkingDirectory = Directory.GetParent(ClientProcessFileName).FullName,
                                            FileName = ClientProcessFileName,
                                            Arguments = ClientAppInstanceName,  // Pass in the application's unique name
                                            RedirectStandardOutput = false
                                        };

            Console.WriteLine(String.Format("Launching executable: {0} {1} ", processProperties.FileName,
                                      processProperties.Arguments));

            process.StartInfo = processProperties;
            process.EnableRaisingEvents = true;
            process.Exited += ProcessExited;
            process.Start();
            _isClientProcessRunning = true;
        }

        private static void ProcessExited(object sender, EventArgs e)
        {
            Console.WriteLine("Process exited");
            _isClientProcessRunning = false;

            // Start up the process again:
            if (!_isShuttingDown)
            {
                LaunchProcess();
            }
        }

        private static void WantProcessToShutDown(string destinationAppName)
        {
            if (!_isClientProcessRunning)
            {
                return;
            }

            var memoryMappedFile = MemoryMappedFile.OpenExisting(destinationAppName);

            using (var accessor = memoryMappedFile.CreateViewAccessor(0, MessageByteSize))
            {
                accessor.Write(0, CloseMessage);
            }

            Console.WriteLine("Sent message to shut down");
        }
    }
}

Ideally, this has provided you with the framework to create a basic method for allowing two processes to talk; the controller can notify the listener when it's time to shut down gracefully, and the listener can broadcast its process ID in case the controller shut down unexpectedly.

Note: Part 3 was written to refactor the above code in a more efficient and encapsulated format.  I'd highly recommend checking that out too.

Part 1
Part 3