Saturday, July 09, 2005

Intellisense stops working for a class...

Symptoms: Intellisense stops working for an entire class.
Conditions:
  • You are exporting symbols with a preprocessor macro #defined to _declspec(dllexport or dllimport)
  • You are exporting individual members of a class as opposed to the entire class
I have a love/hate relationship with my Visual Studio Intellisense. It is a great feature ... if it works. I'm working on an C++ ODBC wrapper class right now and Intellisense did not like my odbc::statement class. I am using an LWODBC_API define that expands to _declspec(dllimport/dllexport) to import or export my classes and members. But I did not want to export the entire odbc::statement class. The class contains a couple of map<> and other constructs that cannot be accessed by 'clients of the DLL'. You know the error.

class LWODBC_API statement {
public:
statement();
~statement();
protected:
my_map m_member;
};

will give a 'Warning: m_member needs DLL-interface to be accessed by clients of...'.

To circumvent that I decided to export the statement members individually.

class statement {
public:
LWODBC_API statement();
LWODBC_API ~statement();
protected:
my_map m_member;
};
Now 'my_map' is no longer exported and the warning is gone.

But this confuses Intellisense and the entire class 'statement' will not work anymore, nor will any class after 'statement'. You might not even notice this rightaway, since Intellisense will use the 'statement' information it has in it's *.ncb database. But any new members you add will not show up.

It took me a while of deleting declarations in the header file, closing the project, deleting the *.ncb database, reopening the project and trying Intellisense until I found out that

LWODBC_API ~statement();

was the culprit. The Intellisense parser fails on this, even when it properly resolves LWODBC_API to _declspec(dllexport).

The workaround is simple:

Before the class declaration, preferably at the top of the header file, add

#ifdef INTELLISENSE_STOPS_WORKING_WORKAROUND
#undef LWODBC_API
#define LWODBC_API
#endif


This makes Intellisense believe that LWODBC_API is actually defined empty and Intellisense will now see
~statement();

and be happy.

But there is one catch. It would be nice if one could add the workaround right after the LWODBC_API definition and have it done once and for all headers. But this does not work if the LWODBC_API definition is contained in a different header file.

The workaround must be in the same header file where Intellisense stumbles.

If you have multiple header files that Intellisense fails to parse correctly, you must include the workaround in each file. And you must include the workaround after the #include statement that includes the LWODBC_API definition.

I'm back to work now and much relieved that I have my Intellisense back for my class.

Hajo

No comments: