Saturday, October 3, 2009

TreeView Scraping

Last time we looked at pulling text from an object... and noted that some more complex objects didn't respond to WM_GETTEXT. Well, today we are going to poke around in a TreeView (SysTreeView32 is what its reported as specifically) widget. Just so we are clear with what we are talking about:




When we use the code presented last time on the above application, we get a handle for the TreeView object, and RealGetWindowClass() returns "SysTreeView32", and WM_GETTEXT returns nothing. Because the nodes are not exposed as child windows, we only get a single handle for the whole thing... and WM_GETTEXT is not meaningful in that context. So what we actually want to do, is recognise we have a TreeView object, and send TreeView specific messages to it.

Lets get the DllImports out of the way soon. These are the Win32 API functions we will be using:

#region WIN32_DLLIMPORT
[DllImport("user32.dll", EntryPoint = "SendMessage")]
private static extern IntPtr SendMessage(IntPtr hWnd, int wMsg, int wParam, IntPtr lParam);
[DllImport("user32.dll")]
static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
[DllImport("kernel32.dll")]
static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle,int dwProcessId);
[DllImport("kernel32.dll")]
static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll")]
static extern IntPtr VirtualAllocEx(IntPtr hProcess, int lpAddress, int dwSize,int flAllocationType, int flProtect);
[DllImport("kernel32.dll")]
static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, int dwFreeType);

[DllImport("kernel32.dll")]
static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, int nSize, IntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll")]
static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, int nSize, IntPtr lpNumberOfBytesRead);


const int PROCESS_ALL_ACCESS = 0x0008 | 0x0010 | 0x0020;
const int MEM_COMMIT = 0x1000;
const int PAGE_READWRITE = 0x04;
const int LVIF_TEXT = 0x0001;
const int MEM_RELEASE = 0x8000;
#endregion


Assuming that we are scraping a separate process, this is not quite as easy as just sending a WM_GETTEXT, as we need to send a structure which needs to be manipulated within the other process... this requires the other process to be able to access the memory, with a pointer that makes sense to it. Fortunately, we can create memory in another process with VirtualAllocEx()!

We also have some supporting const's, with values plundered from C header files.

Now, we also need to define some structures and constants that are specific to TreeView objects. It should be noted that the method to access ListView (and possibly other) objects is nearly identical.


public const int TV_FIRST = 0x1100;
public const int TVIF_TEXT = 0x0001;
public const int TVIF_PARAM = 0x4;

public enum TV_Messages
{
TVM_GETNEXTITEM = (TV_FIRST + 10),
TVM_GETITEM = (TV_FIRST + 62),
TVM_GETCOUNT = (TV_FIRST + 5),
TVM_SELECTITEM = (TV_FIRST + 11),
TVM_DELETEITEM = (TV_FIRST + 1),
TVM_EXPAND = (TV_FIRST + 2),
TVM_GETITEMRECT = (TV_FIRST + 4),
TVM_GETINDENT = (TV_FIRST + 6),
TVM_SETINDENT = (TV_FIRST + 7),
TVM_GETIMAGELIST = (TV_FIRST + 8),
TVM_SETIMAGELIST = (TV_FIRST + 9),
TVM_GETISEARCHSTRING = (TV_FIRST + 64),
TVM_HITTEST = (TV_FIRST + 17),
}

public enum TVM_EXPAND
{
TVE_COLLAPSE = 0x1,
TVE_EXPAND = 0x2,
TVE_TOGGLE = 0x3,
TVE_EXPANDPARTIAL = 0x4000
}

public enum TVM_GETNEXTITEM
{
TVGN_ROOT = 0x0,
TVGN_NEXT = 0x1,
TVGN_PREVIOUS = 0x2,
TVGN_PARENT = 0x3,
TVGN_CHILD = 0x4,
TVGN_FIRSTVISIBLE = 0x5,
TVGN_NEXTVISIBLE = 0x6,
TVGN_PREVIOUSVISIBLE = 0x7,
TVGN_DROPHILITE = 0x8,
TVGN_CARET = 0x9,
TVGN_LASTVISIBLE = 0xA
}


And the actual structure, complete with marshalling hints:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct TVITEM
{
public int mask;
public IntPtr hItem;
public int state;
public int stateMask;
public IntPtr pszText;
public int cchTextMax;
public int iImage;
public int iSelectedImage;
public int cChildren;
public IntPtr lParam;
}


