January 2006 Archives

I've scoured the net for a solution to my problem and found a lot of good resources, but none that solved my issue:
http://blogs.msdn.com/sqlexpress/archive/2004/07/23/192044.aspx
http://blogs.msdn.com/sql_protocols/archive/2005/10/29/486861.aspx#51...

I have a working application that opens a local database (nothing remote) on my development machine with full-blown SQL Server 2005, but when I try the app on a machine with SQL Server 2005 Express, I get the dreaded:
"[DBNETLIB][ConnectionOpen(Connect()).]SQL Server does not exist or access denied."

My C++/ADO connection string is:
"Provider='sqloledb';Data Source='localhost';Initial Catalog='master';Integrated Security='SSPI';"

Things I've tried:
I can connect to the sqlcmd just fine. TCP, Shared, NP are all enabled. The sqlbrowser and express services are started. The OLEDB provider is correctly pointing to MS's DLL, not a rogue provider. The port (1314) is reporting in the App event log and Netstat as listening. I tried changing <localhost> to <machine name>, but it didn't help.

I did notice in the TCP/IP properties of the Server config mgr that even though TCP/IP was enabled, looking at the specific IP address showed that they were active, but disabled. After enabling port there it still didn't help...

On a hunch, I changed my provider from MDAC to Native Client with the string:
"Provider='SQLNCLI';Data Source='localhost';Initial Catalog='master';Integrated Security='SSPI';"

This gave me a more helpful error:
"[SQL Native Client]Named Pipes Provider: Could not open a connection to SQL Server [2]."

I didn't even know I was using Named Pipes! I thought it would've been defaulting to TCP/IP. Going back to the first link
(http://blogs.msdn.com/sqlexpress/archive/2004/07/23/192044.aspx) as reference and stepping through the debugging process for named pipes, I still couldn't connect with \\.\pipe\sql\query. Looking at the Application event log (Event Viewer), I saw that the named pipe, \\.\pipe\MSSQL$SQLEXPRESS\sql\query was listening.

Bingo! That did it, my app works both on the development and test machines with the connection string:
"Provider='SQLNCLI';Data Source='np:\\\\.\\pipe\\MSSQL$SQLEXPRESS\\sql\\query';Initial Catalog='master';Integrated Security='SSPI';"

Ever had one of these problems with using STL objects across DLL boundaries?

  • Export from a DLL a class containing STL objects
  • Access violations with objects passed between DLLs and EXEs

Export from a DLL a class containing STL objects

Apparently there is a compiler limitation for exporting from a DLL standard STL types or classes that contain STL classes. The .NET 2003+ Microsoft compiler (haven't tested older versions) has built in support exporting std::string and std::vector< T >. See Microsoft knowledge base article (http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b168958) for more details on why other classes aren't supported.  If you take the time, all STL classes can be exported, it's just not a lot of fun redefining all the ancillary methods needed for the proper dll-interface, including the allocator methods.

For instance, if you have exported a class from a DLL that internally uses a std::map< T, U > as in the following code, you get compiler warnings...warnings you shouldn't ignore.

class ENGINE_API PluginManager
{
public:
PluginManager();
~PluginManager();
void Load();
void Init();
IDataProvider* GetDataProvider( string InheritedType );
ISyncProvider* GetSyncProvider( string Guid );
vector< IDataProvider* > GetDataProviders();
vector< ISyncProvider* > GetSyncProviders();
vector< IProvider* > GetProviders();
private:
vector< string > FindDlls( string sStartPath );
map< string, ISyncProvider* > m_SyncProviderMapping;
map< string, IDataProvider* > m_DataProviderMapping;
};

The compiler will output warnings like:

c:\My Projects\Engine\PluginManager.h(56) : warning C4251: 'PluginManager::m_SyncProviderMapping' : class 'std::map<_Kty,_Ty>' needs to have dll-interface to be used by clients of class 'PluginManager'
with
[
_Kty=std::string,
_Ty=Idria::ISyncProvider *
]
c:\My Projects\Engine\PluginManager.h(57) : warning C4251: 'PluginManager::m_DataProviderMapping' : class 'std::map<_Kty,_Ty>' needs to have dll-interface to be used by clients of class 'PluginManager'
with
[
_Kty=std::string,
_Ty=Idria::IDataProvider *
]

There are a few tricks you can use depending on how transparent you want it to be.

  1. Wrap the STL containers with or without accessors (encapsulate data members, or just make them public) into a non-exported class. You could then forward-declare the class and completely hide the implementation from someone peeking into your header files.
  2. My favorite way is to not create an entire class, but rather create a locally-scoped private structure within the class you are exporting. This doesn't cause the compiler to think that you need to export all the STL ancillary methods for the templated class. Example code:

private:
vector< string > FindDlls( string sStartPath );
struct PluginManager_impl
{
map< string, ISyncProvider* > m_SyncProviderMapping;
map< string, IDataProvider* > m_DataProviderMapping;
};
PluginManager_impl *m_PluginManager;
};

Now, in your class constructor, allocate a PluginManager_impl struct and use the std::map< T, U > objects directly. The implementation isn't hidden, but it's simple and effective.

As mentioned above, the compiler has built-in support for std::string and std::vector< T > so if you are using those, this trick isn't necessary, just ignore the warnings as recommend by Microsoft by using the following pragma:

#pragma warning( disable: 4251 )

Access violations with objects passed between DLLs and EXEs

Recently on a project, I ran into error messages like this:

ASSERT!
_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
or
>HEAP[MyProgram.exe]: Invalid Address specified to RtlValidateHeap( 00360000, 00353FA0 )
Unhandled exception at 0x77f7f570 in MyProgram.exe.exe:
User breakpoint.

The code looked simple enough, I was returning a std::string object from a class to another DLL. I wasn't passing by reference or pointer as a Microsoft knowledge base article warned me about (http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b172396). Rather, I was passing by value as shown in the code:

string MyNewString = ExternalDllGetString();

In my case, if the string was larger than about 10 characters, I received the access violation.

Remember C 101 that when you return an object by value, a copy of it is made. If this is a class, the copy constructor is called. Therefore, when my object allocated in one DLL was returned passed by value to another DLL or EXE, the allocation and deallocations were occuring in different heap managers since it was across the DLL boundary. After the line of code was executed, the deconstructor for that newly passed value is called causing the access violation.

If you are using different runtime libraries in your DLLs, you will get access violations very quickly because each runtime has its own heap manager and when memory is allocated with one heap manager, it can't be deallocated by a different one.

To fix this issue, all libraries need to use the same runtime library, i.e. /MD, /MDd.

About this Archive

This page is an archive of entries from January 2006 listed from newest to oldest.

December 2005 is the previous archive.

February 2006 is the next archive.

Find recent content on the main index or look in the archives to find all content.