소비자에게 반환되는 열을 동적으로 결정

PROVIDER_COLUMN_ENTRY 매크로는 일반적으로 IColumnsInfo::GetColumnsInfo 호출을 처리합니다. 그러나 소비자는 책갈피를 사용하도록 선택할 수도 있으므로 공급자는 소비자가 책갈피를 요청하는지 여부에 따라 반환되는 열을 변경할 수 있어야 합니다.

IColumnsInfo::GetColumnsInfo 호출을 처리하려면 MyProviderRS.h의 CAgentMan 사용자 레코드에서 GetColumnInfo 함수를 정의하는 PROVIDER_COLUMN_MAP을 삭제하고 이를 사용자의 GetColumnInfo 함수에 대한 정의로 바꿉니다.

////////////////////////////////////////////////////////////////////////
// MyProviderRS.H
class CAgentMan
{
public:
   DWORD dwBookmark;
   TCHAR szCommand[256];
   TCHAR szText[256];
   TCHAR szCommand2[256];
   TCHAR szText2[256];

   static ATLCOLUMNINFO* GetColumnInfo(void* pThis, ULONG* pcCols);
   bool operator==(const CAgentMan& am)
   {
      return (lstrcmpi(szCommand, am.szCommand) == 0);
   }

};

그런 다음 다음의 코드와 같이 MyProviderRS.cpp에 GetColumnInfo 함수를 구현합니다.

GetColumnInfo는 먼저 DBPROP_BOOKMARKS OLE DB 속성이 설정되었는지 확인합니다. GetColumnInfo는 이 속성을 가져오기 위해 행 집합 개체에 대한 포인터(pRowset)를 사용합니다. pThis 포인터는 행 집합을 만든 클래스를 나타내고, 이 클래스는 속성 맵이 저장된 클래스입니다. GetColumnInfo는 pThis 포인터를 RMyProviderRowset 포인터로 변환합니다.

GetColumnInfo는 DBPROP_BOOKMARKS 속성을 확인하기 위해 IRowsetInfo 인터페이스를 사용합니다. 이 인터페이스는 pRowset 인터페이스에 QueryInterface를 호출하여 확보할 수 있습니다. 또는 ATL CComQIPtr 메서드를 대신 사용해도 됩니다.

////////////////////////////////////////////////////////////////////
// MyProviderRS.cpp
ATLCOLUMNINFO* CAgentMan::GetColumnInfo(void* pThis, ULONG* pcCols)
{
   static ATLCOLUMNINFO _rgColumns[5];
   ULONG ulCols = 0;
            
   // Check the property flag for bookmarks; if it is set, set the zero 
   // ordinal entry in the column map with the bookmark information.
   CAgentRowset* pRowset = (CAgentRowset*) pThis;
   CComQIPtr<IRowsetInfo, &IID_IRowsetInfo> spRowsetProps = pRowset;

   CDBPropIDSet set(DBPROPSET_ROWSET);
   set.AddPropertyID(DBPROP_BOOKMARKS);
   DBPROPSET* pPropSet = NULL;
   ULONG ulPropSet = 0;
   HRESULT hr;

   if (spRowsetProps)
      hr = spRowsetProps->GetProperties(1, &set, &ulPropSet, &pPropSet);

   if (pPropSet)
   {
      CComVariant var = pPropSet->rgProperties[0].vValue;
      CoTaskMemFree(pPropSet->rgProperties);
      CoTaskMemFree(pPropSet);
      
      if (SUCCEEDED(hr) && (var.boolVal == VARIANT_TRUE))
      {
         ADD_COLUMN_ENTRY_EX(ulCols, OLESTR("Bookmark"), 0, sizeof(DWORD), 
         DBTYPE_BYTES, 0, 0, GUID_NULL, CAgentMan, dwBookmark, 
         DBCOLUMNFLAGS_ISBOOKMARK)
         ulCols++;
      }
   }

   // Next, set the other columns up.
   ADD_COLUMN_ENTRY(ulCols, OLESTR("Command"), 1, 256, DBTYPE_STR, 0xFF, 0xFF, 
      GUID_NULL, CAgentMan, szCommand)
   ulCols++;
   ADD_COLUMN_ENTRY(ulCols, OLESTR("Text"), 2, 256, DBTYPE_STR, 0xFF, 0xFF, 
      GUID_NULL, CAgentMan, szText)
   ulCols++;

   ADD_COLUMN_ENTRY(ulCols, OLESTR("Command2"), 3, 256, DBTYPE_STR, 0xFF, 0xFF, 
      GUID_NULL, CAgentMan, szCommand2)
   ulCols++;
   ADD_COLUMN_ENTRY(ulCols, OLESTR("Text2"), 4, 256, DBTYPE_STR, 0xFF, 0xFF, 
      GUID_NULL, CAgentMan, szText2)
   ulCols++;

   if (pcCols != NULL)
      *pcCols = ulCols;

   return _rgColumns;
}