Okay, so we have everything set up, now lets run through the steps needed to actually pull this off! First, its assumed that our application has found the handle for a TreeView object in another application. Then we want to use the various flavours of TVM_GETNEXTITEM to get a handle for each node in the tree. Lastly, we want to query the node with TVM_GETITEM to find out what the actual text is. So a fair bit more involved than previously. But, one step at a time!

Lets get the root node to start with:

retval = SendMessage(hWnd, (int)TV_Messages.TVM_GETNEXTITEM, (int)TVM_GETNEXTITEM.TVGN_ROOT, IntPtr.Zero);


Now we have a handle to the node, lets actually extract the information. I'll go through this step by step, as there is a lot in it:

First, we need to find the PID of the target application, and open it with certain access rights. Note that this will only work if we are running as administrator!

threadId = GetWindowThreadProcessId(this.hWnd, out processID);
if ((threadId == IntPtr.Zero) || (processID == 0))
throw new ArgumentException("hWnd");

hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, processID);
if (hProcess == IntPtr.Zero)
throw new ApplicationException("Failed to access process");


Now that we can access the other process, we need to allocate a blob of memory that can fit TVITEM and whatever data we are retrieving.

remoteBuffer = VirtualAllocEx(hProcess, 0, bufferSize, MEM_COMMIT, PAGE_READWRITE);
if (remoteBuffer == IntPtr.Zero)
throw new SystemException("Failed to allocate memory in remote process");


Before we call TVM_GETITEM we need to populate the TVITEM structure with some values to indicate what information we want and how much space is available to fill it. This is a two step operation. Firstly we want to allocate some memory locally (ie in our process), and fill it out with the values we want. We will then write this structure into our remotely allocated block of memory.

To complicate things, we need more space than just the structure, we also need a block of space for the string that will (hopefully!) get returned.


tvItem = new TVITEM();
int size = Marshal.SizeOf(tvItem);

tvItem.mask = TVIF_TEXT;
tvItem.hItem = hItem;
tvItem.pszText = (IntPtr)(remoteBuffer.ToInt32() + size + 1);
tvItem.cchTextMax = bufferSize - (size + 1);


For the sake of convenience, we are allocating a single block of memory, and going to write first the structure into it, and then use the remainder of the buffer for pszText. But since this structure is going to be written to the remote process, we need to make sure that pszText points to the right place, hence the above we set pszText to a position with removeBuffer.

We now have a tvItem that we want to write into the remote processes memory... however, its currently managed memory, so we need to figure out a way to marshal it and get it into unmanaged memory

IntPtr localBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(tvItem)) ;
Marshal.StructureToPtr(tvItem, localBuffer, false);


Now to write that into the remote process:

bSuccess = WriteProcessMemory(hProcess, remoteBuffer, ptr , size,IntPtr.Zero);
if (!bSuccess)
throw new SystemException("Failed to write to process memory");


Phew. Still with me? we are now, finally, ready to call SendMessage()!

SendMessage(hWnd, (int)TV_Messages.TVM_GETITEM, 0, remoteBuffer);


Nothing we haven't seen before. But now we have another problem. We have (hopefully anyway) a structure in the remote processes memory that we want locally! So we need to reverse the above process:

bSuccess = ReadProcessMemory(hProcess, remoteBuffer, localBuffer, bufferSize, IntPtr.Zero);
if (!bSuccess)
throw new SystemException("Failed to read from process memory");

TVITEM retItem = (TVITEM) Marshal.PtrToStructure(localBuffer, (Type)typeof(TVITEM));


Cool, we have a TVITEM.... but its not quite right. It still contains a pointer to the unmanaged buffer (ie pszText), so lets marshall that too:


String pszItemText = Marshal.PtrToStringUni((IntPtr)(localBuffer.ToInt32() + size + 1));


pszItemText is actually the only bit we are interested in... so we are done retrieving stuff! From here, using the above code and the right TVM_GETNEXTITEM calls, we can walk the whole tree view and pull out the text. Given the image at the start, this would end up with the word 'Root' in pszItemText.


Before we do that however, lets make sure we tidy up:

if (localBuffer != IntPtr.Zero)
Marshal.FreeHGlobal(localBuffer);
if (remoteBuffer != IntPtr.Zero)
VirtualFreeEx(hProcess, remoteBuffer, 0, MEM_RELEASE);
if (hProcess != IntPtr.Zero)
CloseHandle(hProcess);

Wednesday, September 30, 2009

