Sometimes you find yourself in a situation where you just can’t use all the tools you are accustomed to having. I had one of those weeks recently.

You see I had to write a DLL plugin for a program on Windows. I prefer to use rapid application development (especially on the Mac) and I rarely write anything like a driver. I’m not incapable of rolling up my sleeves and digging in. I’ve even written my share of assembly code in the past. (68000, 8086, 6502, BAL eeek!) But a DLL is kind of somewhere in between an application and a library. Now I’ve written my share of libraries, and DLLs. A lot of the DLLs I’ve written in the past have worked with MFC. And MFC makes some things easier. But this one was different. It had to be native and small. I had a sample plug-in for this program which was written back in the Visual C++ 6.0 days and the first thing I did was try and get it to compile with Visual Studio 2005.

That sort of worked just by using the Visual Studio wizards but the sample was just that, a sample. The first thing I needed that wasn’t in the sample was a handle to the module of the DLL. Why? Because I needed to store and load some resources. And the DllMain of the sample was never getting called. Maybe the original author never checked, or maybe VS 2005 did something. Now there are lots of ways this can happen, but let me tell you that if you should find yourself in this situation, then pay careful attention the “Calling Convention” setting of the compiler’s Advanced configuration pane. Or you can spend hours trying to figure out what’s wrong out like I did.

You can also fall into the chasm of documentation describing new technologies piled layer upon layer atop the Win32 API. But when it comes to writing something small and portable you have to avoid bringing in the kitchen sink. Here’s some stuff I did to cut corners.

Let’s say you need a working url in a dialog or a window. There’s a new control class which gives you all the bells and whistles including a hand cursor. If you have space, a day to spend studying and writing the code, and the patience of Job then it’s a pretty nifty little thing. Or you can just do this with a static text:

case WM_COMMAND:
.
switch(LOWORD(wParam))
.
case IDC_URL: // the resource id of the static text
       if (HIWORD(wParam) == STN_CLICKED || HIWORD(wParam) == STN_DBLCLK)
       {
               ShellExecute(hwndDlg, "open", "http://my_url.com", 0, 0, 0);
        }
        return true;
.

And elsewhere in the same DialogProc:

     break;
.
.
case WM_CTLCOLORSTATIC: // this draws it with a nice link color
       if (GetDlgItem(hwndDlg, IDC_URL) == (HWND)lParam)
        {
              HDC hDC = (HDC)wParam;
              SetTextColor(hDC, GetSysColor(COLOR_HOTLIGHT));
              SetBkColor(hDC, GetSysColor(COLOR_BTNFACE));  // COLOR_BTNFACE for Dialog backgrounds
              return (BOOL)GetSysColorBrush(COLOR_BTNFACE);
         }

Just make sure you static text has Notify set to true and Disabled set to false.

Another thing you can do in almost any code regardless of environment is use the STL. The vector class is handy for storing the contents of combo boxes between dialog invocations.

Just declare:

#include <vector>;
using namespace std;
 
vector<const char *> myComboStrings;

Fill it with strings as appropriate and then later:

 HWND hwndCombo = GetDlgItem(hwndDlg, IDC_MYCOMBO);
    SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
    for (unsigned int i = 0; i < myComboStrings.size(); i++)
        SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) myComboStrings[i]);

The STL maps class also comes in handy for associations. Say you need a table of callbacks.

#include <string>
#include <map>
using namespace std;
   typedef void (* MyCallBack)(HWND, const char *, unsigned int);
   typedef map<string, MyCallBack> MyCallBackMap;
   typedef MyCallBackMap::iterator MyCallBackIter;
MyCallBackMap callBackMap; // probably a global or static

Then you can save a callback by:

string callbackID("some id");
callBackMap[callbackID] = SomeFunction; // which takes the form of MyCallBack

And then later:

string callbackID("some id");
MyCallBackIter foundCallBack = callBackMap.find(callbackID);
if (foundCallBack != callBackMap.end())
(foundCallBack->second)(hwnd, "some string", anInt); // call SomeFunction
callBackMap.erase(callbackID); // if you are done with the callback function

Well that’s all I have time for now. If you read this far I hope you found something of use.

Tags: 
programming

Comments (1)

Leave a comment

Plain text

  • No HTML tags allowed.
By submitting this form, you accept the Mollom privacy policy.