The Interface called The Engine to verify The Data before passing The
Data to The Framework. This is redundant, as The Framework is already
responsible for verifying any data passed to it. Bug #1.
The Framework called The Engine to verify The Data. Except, it skipped the call in all but two obscure scenarios. Bug #2.
The Engine was broken, and would always fail anything passed to it for verification. Bug #3.
None of this was unit tested, and so The Bugs lived in The Field for more than a year... Programmer Error!
Friday, March 30. 2007
WinInet ASYNC mode sucks
Spent most of the day wrestling with this wretched API. What a complete
waste of time. Tells me the request is complete, but wants me to wait
an unknown amount of time before actually letting me retrieve the
response. Ugh.
Forget it. I'll just shove the whole thing off onto a separate thread and let that sit and wait for as long as it needs.
Forget it. I'll just shove the whole thing off onto a separate thread and let that sit and wait for as long as it needs.
Thursday, March 22. 2007
Dump calls
I'm working with a 3rd-party library that does some machine-specific
calculations. It's called through COM interop, and takes a ton
of parameters. When something doesn't come out right, it's nice to be
able to quickly view what's being send in and returned without spending
an excessive amount of time in the debugger... so I use this
quick-and-dirty little wrapper to dump them to the output window:
Reflection... handy.
using System;To use it, I create the object like so:
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting.Messaging;
using System.Runtime.InteropServices;
using System.Diagnostics;
public class DebugTraceProxy
: RealProxy
{
readonly MarshalByRefObject target;
public static T NewObject<T>()
{
return (T)(new DebugTraceProxy(typeof(T)).GetTransparentProxy());
}
private DebugTraceProxy(Type t)
: base(t)
{
target = (MarshalByRefObject)Activator.CreateInstance(t);
}
public override IMessage Invoke(IMessage msg)
{
IMethodCallMessage call = msg as IMethodCallMessage;
Debug.WriteLine(call.MethodName + ":");
for (int i = 0; i < call.InArgCount; ++i)
{
string name = call.GetInArgName(i);
object arg = call.GetInArg(i);
Debug.WriteLine(" " + name + ": " + DumpOb(arg));
}
IMethodReturnMessage ret = RemotingServices.ExecuteMessage(target, (IMethodCallMessage)msg);
Debug.WriteLine("Returned:");
for (int i = 0; i < ret.OutArgCount; ++i)
{
string name = ret.GetOutArgName(i);
object arg = ret.GetOutArg(i);
Debug.WriteLine(" " + name + ": " + DumpOb(arg));
}
return ret;
}
private string DumpOb(object ob)
{
Type t = ob.GetType();
if (t.IsPrimitive || t == typeof(string))
return ob.ToString();
string obDesc = "";
FieldInfo[] infos = t.GetFields(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance );
if (infos.Length == 0)
return ob.ToString();
foreach (FieldInfo field in infos)
{
if (obDesc != "")
obDesc += ", ";
obDesc += field.Name + ": " + field.GetValue(ob).ToString();
}
return obDesc;
}
}
CrazyOb myCrazyOb = DebugTraceProxy.NewObject<crazyob>();
Reflection... handy.
Saturday, March 10. 2007
VS2005 DataTips for MFC collection classes (CMap, CArray, etc.)
I spend a lot of time debugging old code. Tracing through libraries written years ago, before the VC++ STL had reached maturity. And one of the often-frustrating aspects of this is how difficult it is to examine the contents of the old, MFC collection classes. CDWordArray, CStringArray, CMapPtrToPtr... not to mention the various templatized versions of these classes. While sometimes these can be easily replaced with newer, better-supported STL equivalents, often the effort involved outweighs the benefit.At least for the array classes, it's only a minor inconvenience: the array pointer, and the size of the array are both readily available, and with these it's easy enough to view the contents.
But for the
CMap classes, things get ugly. Internally, these objects are hash tables, with an array of buckets and each bucket a linked list. Viewing the contents of one of these maps in the debugger requires manually tracing the list of each bucket, then backing up and trying another bucket, then another... until you've found the item, or just given up.The
std::map<> class, implemented as a red-black tree, should be just as much of an annoyance to view - however, it gets flattened into what looks like an array:
Handy, eh? So enough of tracing through buckets.
Open
\Program Files\Microsoft Visual Studio 8\Common7\Packages\Debugger\autoexp.dat, and at the end of the [Visualizer] section, add:;------------------------------------------------------------------------------
; CArray
;------------------------------------------------------------------------------
CArray<*>|CDWordArray|CWordArray|CByteArray|CUIntArray|CPtrArray|CObArray|CStringArray{
preview
(
#( "[", [$c.m_nSize], "](",
#array
(
expr : $c.m_pData[$i],
size : $c.m_nSize
),
")")
)
children
(
#(
#array
(
expr : $c.m_pData[$i],
size : $c.m_nSize
)
)
)
}
Start a debug session. You should now be able to quickly examine the various
CArray (CDWordArray...) objects as easily as std::vector<...>s. Note that the preview (...) section controls what's viewed in the initial DataTip or watch line, while the children(...) section controls what's displayed when you expand it.
Now for the fun one. Start with:
;------------------------------------------------------------------------------
; CMap
;------------------------------------------------------------------------------
CMap<*>|CMapPtrToPtr|CMapPtrToWord|CMapWordToPtr|CMapWordToOb|CMapStringToPtr|CMapStringToOb|CMapStringToString{
preview
(
#( "[", [$c.m_nCount], "](",
#array
(
expr : $c.m_pHashTable[$i],
size : $c.m_nHashTableSize
) : #list (
head : &$e,
next : pNext
) : $e,
")")
)
children
(
#(
#array
(
expr : $e.m_pHashTable[$i],
size : $e.m_nHashTableSize
) : #list (
head : &$e,
next : pNext
) : $e
)
)
}
Ah, now this one will save some serious time - it'll flatten the various
CMap objects such that they look like arrays in the debugger. A CMap with 3000 items will show 3000 children, numbered 0-2999. 
But it can still be better: each of those children is a key-value pair, specifically a
CMap::CAssoc object. It'd be nice if we could get a preview of those keys and values as we scroll through those 3000 items, rather than having to expand each one...CMap<*>::CAssoc|CMapPtrToPtr::CAssoc|CMapPtrToWord::CAssoc|CMapWordToPtr::CAssoc|CMapWordToOb::CAssoc|CMapStringToPtr::CAssoc|CMapStringToOb::CAssoc|CMapStringToString::CAssoc {
preview
(
#(
"(",
$e.key,
",",
$e.value,
")"
)
)
children
(
#(
key: $c.key,
value: $c.value
)
)
}
There! All happy. Of course, you can write rules for your own datatypes too, if you want them to be immediately visible in the preview. For a good reference, see the excellent writeup over at virtualdub.org
Monday, February 26. 2007
Tables and numbers and colorful graphs and...
A while back, I needed to generate some reports off of a small database
I maintain. I needed them to be updated frequently, and didn't want to
spend a lot of time putting them together.
Of course, I could have used Crystal Reports. But it just didn't seem right - I keep a large number of knives at home, and should I ever desire death by a thousand cuts, I'm sure it could be arranged on my own time. No reason to mix such activities with work.
So based on a recommendation, I decided to give SQL Server Reporting Services a shot. Installed it on my desktop, threw together a few reports, and that was it. It was quick and easy, and I was happy. Until it suddenly stopped working. I messed around with keys and permissions and database users, and after about a day it was all working again... until, roughly a month later, it suddenly wasn't. This went on for some time, and then, one day, it was time to bring the reports out of development and make them available to other people.
And I balked. Here it was, running on a local machine that had no other users, no onerous loads, a machine that, most days, ran only one very light application... and it was still breaking periodically. Did I really want to put up with babysitting this thing on a remote server? No, I decided, I did not want that.
So, back to the drawing board. Of course, I didn't exactly have time to research and learn a whole new reporting framework. Heck, I didn't have time to do much of anything - any work would have to be done while waiting for builds to complete or tests to run on other projects. So I buckled down and started coding: I needed a few basic statistical routines, a histogram routine, some tables, and a few graphs. Some quick-and-dirty C# took care of the stats, quick-and-dirty HTML for the tables... and the newest addition to my toolbox took care of the graphs.
I'd first run across ZedGraph a few years ago, when John Champion posted his article on The CodeProject. While it looked nice enough, I had no need for such a thing at the time, and forgot about it. But now, running across it in a frantic Google search, it looked like just what I needed. A couple of hours spent playing with it confirmed this notion: it fit my simple needs like a glove, quickly turning the dry, drab reports into slick, colorful affairs, ready for inclusion in any presentation. Best yet, it fit neatly into the quick-and-dirty ASP.NET code I'd already written.
A full day spent hacking (during the aforementioned gaps in testing...), and the new reports were ready. Fast, ridiculously simple, and perfectly suitable for XCOPY deployment.
Of course, I could have used Crystal Reports. But it just didn't seem right - I keep a large number of knives at home, and should I ever desire death by a thousand cuts, I'm sure it could be arranged on my own time. No reason to mix such activities with work.
So based on a recommendation, I decided to give SQL Server Reporting Services a shot. Installed it on my desktop, threw together a few reports, and that was it. It was quick and easy, and I was happy. Until it suddenly stopped working. I messed around with keys and permissions and database users, and after about a day it was all working again... until, roughly a month later, it suddenly wasn't. This went on for some time, and then, one day, it was time to bring the reports out of development and make them available to other people.
And I balked. Here it was, running on a local machine that had no other users, no onerous loads, a machine that, most days, ran only one very light application... and it was still breaking periodically. Did I really want to put up with babysitting this thing on a remote server? No, I decided, I did not want that.
So, back to the drawing board. Of course, I didn't exactly have time to research and learn a whole new reporting framework. Heck, I didn't have time to do much of anything - any work would have to be done while waiting for builds to complete or tests to run on other projects. So I buckled down and started coding: I needed a few basic statistical routines, a histogram routine, some tables, and a few graphs. Some quick-and-dirty C# took care of the stats, quick-and-dirty HTML for the tables... and the newest addition to my toolbox took care of the graphs.
I'd first run across ZedGraph a few years ago, when John Champion posted his article on The CodeProject. While it looked nice enough, I had no need for such a thing at the time, and forgot about it. But now, running across it in a frantic Google search, it looked like just what I needed. A couple of hours spent playing with it confirmed this notion: it fit my simple needs like a glove, quickly turning the dry, drab reports into slick, colorful affairs, ready for inclusion in any presentation. Best yet, it fit neatly into the quick-and-dirty ASP.NET code I'd already written.
A full day spent hacking (during the aforementioned gaps in testing...), and the new reports were ready. Fast, ridiculously simple, and perfectly suitable for XCOPY deployment.
previous page
(Page 2 of 3, totaling 15 entries)
next page