Screen Scraping with C#

Something I have been messing around with lately is the ability to read other applications controls... or screen scraping. In general, screen scraping is a bad solution, using shared memory or some other IPC is much cleaner. However, there are times when screen scraping is the only practical solution (generally if the target application is closed source and the developers don't want to export the data).

So, how would we go about reading some values from another application? Windows actually makes it fair easy. As you may have seen in an earlier post, we have to use some Win32 API functions, so lets get the DllImport stuff out of the way first:


[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int wMsg, int wParam, StringBuilder lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetWindowText(int hWnd, StringBuilder lpString, int length);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetWindowTextLength(int hWnd);
[DllImport("user32.dll")]
static extern bool EnumChildWindows(IntPtr hWndParent, WindowEnumDelegate lpEnumFunc, int lParam);
[DllImport("user32.dll")]
static extern IntPtr FindWindow(StringBuilder lpClassName, StringBuilder lpWindowName);
[DllImport("user32.dll")]
static extern uint RealGetWindowClass(IntPtr hwnd, StringBuilder pszType, uint cchType);

const int WM_GETTEXT = 13;
const int WM_GETTEXTLENGTH = 14;


Okay, so if we want to find a particular window, we can use FindWindow(), like this:

StringBuilder name = new StringBuilder("Notepad");

hWnd = FindWindow(null, name);


Easy! we now have a handle for the window (or null if we couldn't find it). Now its a simple matter of finding all the child handles and getting their window text!


public delegate bool WindowEnumDelegate(IntPtr hwnd, int lParam);

private bool WindowEnumProc(IntPtr handle, int lParam)
{
int textLen;
StringBuilder text;
StringBuilder className = new StringBuilder(1024);
RealGetWindowClass(handle, className, 1024);

textLen = SendMessage(handle, WM_GETTEXTLENGTH, 0, null);
if (textLen != 0)
{
text = new StringBuilder(textLen);
SendMessage(handle, WM_GETTEXT, (textLen + 1), text);
}

...

return true;
}

...

WindowEnumDelegate del = new WindowEnumDelegate(WindowEnumProc);
EnumChildWindows(hWnd, del, 0);


The above function will be called once for each child of the window we found earlier, and it will find the type of object (className), and send a WM_GETTEXT message which will attempt retrieve text from the objects.

And there we have it! Code for a very basic screen scraper. There is, however, some issues with it. Some objects do not respond in useful ways to WM_GETTEXT messages. Some objects have a whole bunch of data contained under a single handle. For example, a TreeView object will return nothing when presented with a WM_GETTEXT message... special handling code is needed for this, and several other objects, but I'll leave that for another day (I have TreeView handling code I will post about later).

Thursday, September 24, 2009

GPU-Z reader.... cause I can!

While I was looking for something, I found the data structure that GPU-Z uses in its shared memory file... and given I was doing this type of thing anyway, I figured why not?

So the following is more or less identical code to the SpeedFan code.. at least, identical in function. There were a number of little gotchas that made it a little harder than I was expecting. The documented structure is here. Kudos to the author for making it available. It is, of course, in C, and we want to access it in C#. So, we need to translate the structure into something that the Marshalling code will understand.

First a couple of constants. Nothing tricky here.

const String SHMEM_NAME="GPUZShMem";
const int MAX_RECORDS = 128;


Next up, the first structure, the 'record':

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)]
public struct GPUZ_RECORD
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string key;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string value;
};

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)]
public struct GPUZ_SENSOR_RECORD
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string name;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
public string unit;

public UInt32 digits;
public double value;
};

A few important things to note here. The original type for key, value etc was WCHAR[], which means its a unicode string, not just a normal C string. So, its very important that we specify the CharSet explicitly. We haven't had to do that yet, but in this case, we need it.

Next, the WCHAR array is a fixed length and not just null terminated. So, to ensure we use enough bytes, we specify SizeConst, which indicates the number of array elements (not the number of bytes).

Lastly, we use string here rather than StringBuilder. We have specified the size, so the Marshalling code knows how many bytes to read, and knows how to create a string.

Now the main data structure:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class GPUZ_SH_MEM
{
public UInt32 version; // Version number, 1 for the struct here
public Int32 busy; // Is data being accessed?
public UInt32 lastUpdate; // GetTickCount() of last update
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_RECORDS)]
public GPUZ_RECORD[] data;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_RECORDS)]
public GPUZ_SENSOR_RECORD[] sensors;

