January 25, 2021
Hot Topics:

Using Database Engines in a Mobile Application

  • By Alex Gusev
  • Send Email »
  • More Articles »


First glance

When you're facing high performance requirements or have a large amount of application data, OLE DB raises its head. It sounds attractive until you start to code something. The native OLE DB API is very similar to regular CE databases. A good example is shipped within SQL CE samples. No doubt, you will want to implement some wrapper classes or use existing ones. Thus, our hopes are moving forward to ATL CE.

If you look into atldbcli.h, you'll be surprised to find a lot of code doing a lot of black jobs for you with OLE DB interfaces. Great, you might say. The sad fact is that you can't compile your code with ATL OLE DB client code (no matter whether it's on PPC 2002 or PPC 2003). Fortunately, we're able to get it working after doing some effort.

First all, if you try to include atldbcli.h at the end of standard stdafx.h for an MFC-based application and compile, you'll get error messages. That happens because of the following line in wce.h:

#define __oledb_h__

The workaround of this issue is simple: Either put all needed stuff before the MFC headers or just use an undef 'undesirable' definition and then include all needed headers:

// MFC stuff
#define VC_EXTRALEAN        // Exclude rarely-used stuff from
                            // Windows headers
#include <afxwin.h>         // MFC core and standard components
#include <afxext.h>         // MFC extensions
#if defined(_AFXDLL)
   #include <afxdtctl.h>    // MFC support for Internet
                            // Explorer 4 Common Controls
   #include <afxcmn.h>      // MFC support for Windows Common
                            // Controls
#endif                      // _AFX_NO_AFXCMN_SUPPORT

// ATL OLEDB stuff
#define _ATL_MIN_CRT
#define INITGUID

#undef __oledb_h__

#include <oledb.h>
#include <oledberr.h>
#include <atldbcli.h>

// SQLCE stuff
#include "ssceoledb.h"
#include "ca_mergex.h"

The main issue left is the QueryInterface function of the IUnknown interface. Unlike the desktop version, its Windows CE counterpart has lost a small template version of QueryInterface. The following code marks all important changes in unknwn.h with a bold red font:

extern "C++"

   interface DECLSPEC_UUID("00000000-0000-0000-C000-000000000046")
      virtual HRESULT STDMETHODCALLTYPE QueryInterface(
         /* [in] */    REFIID riid,
         /* [iid_is][out] */    void __RPC_FAR *__RPC_FAR *ppvObject)
                                = 0;

      virtual ULONG STDMETHODCALLTYPE AddRef( void)  = 0;

      virtual ULONG STDMETHODCALLTYPE Release( void) = 0;

   template <class Q>
      return QueryInterface(__uuidof(Q), (void**)pp);



Another solution is to change atldbcli.h in all methods that take a pointer to IUnknown-derived interfaces according to the following pattern:

// smart pointer definition
CComPtr<ISomething> spSomething;

// change next line from
HRESULT hr = pUnk->QueryInterface(&spSomething);
// to
HRESULT hr = pUnk->QueryInterface(__uuidof(ISomething),

In addition, in all places where class members are used (defined as smart pointers), just replace "->" with ".":

class CRowset
   HRESULT Compare(const CBookmarkBase& bookmark1,
                   const CBookmarkBase& bookmark2,
      DBCOMPARE* pComparison) const
      ATLASSERT(m_spRowset != NULL);
      CComPtr<IRowsetLocate> spLocate;
      // Replace the next line
      HRESULT hr = m_spRowset->QueryInterface(&spLocate);
      // with this
      HRESULT hr = m_spRowset.QueryInterface(&spLocate);
      if (FAILED(hr))
         return hr;

      return spLocate->Compare(NULL, bookmark1.GetSize(),
         bookmark2.GetSize(), bookmark2.GetBuffer(), pComparison);

Which solution you choose is totally your call. I guess that changing things in IUnknown is much quicker, even though you should correct atldbcli.h in any case. When you take a look at the CDynamicAccessor::BindColumns method, you'll see the following code:

HRESULT BindColumns(IUnknown* pUnk)
   // If column is of type STR or WSTR increase length by 1
   // to accommodate the NULL terminator.
   if (m_pColumnInfo[i].wType == DBTYPE_STR ||
       m_pColumnInfo[i].wType == DBTYPE_WSTR)
       m_pColumnInfo[i].ulColumnSize += 1;

It means that ASCII and UNICODE strings are handled the same way. You may correct it as follows:

HRESULT BindColumns(IUnknown* pUnk)
   // If column is of type STR or WSTR increase length by 1
   // to accommodate the NULL terminator.
   if (m_pColumnInfo[i].wType == DBTYPE_STR ||
      m_pColumnInfo[i].wType  == DBTYPE_WSTR)
         m_pColumnInfo[i].ulColumnSize += 1;
            if (m_pColumnInfo[i].wType == DBTYPE_WSTR)
         m_pColumnInfo[i].ulColumnSize *= sizeof(TCHAR);

And finally, there's one last thing before you can program something meaningful. In SDKs for WinCE 4.X, there is no oledb.lib file. In the case of SQL CE, you may download a workaround for this issue from here.

Page 2 of 3

This article was originally published on May 17, 2004

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date