2

When writing an unmanaged Win32 DLL that exports functions, it's not uncommon to have some functions, variables and/or classes that aren't meant to be exported and are only for internal use within the DLL. Since we were targetting applications written in both .NET and Visual FoxPro at the time, using a .def file instead of the __declspec(dllexport) keyword was the way to go.

When writing components of this nature in a DLL the way I usually do it is with a #define that expands to nothing but helps me keep track of what the purpose behind the component is, i.e.:

#define INTERNALUSE

// Function used internally by the DLL
VOID WINAPI INTERNALUSE StrDateToNumDate(wchar_t *wszDateString, int cchDate);
// Function exported by the DLL
BOOL WINAPI ValidateDateString(wchar_t *wszDateString, int cchDate);

One of my coworkers at this company had commented that this was confusing and bloated the code at the time when I wrote the component, and that, usually, the appearance of an additional keyword in a function definition in a DLL implies that the function is going to be exported (a la the #define PROJECTNAME __declspec(dllexport) lines automatically generated by MSVC), but I found it much easier to keep maintain this way.

I haven't thought about this issue for a while but digging through some of my old code brought it back to my mind just now. I am curious if anyone has any insight on this topic and on which of us was more correct.

  • 7
    I'm not buying the "bloated" argument. Confusing? Maybe, until you spend the 30 seconds explaining its purpose, then it shouldn't be confusing anymore. – Robert Harvey Jun 27 '16 at 21:02
1

While I don't think that this sort of pre-processor-level “comment” is evil, I'm also not very excited about it. Your tools won't interpret it in any way and won't be able to catch any bugs caused by accidentally using a function in a way it wasn't intended to. The tag is also invisible at the call-site.

Since it is really just a comment, you could equally well spell it as such.

VOID WINAPI /* internal */ StrDateToNumDate(wchar_t *wszDateString, int cchDate);

I'm not a big fan of this solution either but it would save your co-worker the (arguably minimal) cognitive burden to figure out what the token does and still serve as the documentation you're after. I would prefer to put the comment (or the tagging macro) after the function, however. This is also where function attributes (at least in my compiler) go.

Your compiler might actually have an annotation type to express the semantics you want to convey in a way that the compiler can understand. Even if it does not have it today, this is actually a counter-argument to use lexical comments and a good argument for using the macro: If you ever decide to use such annotations (maybe because your compiler adds support for them) you can switch to them simply be editing the macro definition.

An alternative solution that would be more intrusive but also remember you of the function's “internalness” at the call-site and allow limited tool support would be to use a naming-convention. For example, all internal functions could be named with a trailing underscore. This can of course be combined with the tagging or annotations.

  • I don't think that use at the call-site was a concern at the time, it was more or less "did I forget to add this to the .DEF file?" Well thought out response though; appreciate it! – Govind Parmar Jun 27 '16 at 21:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.