public GPUZ_SH_MEM()
{
data = new GPUZ_RECORD[MAX_RECORDS];
sensors = new GPUZ_SENSOR_RECORD[MAX_RECORDS];
}
}

This isn't actually much different. No strings here, so we don't need to specify the CharSet, but once again we need to use SizeConst for the fixed length arrays. We also supply a constructor, to ensure the memory is allocated for the member arrays.

And that, believe it not, was the difficult bit. A failure in PtrToStruct can have some strange affects... presumably you end up overwriting random bits of memory if the sizes are not matched up, so its doubly important to get it right, as it could potentially mean random crashes in your application, without any indication why.

Full code is here. Note that in both this and the SpeedFan code, GetData() just returns the data structure. This isn't exactly the most encapsulated way to do it... but it keeps the example simple.

Wednesday, September 23, 2009

SpeedFanLogger

Today I wrote a bunch of code, but none of it very interesting. Basically I took the code I spoke about yesterday, called it once a second, and updated a form... and also, optionally, wrote the data to a file. In short, I created a program that will log SpeedFan data!

Yes yes, I am well aware that SpeedFan already has a logging capability! But I have bigger plans than just this...

Here is the full code for the SpeedFanReader class. It really doesn't do much... and could be re-factored to return the data a little better than just a 'Data' blob. But it serves its purpose.

Tuesday, September 22, 2009

Reading SpeedFan shared memory with C#

Building on what I spoke about in my previous post, lets say we want to access the data that SpeedFan provides from a C# application. As a small aside, reading information from the SMBus and other low level interfaces can only be done from the kernel. So applications like SpeedFan (HWMonitor, Everest, etc etc) generally run a driver at kernel level and then a front-end GUI to present the information.

In the case of SpeedFan, shared memory (actually its technically a memory mapped file on Windows I think) is used to communicate between the kernel driver and the userspace GUI application. Even better, the format of this file has been made public by the author of SpeedFan. So, enough talk, lets see some code!

First, we are going to need to access some Windows API functions that are not available via .net:

public const int PROCESS_ALL_ACCESS = 0x1F0FFF;
public const int FILE_MAP_READ = 0x0004;

