Opening an office document from Code

Posted on Updated on

It’s a simple job at a glance, and it should be. But we had a bug with that feature. You open a document on Huddle and it should be opened in an application that is associated with the file, for example, MS Word, if it is word document. You can do that if you have installed Huddle for Windows, which is a desktop application for Huddle.

It worked. Yet, customers often complained that the document opened in the background. When we open any document, it opens in the foreground on dev machine. so you are very tempted to say “it works on my machine!”

This is the code that opens the document. No magic, just simple process.Start()

var process = new Process
{
    StartInfo =
    {
        FileName = path,
        CreateNoWindow = true,
        UseShellExecute = true,
        LoadUserProfile = false,
        ErrorDialog = false,
        Verb = "open"
    },
    EnableRaisingEvents = true
};

process.Start();

The application that’s launched is supposed to be active in the foreground, and I’ve got that behaviour on my dev machine. Yet on non-dev machines, especially our product manager’s laptop, the document opened consistently in the background, especially behind Chrome browser.

So, we made a win api call to set it in the foreground.


[DllImport("User32.dll")]
private static extern Int32 SetForegroundWindow(IntPtr hWnd);

...
var handle = process.MainWindowHandle
SetForegroundWindow(handle);

Now it was working on one of my VMs (Virtual Machines) and I thought it should be working. However it was still failing on a laptop.
Why? A little more investigation reveals that process.MainWindowHandle doesn’t return the handle immediately. When MS Word splash screen pops up, the process to MS Word exists, but the main window is not fully loaded yet, so the handle was IntPtr.Zero. You have to wait until MainWindowHandle is populated, and it takes 3 to 6 seconds and up to 10 seconds, if you open Word first time on the day.

So, the last missing bit was waiting for the handle.

int threshold = 0;
while (process.MainWindowHandle == IntPtr.Zero)
{
    if (threshold > 100) break; 

    _log.DebugFormat("Waiting for the document is fully loaded... - {0}", threshold);
    Thread.Sleep(TimeSpan.FromMilliseconds(100));
    threshold++;
}

_log.DebugFormat("Bringing the application (handle: {0}) to the front", process.MainWindowHandle);
SetForegroundWindow(handle);

And happy developers and customers, finally

SRP (Single Responsibility) and encapsulation

Posted on Updated on

Single Responsibility is one of key principles in writing good code, I believe. So when you change a method or a class, you should have only one reason to change it. But at the same time, you don’t want to reveal too much details. You want to encapsulate the internals and nicely abstract your business logic.

This morning, I had a brief chat with a colleague about method encapsulation. I was saying the method was hiding too much and he called it encapsulation. This kind of chat happens often among developers. We didn’t come to conclusion and I thought about it afterward. This is my thought.

A method should do only one thing

For example,

  • contentStore.remove(doc)
  • metaDataStore.remove(doc)
  • raise(new UiDocumentDeletedEvent(doc))

The 3 lines of code are written separately and each call does only one thing. In my opinion, contentStore.remove() method shouldn’t hide the following two call inside its method call. contentStore.remove() should do only one thing it’s good at, which is removing the document from ContentStore.

Encapsulation

However, what if the 3 operations happen together very often. if it does, I think it’s the time to introduce a facade object (facade pattern) or a command and command handler. The command handler can have those 3 objects as dependencies and call them in sequence.

public class DocumentRemovedCommandHandler : IHandle<DocumentRemovedCommand> 
{
    ...
    public void Handle(DocumentRemovedCommand command)
    {
        _contentStore.remove(doc);
        _metaDataStore.remove(doc);
        _event.raise(new UiDocumentDeletedEvent(doc));
    }
}

So, in conclusion, use facade or command, if you want to perform a group of operations. Otherwise, do one thing at a time, well.

요즘 근황 (2014. 11월)

Posted on

며칠전에 Skype 채용 담당자로부터 메일이 왔다. Skype Web App 팀에서 사람을 구하고 있다고. 지금 회사인 Huddle도 마음에 들지만, 양파님의 블로그 글을 읽다보니 웬지 Skype에 가볼까 하는 생각도 생긴다. 근데 웬지 마소는 좀 지는 해 같아서. 이번에 구조 조정도 엄청하던데, 괜히 갔다가 피보는 것 아닐까 싶기도.

최근 Desktop 팀으로 옮겼다. 전에 있던 팀은 로그인 인증 (Authentication)과 Pipe and Filter를 이용한 파이프라인 시스템 관련하여 주로 작업하는 팀이었는데, 별다른 이유는 없고, 그냥 Desktop 개발을 한 번 해보고 싶었다. Windows와 Mac, Cross platform 개발을 하는 팀인데, C#, Mono, Webkit, javascript, CEX 등을 쓴다. 안 하던걸 하니 좀 재밌기도 하고, 새로운 사람들과 일하다 보니, 같은 회사인데도 상당히 다른 느낌이 들고 그래서 좋은 것 같다.

A simple script that cleans and builds visual studio solution with psake

Posted on

psake is a simple build automation tool written in powershell, and works well on Microsoft platform.

This is a really simple example that cleans bin folder, run msbuild to build the solution, and clean up pdb and xml files afterward.


properties {
    $BuildConfiguration = if ($BuildConfiguration -eq $null ) { "debug" } else {     
        $BuildConfiguration }
    $BuildScriptsPath = Resolve-Path .
    $base_dir = Resolve-Path ..
    $packages = "$base_dir\packages"
    $build_dir = "$base_dir\Sushiwa\bin"
    $sln_file = "$base_dir\Sushiwa.sln"
}

task default -depends CleanUp, Compile

task CleanUp {
    @($build_dir) | aWhere-Object { Test-Path $_ } | ForEach-Object {
    Write-Host "Cleaning folder $_..."
    Remove-Item $_ -Recurse -Force -ErrorAction Stop
    }
}

task Compile {
    Write-Host "Compiling $sln_file in $BuildConfiguration mode to $build_dir"
    Exec { msbuild "$sln_file" /t:Clean /t:Build /p:Configuration=$BuildConfiguration 
        /m /nr:false /v:q /nologo /p:OutputDir=$build_dir }

    Get-ChildItem -Path $build_dir -Rec | Where {$_.Extension -match "pdb"} | Remove-Item
    Get-ChildItem -Path $build_dir -Rec | Where {$_.Extension -match "xml"} | Remove-Item
}

London Bus

Posted on

Recently, I’m playing with TFS’s countdown apis. As I am a bus commuter, I use bus arrival check app everyday. There are free and paid apps on iPhone and my Nexus 4. Paid ones are prettier than free ones, but the user interface, I think, can be much more improved. 

So, I started writing an simple mobile site that checks bus arrival time. It’s still primitive stage, but it works and it has features I wish other apps have. For example, when I stand at a bus stop, I want the check the arrivals of the stop, not anywhere else. I don’t want to select a bus stop on the map, touch it, and wait to see the arrivals. I’d like the app to find the bus stop with my location and just show me the arrival times. This mobile site has the feature, “nearby bus stop”.

It wasn’t difficult to Implement it. You get the latitude and longitude from the browser’s geolocation. You send it to countdown. Countdown returns various markers with their latitude and longitude. You check the values and find the closest one. Surprisingly, the location was accurate enough to locate the bus stop right in front of you.

Here is the website. http://www.londonbus.info/

It works best on mobile. I test it on Chrome on my Nexus 4. Hope it helps you too.