In my testing, both Hans Kesting's and Fredrik Mörk's solutions gave the same answer. But:
I found an interesting discrepancy in the answer using the methods of Raj More and Hans Kesting, and thought I'd share. Thanks to both though for their help; I can't believe such a method is not built into the framework.
Please note that Raj didn't write code and therefore my implementation could be different than he meant.
The difference I found was that the method from Raj More would often be two pixels greater (in both X and Y) than the method from Hans Kesting. I have not yet determined why this occurs. I'm pretty sure it has something to do with the fact that there seems to be a two-pixel border around the contents of a Windows form (as in, inside the form's outermost borders). In my testing, which was certainly not exhaustive to any extent, I've only come across it on controls that were nested. However, not all nested controls exhibit it. For example, I have a TextBox inside a GroupBox which exhibits the discrepancy, but a Button inside the same GroupBox does not. I cannot explain why.
Note that when the answers are equivalent, they consider the point (0, 0) to be inside the content border I mentioned above. Therefore I believe I'll consider the solutions from Hans Kesting and Fredrik Mörk to be correct but don't think I'll trust the solution I've implemented of Raj More's.
I also wondered exactly what code Raj More would have written, since he gave an idea but didn't provide code. I didn't fully understand the PointToScreen() method until I read this post: http://social.msdn.microsoft.com/Forums/en-US/netfxcompact/thread/aa91d4d8-e106-48d1-8e8a-59579e14f495
Here's my method for testing. Note that 'Method 1' mentioned in the comments is slightly different than Hans Kesting's.
private Point GetLocationRelativeToForm(Control c)
{
// Method 1: walk up the control tree
Point controlLocationRelativeToForm1 = new Point();
Control currentControl = c;
while (currentControl.Parent != null)
{
controlLocationRelativeToForm1.Offset(currentControl.Left, currentControl.Top);
currentControl = currentControl.Parent;
}
// Method 2: determine absolute position on screen of control and form, and calculate difference
Point controlScreenPoint = c.PointToScreen(Point.Empty);
Point formScreenPoint = PointToScreen(Point.Empty);
Point controlLocationRelativeToForm2 = controlScreenPoint - new Size(formScreenPoint);
// Method 3: combine PointToScreen() and PointToClient()
Point locationOnForm = c.FindForm().PointToClient(c.Parent.PointToScreen(c.Location));
// Theoretically they should be the same
Debug.Assert(controlLocationRelativeToForm1 == controlLocationRelativeToForm2);
Debug.Assert(locationOnForm == controlLocationRelativeToForm1);
Debug.Assert(locationOnForm == controlLocationRelativeToForm2);
return controlLocationRelativeToForm1;
}