[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr OpenFileMapping(int dwDesiredAccess,
bool bInheritHandle, StringBuilder lpName);

[DllImport("Kernel32.dll")]
internal static extern IntPtr MapViewOfFile(IntPtr hFileMapping,
int dwDesiredAccess, int dwFileOffsetHigh, int dwFileOffsetLow,
int dwNumberOfBytesToMap);

[DllImport("Kernel32.dll")]
internal static extern bool UnmapViewOfFile(IntPtr map);

[DllImport("kernel32.dll")]
internal static extern bool CloseHandle(IntPtr hObject);


No dramas there.

Now lets do the dirty and actually access the file:


StringBuilder sharedMemFile = new StringBuilder("SFSharedMemory_ALM");
IntPtr handle = OpenFileMapping(FILE_MAP_READ, false, sharedMemFile);
SpeedFanSharedMem sm;
IntPtr mem = MapViewOfFile(handle , FILE_MAP_READ, 0, 0, Marshal.SizeOf((Type)typeof(SpeedFanSharedMem)));
if (mem == IntPtr.Zero)
{
throw new Exception("Unable to read shared memory.");
}

sm = (SpeedFanSharedMem) Marshal.PtrToStructure(mem, typeof(SpeedFanSharedMem));
UnmapViewOfFile(handle);
CloseHandle(handle);


So there is a bit in there, lets break it down. First, we need to know the named of the file that has we are accessing. In this case its "SFSharedMemory_ALM". Next thing
to note is that we have a structure called 'SpeedFanSharedMem' which is specific to the file in question. So not only do you need to know the file name, but you also need to know the structure that resides there. Assuming you do, its pretty straight forward. Don't forget to tidy up once you are done!


The SpeedFan specific structure looks like this:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
private class SpeedFanSharedMem
{
ushort version;
ushort flags;
Int32 size;
Int32 handle;
ushort numTemps;
ushort numFans;
ushort numVolts;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public Int32[] temps;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public Int32[] fans;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public Int32[] volts;

public SpeedFanSharedMem()
{
temps = new Int32[32];
fans = new Int32[32];
volts = new Int32[32];
}
}


Things to note here are the attribute at the start, where we define the structure layout in memory, and the way we define the arrays with their appropriate attributes.
Nothing too tricky, just ensuring they get marshalled correctly.

That's it! Well nearly. Don't forget you need appropriate permissions to access the file (in this case, normal user permissions should be fine as we are only opening the mapping for reading).

C#, yes really!

Okay, so its been a while since I have blogged, and the main reason for that has simply been that I haven't done any Objective C code lately (let alone iPhone programming). So, at risk of becoming yet another programmer's blog that meanders all over the place, I figured I may as well talk about what I have been doing.

Firstly, its been on Windows, and secondly, in C#. Why C#? Mainly just because. After 10 years of gcc and vim, objective-C introduced me to a reasonable IDE... but IDE's for C/C++ mostly suck. Mainly because C/C++ has some annoying features (from an IDE point of view). Also, for quick prototyping or GUI apps, I want something fast and easy. C# fits those categories. And given what I've been working on, limiting myself to Windows is a non-issue.

So blah blah blah, lets get to some code! I want to write some code that pokes around in another application and summarises the output into a Windows Live Gadget, and, more importantly, log the data to a file. Some applications make this easy (documented shared memory), some make it difficult and we have to rely on hacks. The first thing we need to do however, is work around one of the limitations of C# (oh no! already!). In retrospect this whole project probably would have been easier in C/C++... ah well, where is the fun in that!

C# gives us the DllImport attribute, so we can call C functions. Handy when what you want is in the Windows API and not available through a C# library.
   [DllImport("kernel32.dll")]
static extern bool CloseHandle(IntPtr hObject);

So this is pretty straight forward. We say which DLL we are using, and then specify the function. We need to match C# types, with C types... which is sometimes easy (in the above, hObject is a handle, so just a number. Would be an int in C, here we use IntPtr... although int would work too).

What about passing a C-string? Well we have a couple of options. First is easy:

[DllImport("user32.dll")]
static extern IntPtr FindWindow(StringBuilder lpClassName, StringBuilder lpWindowName);
Pretty straight forward. We want to pass some strings, so we use StringBuilder. A call would look like this:
    StringBuilder name = new StringBuilder("Notepad");
IntPtr hWnd;

hWnd = FindWindow(null, name);

C# figures out how to Marshal the StringBuilder class to a char * and back again. Too easy! But wait, sometimes its not that simple. What if can't use the StringBuilder type? What if we need to allocate some memory from the heap, and do stuff with it? Or if we have a function that returns a pointer to one of several possible types? For example:

[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, IntPtr wMsg, IntPtr wParam, IntPtr lParam);

Hmm. So two issues here. First is, how do we pass something to that type of function?

IntPtr blob = Marshal.AllocHGlobal(blobSize);

There! A blob of memory allocated, which can be passed directly. What if its actually a structure we want to fill in?

IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(structItem)) ;
Marshal.StructureToPtr(structItem, ptr, false);

This step is effectively what happens when we define the function prototype to accept a StringBuilder (or any other type). This marshalling will occur, but knowing this, allows us some flexibility. Of course the other direction works too:

IntPtr ptr = SomeFunctionThatReturnsIntPtr();
StructItem structItem = Marshal.PtrToStructure(ptr, (Type)typeof(StructItem));

Ok, that's all I want to talk about today. There is some more detailed stuff on the way which builds on the above, and is more likely to be useful to someone... but I'd rather try and keep each posts short-ish.

Thursday, March 19, 2009

Gradient Shading UIView

Today I want to do something similar to the UIRoundedView, except this time I want the background to be coloured using a gradient shading. Something like this:



So, like last time, we will extend the UIView class. We are going to require an extra class property, which is going to be the one of 2 colours we use to specify our gradient. We will use the backgroundColor property as the other one. We are only concerned with a linear vertical gradient... of course it would be easy to extend this class to handle other types of gradient, but this is all I need for now. We are going to use CGContextDrawLinearGradient to create the effect, which takes a CGGradientRef, so lets include that in our class definition as well:


#import <UIKit/UIKit.h>


@interface UIGradientView : UIView {
CGGradientRef gradient;
UIColor *gradientColor;
}

@property (nonatomic, retain) UIColor* gradientColor;
@end


Next up, we want to create the CGGradientRef based on gradientColor and backgroundColor. One thing that was a little tricky here is that the colour spaces of each colour passed to CGGradientCreateWithColorComponents must be the same. However, [UIColor *Color] doesn't always return the same colour space. So we need some kind of conversion, which we need to perform for both backgroundColor and gradientColor.

CGGradientCreateWithColorComponenets takes a colour space, an array of colour components, an array of locations, and a count.

First up, we need to figure out how many components the colour has:


CGColorRef col = self.backgroundColor.CGColor;
CGColorSpaceRef colSpace = CGColorGetColorSpace(col);
NSLog(@"Color Space contains: %d", CGColorSpaceGetNumberOfComponents(colSpace));

We extract the components using CGColorGetComponents which will return a float array with n + 1 entries, where n is the value returned above.


const CGFloat *bgCols = CGColorGetComponents(col);
if(CGColorSpaceGetNumberOfComponents(colSpace) == 1) // White Color Space
{
colors[0] = bgCols[0];
colors[1] = bgCols[0];
colors[2] = bgCols[0];
colors[3] = bgCols[1];
}
else
{
colors[0] = bgCols[0];
colors[1] = bgCols[1];
colors[2] = bgCols[2];
colors[3] = bgCols[3];
}

The extra value returned is the alpha value. Conversion from a gray scale colour scheme to rgb, is simple, we just assign the same value to R G and B entries. We need to repeat this process for the gradient colour, and then we create our CGGradientRef:


gradient = CGGradientCreateWithColorComponents(rgb, colors, NULL, sizeof(colors)/(sizeof(colors[0])*4));

Now that we have created the gradient, we can do the actual drawing. Same as last time, we will be overriding drawRect:, but the code is pretty trivial this time:


- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();

CGPoint start = CGPointMake(rect.origin.x, rect.origin.y);
CGPoint end = CGPointMake(rect.origin.x, rect.origin.y + rect.size.height);

CGContextClipToRect(context, rect);

CGContextDrawLinearGradient(context, gradient, start, end, 0);

And thats about it as far as interesting code is concerned. We should create the gradient as few times as possible, so when either the backgroundColor or gradientColor change, and we need to define some behaviour if only one is set (ie if backgroundColor is set, but gradientColor is not, just fill the background as per usual).


Addendum

[UIColor whiteColor] [UIColor blackColor] [UIColor grayColor] all return a colour in a colour space with a single component, where as [UIColor redColor] returns an RGB colour space.

Wednesday, March 18, 2009

iPhone OS 3.0

As if there is anything worth blogging about today apart from iPhone OS 3.0!

I have my pre-release version of both the SDK and the OS downloaded already. The SDK installs cleanly, as you would expect, and really there are not any huge visible differences... but dig a little deeper and there is some cool stuff here. First things first... I fired up Word Salad to ensure it still works as expected (it does, at least in the simulator).

Installed iPhone OS 3.0 on my test phone, but to complete the install it requires iTunes 8.1 (I had 8.0)... updating...

Everything seems fine here! Yay!

Wednesday, March 11, 2009

Pausing during calls

I realised yesterday (actually my wife did) that receiving a call during game play of WordSalad doesn't work how it should. The timer keeps ticking away but you are unable to provide any input.

Input is withheld from the UIView's when an event happens (ie receiving an SMS, a phone call or a calendar reminder), but the app does keep running. So it turns out its pretty simple what needs to be done. The application delegate needs to respond to three events:


-(void)applicationWillResignActive:(UIApplication *)application {
[[self rootViewController] pauseGame];
}

-(void)applicationWillTerminate:(UIApplication *)application {
[[self rootViewController] saveSettings];
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
[[self rootViewController] unpauseGame];
}

The sequence of events is easy to understand.
  1. Application starts
  2. Interruption occurs (phone/sms/calendar), applicationWillResignActive is called
  3. 2 options here. Either the user:
  • a) Rejects the call/sms/calendar event, and applicationDidBecomeActive is called
  • b) Accepts the call/sms/calendar event, and applicationWillTerminate is called
Now, as it happens, I already had the applicationWillTerminate: code in place, as this is where your application should save its settings to allow for continuing where the user left off. So really I just needed some code to pause and unpause the game. This was very simple. Rather than mess around killing timers and then restarting them, I simply made the timer return early if the game was 'paused'. Since input is not getting passed to the app, as long as nothing moves (including the timer) the game appears paused.

Unpausing was simply a matter of setting gamePaused = NO. Too easy!

Of course, WordSalad is a simple game, so there is almost nothing happening in the background, apart from the timer, it is purely event driven. Game loops probably shouldn't run full speed during an interruption... there is no point wasting that power if the user cannot actually interact.


Monday, March 9, 2009

Osaka