이 예제는 정적 배열을 사용하여 열 정보를 포함합니다. 소비자에게 책갈피 열이 필요하지 않는 경우 배열의 항목 하나가 사용되지 않습니다. 이 정보를 처리하려면 ADD_COLUMN_ENTRY와 ADD_COLUMN_ENTRY_EX라는 두 배열 매크로를 만듭니다. ADD_COLUMN_ENTRY_EX는 책갈피 열을 지정할 경우 필요한 flags라는 추가 매개 변수를 가져옵니다.

////////////////////////////////////////////////////////////////////////
// MyProviderRS.h

#define ADD_COLUMN_ENTRY(ulCols, name, ordinal, colSize, type, precision, 
scale, guid, dataClass, member) \
   _rgColumns[ulCols].pwszName = (LPOLESTR)name; \
   _rgColumns[ulCols].pTypeInfo = (ITypeInfo*)NULL; \
   _rgColumns[ulCols].iOrdinal = (ULONG)ordinal; \
   _rgColumns[ulCols].dwFlags = 0; \
   _rgColumns[ulCols].ulColumnSize = (ULONG)colSize; \
   _rgColumns[ulCols].wType = (DBTYPE)type; \
   _rgColumns[ulCols].bPrecision = (BYTE)precision; \
   _rgColumns[ulCols].bScale = (BYTE)scale; \
   _rgColumns[ulCols].cbOffset = offsetof(dataClass, member);

#define ADD_COLUMN_ENTRY_EX(ulCols, name, ordinal, colSize, type, 
precision, scale, guid, dataClass, member, flags) \
   _rgColumns[ulCols].pwszName = (LPOLESTR)name; \
   _rgColumns[ulCols].pTypeInfo = (ITypeInfo*)NULL; \
   _rgColumns[ulCols].iOrdinal = (ULONG)ordinal; \
   _rgColumns[ulCols].dwFlags = flags; \
   _rgColumns[ulCols].ulColumnSize = (ULONG)colSize; \
   _rgColumns[ulCols].wType = (DBTYPE)type; \
   _rgColumns[ulCols].bPrecision = (BYTE)precision; \
   _rgColumns[ulCols].bScale = (BYTE)scale; \
   _rgColumns[ulCols].cbOffset = offsetof(dataClass, member); \
   memset(&(_rgColumns[ulCols].columnid), 0, sizeof(DBID)); \
   _rgColumns[ulCols].columnid.uName.pwszName = (LPOLESTR)name;

GetColumnInfo 함수에서 책갈피 매크로는 다음과 같이 사용됩니다.

ADD_COLUMN_ENTRY_EX(ulCols, OLESTR("Bookmark"), 0, sizeof(DWORD),
   DBTYPE_BYTES, 0, 0, GUID_NULL, CAgentMan, dwBookmark, 
   DBCOLUMNFLAGS_ISBOOKMARK)

이제 향상된 공급자를 컴파일하고 실행할 수 있습니다. 공급자를 테스트하려면 단순 소비자 구현에서 설명하는 대로 테스트 소비자를 수정합니다. 공급자와 함께 테스트 소비자를 실행합니다. Test Consumer 대화 상자의 Run 단추를 클릭하여 테스트 소비자가 공급자에서 적절한 문자열을 검색하는지 확인합니다.

참고 항목

참조

단순한 읽기 전용 공급자의 기능 향상