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

Welcome to my logbook

Hi all,
I just found out why Visual Studio's Intellisense stopped working for one of my classes and decided to share this information.

I am software developer working with Visual Studio .NET 2003 under Windows using wxWidgets and boost and a lot of other stuff. In the past I frequently hunted down obscure bugs or found workarounds for bugging problems and wrote about them on my main page. If you want to know for example how to create a (reasonably) secure MS Access database via ODBC, you will find the answer at http://www.litwindow.com/Knowhow/knowhow.html.

But changing my webpage everytime I find a little software programming gem or a workaround is too much of a hassle. So I decided to start a blog where I will be sharing what I find. I hope this will be useful to someone. If it is, feel free to spread the word and add your comments.

Best regards

Hajo Kirchhoff