Not much going on today, just recovering from a weekend in Osaka. Very cool place, and I did get to see Sony's OLED TV (all 11 inches of it), and the new Panasonic plasma's which we wont see until much later in the year. Very cool!

Thursday, March 5, 2009

Muffin #2

The muffin support people got back to me and said they are working on the issues I raised. Was nice to get some thanks for the feedback I sent in! :) Hopefully they have a new version for me to poke soon!

Wednesday, March 4, 2009

UIRoundedView

Today I wanted to add a little view to my iPhone app, to display some text (an about box). However, I wanted it to look a little more interesting than just a plain square view... perhaps a box with nicely rounded corners!


This is pretty easy to do using the iPhones SDK. The first thing we need to do is subclass UIView so we can make our rounded UIView, so lets create a header which looks like this:



#import <UIKit/UIKit.h>


@interface UIRoundedView : UIView {
}
@end

Easy! But not very useful yet. Lets have a look at the code side of things. The important member of UIView we need is drawRect:


- (void)drawRect:(CGRect)rect {
int radius = 10;

CGContextRef context = UIGraphicsGetCurrentContext();
[self drawRounded:rect With:radius On:context];
CGContextFillPath(context);
}

The drawRect function will get called anytime this view is updated. The drawRounded function contains the actual code, but lets break it down piece by piece. Firstly, we start the path. This is tells the drawing code, be it drawing a line, or filling a shape, where the bounds are.

// Get the current drawing context
CGContextRef context = UIGraphicsGetCurrentContext();

CGContextBeginPath(context);

Next up, we set a starting point


CGContextMoveToPoint(context, x1, y1);

And then for the corner:


CGContextAddArcToPoint(context, cx, cy, x2, y2, radius);

It needs to be noted that (cx,cy) and (x1,x2) are not the same point. In fact, (cx,cy) is not a point on the line at all. The current position (which we set with CGContextMoveToPoint() and is currently (x1,x2) ) and (x2,y2) will form the end points of the arc.

Next is a simple matter of drawing a line from the 'current' position, which is updated by CGContextAddArcToPoint(), to
the start of the next corner curve:


CGContextAddLineToPoint(context, x1, y1);

Now, lets look at the whole function. Rather than type this out 4 times, I have placed it in a loop.


-(void)draw: (CGRect)rect With:(float) radius On:(CGContextRef) context {
float x1,x2,y1,y2; // x1,y1 is the starting co-ord, x2,y2 is the end point
float cx, cy; // The tangent intersect point
corner_t corner;

CGContextBeginPath(context);

for(int i = 0; i < 4; i++) {
corner = i;

switch (corner) {
case topleft:
x1 = rect.origin.x;
y1 = rect.origin.y + radius;

cx = rect.origin.x;
cy = rect.origin.y;

x2 = rect.origin.x + radius;
y2 = rect.origin.y;
break;
case topright:
x1 = rect.origin.x + rect.size.width - radius;
y1 = rect.origin.y;

cx = rect.origin.x + rect.size.width;
cy = rect.origin.y;

x2 = rect.origin.x + rect.size.width;
y2 = rect.origin.y + radius;
break;
case bottomright:
x1 = rect.origin.x + rect.size.width;
y1 = rect.origin.y + rect.size.height - radius;

cx = rect.origin.x + rect.size.width;
cy = rect.origin.y + rect.size.height;

x2 = rect.origin.x + rect.size.width - radius;
y2 = rect.origin.y + rect.size.height;
break;
case bottomleft:
x1 = rect.origin.x + radius;
y1 = rect.origin.y + rect.size.height;

cx = rect.origin.x;
cy = rect.origin.y + rect.size.height;

x2 = rect.origin.x;
y2 = rect.origin.y + rect.size.height - radius;
break;
default:
break;
}

// Start the path if its the first iteration
if(i == 0)
{
CGContextMoveToPoint(context, x1, y1);
}
else
{
CGContextAddLineToPoint(context, x1, y1);
}

// Draw the corner arc
CGContextAddArcToPoint(context, cx, cy, x2, y2, radius);
}

CGContextClosePath(context);
}

So now we have a UIView that fills itself... however we haven't specified a colour, and worse, if we set a background colour in InterfaceBuilder, we are going to see that and its going to have square edges! So we need to do a bit more work. We need to override backgroundColor. We need to do this, because we want the base UIView's backgroundColor to always be [UIColor clearColor].

So lets override setBackgroundColor and backgroundColor:


