Experiences with FxCop and wrapping the native debug API

I’m writing some managed wrappers for the native-debugging API (I expect they’ll eventually become part of the MDbg sample). I’m trying to make them FxCop compliant. Here are some random thoughts about my experiences.

  1. FxCop has a lot of great rules. Merely running FxCop to see what it says and giving it the benefit of the doubt is valuable. For example, the rules about Disposable were great. They call out mistakes and point you to examples about how to write it properly. ValidateArgumentsOfPublicMethods was also useful.

  2. There’s a great FxCop forum. You can got a lot more feedback about the rules (and this feedback gets rolled into future docs).

  3. FxCop really encourages full VB-friendly wrappers that hide all the ugly details of native code. Many of the normal interop techniques are not fxcop friendly (eg, passing value-types by-ref, using IntPtr, using uint). Depending on your goals, it can be nice to import the raw native structures, add some helper methods to smooth things over (eg, stuff to help the marshallers, common utility functionality, etc), but leave the raw native fields available for advanced usage.
    a) FxCop and C# don’t like IntPtr, which is pretty necessary for low-level API usage.
    b) FxCop doesn’t like exposing native structures.
    c) FxCop does not like exposing instance fields, even for large value-types.

  4. I hit some confused mappings with UseManagedEquivalentsOfWin32Api, particularly confusing the native debugging APIs with the managed ones in the Debugger class. That inspired the comparison here.

  5. Naming issues. Win32sdk naming (eg, STATUS_SINGLESTEP) is not fxcop compliant. So the wrappers need to decide whether to keep affinity to the native APIs, or change to pick up managed conventions that may confuse the native-API users.

I think the big picture is that FxCop is really intended for friendly class libraries; and so using it directly on native wrappers is somewhat of an abuse. Thus the end wrappers will violate a few rules (though violate them many times). I still found it very useful overall. In the worst case, you can ignore a rule. It’s batting average was high enough that I found it certainly added value.  If you’re not running FxCop on your managed code, try it out. 

Comments (6)

  1. barrkel says:

    I would recommend that you at least conflate things like those "STATUS_SINGLESTEP" (which I’ve never heard of, I must confess – can’t find it on google or in the PSDK either) to something like ThreadStatus.SingleStep – when those things aren’t enumerations they just aren’t typesafe or discoverable enough.

    There’s only two things worth doing, IMO: (1) a raw P/Invoke set of method declarations and structures, or (2) a managed api which exposes no SafeHandle or any other underlying mechanism. A mix between the two is just a convenience for Win32 throwbacks. That’s just my opinion, though.

  2. MSDN Archive says:

    Mike, thanks for the feedback. I think barrkel touched on an important point which I’d like to expand upon.

    Roughly speaking, we can break down ‘wrappers’ for unmanaged API in to three categories:

    (1) Raw: Just the constants, structures, and P/Invoke or ComImport declarations required to interface to the unmanaged API.

    (2) Abstract: Resurfaces the functionality of the unmanaged API without exposing any of the ‘raw’ elements. The resulting managed API stands alone and affinity to the unmanaged API is an explicit non-goal.

    (3) Hybrid: Some parts of the unmanaged API are simplified for the end user, but the ‘raw’ elements remain accessible to cover the remaining scenarios.

    FxCop reinforces the Framework Design Guidelines (FDG), which effectively discourage both (1) and (3), and strongly encourage (2). However, the word ‘Framework’ in FDG is key. If your ‘wrapper’ is just an implementation detail of a larger system, then it isn’t the intended target of the guidelines or the corresponding rule. (In that case, however, if it’s at all possible, it’s best to internalize the raw interop code.)

    On the other hand, if you think about the API that you’re building as a reusable framework, then it (ideally) should be designed on its owned terms following the FDG, and leaving the underlying unmanaged API as an implementation detail. I would argue that there’s far more to gain than "VB-friendlyness" from taking this approach.

  3. Nichol – I think that’s a great response and it makes a lot of sense. The key tension I’m sensing is about when to not apply FxCop.

    I detect one camp of folks that basically champion that everything should be FxCop compliant (which is what this FxCop blog entry alludes to http://blogs.msdn.com/fxcop/archive/2006/04/11/WeWantYourFeedback.aspx).

  4. Barkel – Stuff like "STATUS_SINGLESTEP" can still be in an enum (eg, enum NativeExceptionCodes) so that it’s discoverable.

    I’m a big fan of NicholG’s case #3 – the hybrid. Providing a full managed wrapper for somethings can be bad. I’ll write up my thoughts on this in another blog post.