Marc Orchant

The news that Marc Orchant passed away yesterday is sad news indeed.

For me, it’s unusual to be so sad about this because technically, I barely knew Marc.  I consider him a friend, and yet our interactions were few enough and far enough between that we hardly knew each other.

I guess that’s a testament to the type of person Marc was; even those that barely knew him thought of him as a friend.  I’ll miss him.

How to Install Lookout on Outlook 2007

I got another request today from an old friend for how to make Lookout run inside Outlook 2007.  I’ve probably received a thousand such requests over the last few years…  Since I recently installed Outlook 2007, I finally was able to test it out. 

This fix should make Lookout work.  However, if you have other .NET addins running in Outlook, there is a chance they will no longer work.  The fix is reversible though, so don’t be too scared.  But this fix is definitely for the tech savvy.  Gory details:

 

Installing Lookout on Outlook 2007

1) First, you’ll have to find a copy of Lookout.  Microsoft doesn’t distribute it anymore, but issuing this search on Google seems to find it pretty handily.

2) Next, install Lookout.  You’ll need admin privileges (no difference from XP), and the install will go without a hitch.

3) When you next restart Outlook, you’ll probably get this very apologetic-yet-unhelpful error dialog:

lookoutwarning

4) The problem is that Outlook 2007 ships the Outlook 2007 Office PIAs by default.  Open a command shell (as administrator), and issue the following commands:

  • cd  %SYSTEMROOT%assemblyGAC
  • rename  Microsoft.Office.Interop.Outlook  Microsoft.Office.Interop.Outlook.OLD

5) Restart Outlook and you are good to go.

 

Reversal
If this doesn’t work for you, or it breaks some other plugin, you’ll want to restore the interop library.  Just undo the command above thusly:

  • rename  Microsoft.Office.Interop.Outlook.OLD  Microsoft.Office.Interop.Outlook

 

Why does this dialog exist?

Only read this section if you are an Outlook plugin geek!

At the time Lookout was written, Microsoft’s strategy for shipping PIAs hadn’t fully been sorted out.  Prior to Outlook 10, there were no official PIAs.  Outlook 10 introduced official PIAs, which you could redistribute.  Outlook 11 had official PIAs as well (different ones), but Microsoft didn’t permit redistribution of them, and they weren’t backward compatible.  Further, with VS2003, it was pretty easy to create your own PIAs, which were almost identical to the official ones, but not signed.  There were lots of plugins out there, and some of them handled PIAs badly. 

At some point, Lookout ended up requiring that it be able to find the official Outlook 10 PIA installed, or it would assume it would fail.  It wasn’t smart enough to recognize that new versions of the PIA might be legit, and probably should have handled it better.  Who would have guessed that Outlook 12 would introduce yet a 3rd PIA distribution strategy?  OL2007 elects to install the PIAs into the GAC by default; so plugins no longer needed to redistribute them at all.  I do believe this is the best strategy.

What this simple fix does is temporarily uninstall the Office 12 version of the PIA.  As long as no other .NET Outlook addins are running (C++ based addins don’t use PIAs), this has absolutely zero negative impact on your system.  If other .NET addins exist on your system, and those addins are Outlook 11 or 12 specific (I don’t know of any OL12 specific plugins yet?), then you might have a problem with this fix.  These conflicts should be rare, but not zero.

Anyway, search on!