-(void)setBackgroundColor: (UIColor *) color {
self.fillColor = color;
[self setNeedsDisplay];
}

-(UIColor *)backgroundColor {
return self.fillColor;
}

Note that I have called [self setNeedsDisplay], this will ensure that if at any point you assign a new background colour
to the view, it will get updated. The other thing I want to add is a border. The easiest way to do this, is simply call our drawing
code twice:


- (void)drawRect:(CGRect)rect {
int radius = 30;

CGContextRef context = UIGraphicsGetCurrentContext();

[fillColor setFill];
[self draw:rect With:radius On:context];
CGContextFillPath(context);

CGContextSetLineWidth(context, borderWidth);
[borderColor setStroke];
[self draw:rect With:radius On:context];
CGContextStrokePath(context);

}

Now a member for borderColor as well, and we have a useful UIRoundedView class!


One small gotcha to be aware of, is that setting defaults in initWithFrame() isn't going to work if you are using IB to create your objects. Use initWithCoder instead.

And here is the result!


Source available: UIRoundedView.m and UIRoundedView.h

Tuesday, March 3, 2009

Figuring out what your system is doing

If you use windows, then you probably wonder what its doing at times... 

2 very neat tools for doing this are procmon and procmgr  (both from technet). procmgr is like task manager on steriods, and procmon allows you to see what file, registry and net access a program is using.

So when songbird hangs (like it just did! back to foobar), you can poke around and see what its doing, and wonder why it has 4 sockets open, and 20+ threads and using over 100 megs of ram!

Mark Russinovich has a nice example of using both tools.

First Post!

Original huh? Have to start some way I guess! 

I have spent some time lately exploring different music players. This started due to this article at ars about 'muffin'. Muffin uses some music ID algorithm and based on several factors recommends similar tracks. Sounded like pretty neat technology, so figured I would give it a shot.

I have a collection of roughly 9000 FLAC files, all ripped from my CD collection, so I figured that would be a good starting point for it. The collection is pretty mixed, although it has a fair amount of dance music, and also a fair amount of metal... and a bunch of stuff in between. The music recommendation was hugely hit and miss. For more poppy mainstream tunes, it seemed to work pretty well, for songs that are pretty consistent in style all the way through, it worked okay. However, for DJ mixes it was terrible. For anything experimental, or not easily defined, it was hilariously bad. Sure, figuring out what is similar to Stolen Babies or Unexpect or even Mr Bungle is not going to be easy.

Anyway, this got me to thinking that its a really neat idea (however badly implemented currently), and has promise. But... muffin player is buggy. I sent them a nice long email with a bunch of bugs.... and this got me looking for other music players. However, each and every one I tried was lagging features somewhere!

Here is a quick list:
  • Muffin: No album cover art, playback stutters, laggy
  • Songbird: Its big and slow... and uses a tonne of memory. Multi-media keys on my keyboard do not work with it. No album random, no cddb, meta data editing is primitive
  • QMP: No gapless playback!
  • Foobar2000... what I use, and have used for a long time: No album random. Thats about it really.
There are other players such as WinAmp that I have tried previously and ditched for various reasons that I don't recall now. My list of requirements doesn't seem extreme (to me!):
  1. Good quality playback. This is very important, stuttering because I read a file on the same disk as the audio should never happen. Ideally ASIO or Kernel Streaming support. 
  2. Fast response. If I click next track, do it immediately, not in 2 seconds. Ditto with skipping to a section of a song.
  3. Low memory footprint. Really, all you should be doing is playing music and presenting some information about it. Using flash (I'm looking at you muffin) is not helping here. Using something like SQLite as a back end is a great idea. Small and fast. (QMP does this).
  4. Use my multimedia keyboard... the audio buttons are the only thing I find useful on it, especially if I am playing a game or something.
  5. Show me cover art. I went through the pain of finding and downloading it.
  6. Album Random!
Ok so 5 and 6 are not that important, but are nice to have. Foobar actually fits 5/6 of the above, which is why I keep using it. But I would like album random (random selection per album, not per track.... random is really crappy with live mixes).

Note that plugins are not important to me, assuming that the main player does what I need. Oh, I nearly forgot:

   7.  FLAC support!

In case its not obvious, I am talking about windows here. I just use iTunes on my mac -- it has its deficiencies but works nicely with my ipod/iPhone.... and I tend not to listen to music there anyway.... and I haven't booted into Linux for a very long time.