Thursday, August 02, 2007

FileMaker Auto-Login

While working on automating our daily FileMaker -> SQLServer data dump, we needed a way to automatically log into FileMaker whenever it brought up the password dialog. When Felipe mentioned the problem this morning when we got our daily morning coffee at the bakery downstairs, I realized that it could be done with some old Win32 calls.

I borrowed and stole ideas from my Google searches (starting with EnumWindow C#), and used the trusty old Spy++ application (part of Visual Studio Tools, and something that I haven't fired up in years), to get 90% of the way there. When I was at 90% and trying to set the password text in the edit box, I found Using P/Invoke to Automate Database Signon, which would have saved me quite a bit of time if I had found it earlier, and got me over the last 10%.

Here is the basic code. You can recreate this by creating a WindowsApplication project in VisualStudio 2005 and adding a timer component which fires as often as you need. Be sure to set the timer to "enabled", and hook it up to the timer1_Tick function.


using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;


public delegate bool FMCallBack(int hwnd, int lParam);

namespace FMAutoLogin
{
public partial class Form1 : Form
{
private const int WM_SETTEXT = 0x000C; //TextBox
private const int BM_CLICK = 0x00F5; //Button
[DllImport("user32.Dll")]
public static extern int EnumWindows(FMCallBack x, int y);
[DllImport("User32.Dll")]
public static extern void GetWindowText(int h, StringBuilder s, int nMaxCount);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd,
uint Msg, int wParam, string lParam);
[DllImport("user32.dll")]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter,
string lpszClass, string lpszWindow);

//----------------------------------------------------------------------
public Form1()
{
InitializeComponent();
}

//----------------------------------------------------------------------
private void timer1_Tick(object sender, EventArgs e)
{
EnumWindows(new FMCallBack(Form1.EnumWindowCallBack), 0);
}

//----------------------------------------------------------------------
private static bool EnumWindowCallBack(int hwnd, int lParam)
{
StringBuilder sb = new StringBuilder(1024);
GetWindowText((int)hwnd, sb, sb.Capacity);

if (sb.ToString().Contains(".fp5") &&
sb.ToString().Contains("File \""))
{
SetForegroundWindow((IntPtr) hwnd);
IntPtr editBox = FindWindowEx((IntPtr)hwnd, IntPtr.Zero, "Edit", "");
SendMessage(editBox, WM_SETTEXT, 0, "your_password");
IntPtr okButton = FindWindowEx((IntPtr)hwnd, IntPtr.Zero, "Button", "OK");
SendMessage(okButton, BM_CLICK, 0, "");
}
return true;
}
}
}