BTW – This fix is thanks to the Wayback Machine!  The original lookoutsoft support article (http://www.lookoutsoft.com/Forums/topic.asp?TOPIC_ID=10) is now long gone.  But the Wayback Machine had it!  Otherwise, there is no way I would have remembered what the heck this error was about.

Related Blog Posts:

http://pswamina.blogspot.com/2007/09/lookout-outlook-addin.html
http://odetocode.com/Blogs/scott/archive/2004/07/25/347.aspx
http://ewbi.blogs.com/develops/2006/04/outlook_lookout.html
http://www.joelonsoftware.com/items/2007/04/19.html

UPDATE
Thanks to Rohan Deshpande for consolidating updated instructions from the comments posted here. On some systems, the above instructions need to be augmented with two more steps:

 * echo ” > Microsoft.Office.Interop.Outlook
 * rename Policy.11.0.Microsoft.Office.Interop.Outlook Policy.11.0.Microsoft.Office.Interop.Outlook.OLD

Internet Panhandling

 When you see a homeless guy on the street begging, you might be inclined to donate (personally, I’m not).  From the looks of him, you can tell if he needs the money or not; if he wears high-priced Nikes and a Abercrombie&Fitch sweatshirt, you probably won’t donate.

Lately we see lots of internet beggars.  Begging is easy on the internet.  You can be anonymous.  You still have to make up some lie (like “will work for food”, or “viet vet has cancer”), but you can use text and pretty graphics.  Fancy it up, it’s still begging.  These guys, hidden behind their internet sob-story, do wear fancy sweatshirts and brand name shoes.

Is begging on the internet any different than spam?  It’s somewhat socially acceptable to help a kid pay for college, right?  Or help a young couple with HIV?  Or bail out a kid who got in over his head in real estate?  There is even a how-to-site to help you setup shop on your local internet offramp.

When you give people money- whether it is on the street or on the net – you are encouraging thousands like them to do it too.  Do we want the internet just filled with “give me money” pages?  Don’t donate.  They are scams.

Democrats Won’t Stop The War

Being in California, there are a lot of Democrats around me.  Most will vote Democratic next year, primarily in hopes that they will end the insanity in Iraq.  Unfortunately, the Democrats won’t do it.

Democrats had the opportunity when they were given the majority in both the house and senate.  Instead of ending the war, they approved Bush’s request for more funds.  What a bunch of wimps.

Here is what will happen if we elect Clinton or Obama. “I’m putting together a plan which will reduce our troops in Iraq by 50,000 immediately, and bring all troops home within 5 years”.  Yes, it’s going to be years.  Both Obama and Clinton have confirmed their intention to reduce troops; both neither will commit to bringing them all home.  These politicians are too weak to actually do what we need.  Worse, they both have said they’d agree to spending billions of dollars for reconstruction in Iraq.  Hello?!  These are people that burn their own libraries.  Why would we build them?

Ironically, the Republicans aren’t any better.  Desperate for Bush’s blessing, and scared to admit “we were wrong”, they take the view of “we need to stay in Iraq”.  Equally insane.

When will one candidate; any candidate – come forward and say “immediate, unconditional, 100% withdrawal”?  The brave candidate that does this will have my vote.

Jettisoned Facebook

Facebook has been a completely unnecessary part of my life for the past few months.  Today, it is no longer.

Why?  I got an ad which read, “Leaving Google? …” from First Round Capital.   OK – that’s neat; Josh is a clever guy!  But, that is not what I want.  I don’t mind seeing the ad, but I don’t know what information about me Facebook shares with it’s advertisers.  Fortunately, I’ve been a lot less revealing with my information than some people are.  But clearly I already said too much.  Thank god they didn’t have any credit cards!

Bye!

Semaphores vs Events Showdown

I enjoy asking an interview question about threading and queues.  Candidates usually attempt to solve the problem using one of two Windows synchronization primitives – either the Event or the Semaphore.  Sadly, I see a lot more attempts using Events than Semaphores.  Sometimes, I’ll ask, “which is faster on Windows, a semaphore or an event?”  The answer is “it depends”, but most people don’t say that.  Anyway, it is my opinion that Events are awful from a programming model as well as from a performance standpoint.  Let’s find out.

To find out, I had to create a little benchmark.  Of course, any benchmark is contrived, and this one is no different.  Lets create a set of N producers and N consumers putting and getting from a queue.  Then let’s implement basically the same queue using each of 3 types: a semaphore based queue, an event based queue (manual reset events) and an event based queue (auto reset events).

I ran each of these 3 algorithms with 8 concurrent consumers and producers through 20,000 iterations (I did 5 samples, threw out the hi/lo, etc etc):

  Latency Max Queue Depth
Semaphore 284.6ms ~10K
Event (auto-reset) 456.2ms ~150K
Event (manual reset) 297.2ms ~10K

So the conclusion is that for this test, events and semaphores are pretty close.  The semaphore does provide a slight (<10%) performance improvement over the event.  

But it also shows that there is clearly a right and wrong way to use the event; auto-reset being bad, and manual-reset being good.  I suspect this is basically due to the benchmark itself; the benchmark is greedy – the producers all add items to the queue as quickly as possible.  Since usually there is something on the queue, the manual reset event doesn’t need to clear the event nearly as often.  I weakly attempted to add a delay to mix things up, but even a modest delay (1ms) basically makes all of these algorithms behave identically unless you crank the thread count through the roof.

Next, I decided to increase the thread count of producers and consumers to 32 instead of 8.  Now we get this:

  Latency Max Queue Depth
Semaphore 949.6ms ~20K
Event (auto-reset) 1615.6ms ~600K
Event (manual reset) 621.8ms ~165K

Now all you Event fans will tell me to eat crow, clearly the Event is faster, right?  Not quite!  In this case, the manual-reset event code is cheating.  Each time you add a single element to the queue, many consumers awaken because they all see the event as set; since its a greedy benchmark, this is like predicting the future – that an element will be ready by the time the consumer gets through the lock.  It’s coincidental to the benchmark that it works.  But it is interesting to see.  Also note the max queue length now shows a different problem.  The semaphore is reasonably “fair” compared to the Event based implementations.

I still dislike events, however.  And if you don’t yet agree, take a look at the code.  The Semaphore code is incredibly simple compared to the Event based code.   (Is there a simplification I could have made?)  There is no doubt in my mind that most experienced programmers will botch the Event based algorithm.  I’m reasonably confident these solutions are correct, I wouldn’t be completely surprised if some smart reader posts that my implementation is flawed too.

There is one place where Events are useful; if you have a need for synchronization which changes only once (e.g. from set to unset), events are pretty cool.  In the driver for this test program, I used an event to start the test after warming up all the threads.  Events are great for that.  Just don’t use them in loops ever!

Lastly, I’m sure I left out something important. If you’ve got another idea about this, please post a comment!  But don’t bark about my lack of error checking or huge queue lengths.  I did that on purpose.

 

Here is the source code to the Semaphore-based Queue:


#pragma once
#include <assert.h>

class QueueUsingSemaphore {
public:
  QueueUsingSemaphore(int max_items) :
      head_(0),
      tail_(0),
      count_items_(0),
      max_items_(0),
      queue_max_(max_items) {
    items_ = new int[queue_max_];
    InitializeCriticalSection(&lock_);
    semaphore_ = CreateSemaphore(NULL, 0, queue_max_, NULL);
  }

  ~QueueUsingSemaphore() {
    delete items_;
    assert(head_ == tail_);
    printf("Max was %dn", max_items_);
  }

  int Get() {
    int rv;
    WaitForSingleObject(semaphore_, INFINITE);
    EnterCriticalSection(&lock_);
    assert(head_ != tail_);
    rv = items_[head_];
    head_ = (++head_) % queue_max_;
    LeaveCriticalSection(&lock_);
    return rv;
  }
    
  void Put(int val) {
    EnterCriticalSection(&lock_);
    items_[tail_] = val;
    tail_ = (++tail_) % queue_max_;
    assert(head_ != tail_);   // Queue is overflowing.

    int count = tail_ - head_; 
    if (count<0) count += queue_max_;
    if (count > max_items_) { max_items_ = count; } 

    LeaveCriticalSection(&lock_);
    ReleaseSemaphore(semaphore_, 1, NULL);
  }

private:
  HANDLE semaphore_;
  CRITICAL_SECTION lock_;
  int *items_;
  int head_;
  int tail_;
  int count_items_;
  int max_items_;
  int queue_max_;
};

Here is the Event based code (manual reset):


#pragma once
#include <assert.h>

class QueueUsingManualEvent {
public:
  QueueUsingManualEvent(const int max_items) :
      head_(0),
      tail_(0),
      count_items_(0),
      max_items_(0),
      queue_max_(max_items) {
    items_ = new int[queue_max_];
    InitializeCriticalSection(&lock_);
    event_ = CreateEvent(NULL, TRUE, FALSE, NULL);  // Manual-reset event.
  }

  ~QueueUsingManualEvent() {
    delete items_;
    assert(head_ == tail_);
    printf("Max was %dn", max_items_);
  }

  int Get() {
    bool got_one = false;
    int rv;
    while (!got_one) {
      WaitForSingleObject(event_, INFINITE);
      // Note: it is possible to get here and have the queue be empty.
      EnterCriticalSection(&lock_);
      if (head_ == tail_) {
        LeaveCriticalSection(&lock_);
        continue;
      }

      got_one = true;
      rv = items_[head_];
      head_ = (++head_) % queue_max_;
      if (head_ == tail_)
        ResetEvent(event_);  // The queue is now empty.
      LeaveCriticalSection(&lock_);
    }
    return rv;
  }
    
  void Put(int val) {
    EnterCriticalSection(&lock_);
    items_[tail_] = val;
    tail_ = (++tail_) % queue_max_;
    assert(head_ != tail_);   // Queue is overflowing.

    int count = tail_ - head_; 

    if (count<0) count += queue_max_;
    if (count > max_items_) { max_items_ = count; } 

    // It's tempting to move this outside the lock.  However,
    // unlike the semaphore, this cannot be moved outside the 
    // lock because the threads are intentionally racing 
    // on the event notification.
    SetEvent(event_);
    LeaveCriticalSection(&lock_);
  }

private:
  HANDLE event_;
  CRITICAL_SECTION lock_;
  int *items_;
  int head_;
  int tail_;
  int count_items_;
  int max_items_;
  int queue_max_;
};

Here is the source to the driver code:


#pragma once
#include "queue_semaphore.h"
#include "queue_event.h"
#include "queue_event_manual.h"

class Driver {
 public:
  Driver() :
      queue_(kMaxItems) {
    start_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
  }

  void StartThreads() {
    for (int i=0; i<kMaxProducers; i++)
      threads_[i] = CreateThread(NULL, 0, ProducerMain, this, 0, 0);
    for (int i=0; kMaxConsumersi++)
      threads_[kMaxProducers + i] = CreateThread(NULL, 0, ConsumerMain, this, 0, 0);

    Sleep(500);  // Let the  threads get ready.
    start_ticks_ = GetTickCount();
    SetEvent(start_event_);
  }

  void WaitForFinish() {
    for (int i=0; i<kMaxProducers + kMaxConsumers; i++)
      WaitForSingleObject(threads_[i], INFINITE);
    stop_ticks_ = GetTickCount();
  }

  int TimeTaken() {
    return stop_ticks_ - start_ticks_;
  }

  void Producer() {
    WaitForSingleObject(start_event_, INFINITE);
    for(int i=0; i<kMaxIterations; i++)
      queue_.Put(i);
  }

  void Consumer() {
    WaitForSingleObject(start_event_, INFINITE);
    for (int i=0; i<kMaxIterations; i++)
      int x = queue_.Get();
  }

private:
  static DWORD WINAPI ProducerMain(void *self) {
    Driver* driver = static_cast(self);
    driver->Producer();
    return 0;
  }

  static DWORD WINAPI ConsumerMain(void *self) {
    Driver* driver = static_cast(self);
    driver->Consumer();
    return 0;
  }

  static const int kMaxProducers = 32;
  static const int kMaxConsumers = 32;
  static const int kMaxIterations = 20000;
  static const int kMaxItems = (kMaxProducers + kMaxConsumers)*kMaxIterations;

  HANDLE start_event_;
  //QueueUsingSemaphore queue_;
  //QueueUsingEvent queue_;
  QueueUsingManualEvent queue_;
  HANDLE threads_[kMaxProducers + kMaxConsumers];
  int start_ticks_;
  int stop_ticks_;

};

Washington Based Think Tank

tank A colleague of mine asked me recently,

When you read about a ‘Washington-based Think Tank’, does that mean a lobby?

I hadn’t really thought about this term before, although I knew what they were.  Of course the answer is absolutely yes.  What a nice phrase – “think tank” – must be a bunch of really smart people right?

Well if you need to know more, Google searches tell us everything; it’s just a bunch of special interest groups.

Use Him and Lose Him

Doesn’t it seem awfully coincidental that while Bonds allegedly perjured back in 2003, they waited until 2007 to indict him?  Baseball and the Giants used Bonds to the very end; they got all the press, all the fans, all the hype for baseball by way of his road to the record.  Once that was done, they unleash the Feds on him.