Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

808 lines
24 KiB

// MSInfo4Category.cpp: implementation of the CMSInfo4Category class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "resource.h"
#include "category.h"
#include "msictrl.h"
#include "datasource.h"
#include "MSInfo4Category.h"
#include "MSInfo5Category.h"
#include "filestuff.h"
#include <afxole.h>
#include "FileIO.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CNFO4DataSource* CMSInfo4Category::s_pNfo4DataSource = NULL;
//a-kjaw
BOOL CMSInfo4Category::m_bIsControlInstalled = TRUE;
//a-kjaw
CMSInfo4Category::CMSInfo4Category() : m_pUnknown(NULL)
{
}
CMSInfo4Category::~CMSInfo4Category()
{
}
HRESULT CMSInfo4Category::ReadMSI4NFO(CString strFileName/*HANDLE hFile*/,CMSInfo4Category** ppRootCat)
{
DWORD grfMode = STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE;
CComPtr<IStream> pStream;
CComBSTR bstrFileName(strFileName);
CComPtr<IStorage> pStorage;
HRESULT hr = StgOpenStorage(bstrFileName, NULL, grfMode, NULL, 0, &pStorage);
if (!SUCCEEDED(hr))
{
return hr;
}
CComBSTR bstrMSIStream(_T("MSInfo"));
hr = pStorage->OpenStream(bstrMSIStream, NULL, grfMode, 0, &pStream);
if (!SUCCEEDED(hr))
{
return hr;
}
COleStreamFile* pOStream;
pOStream = new COleStreamFile(pStream);
const DWORD MSI_FILE_VER = 0x03000000;
DWORD dwVersion, dwCount;
ULONG ulCount;
// First, read and check the version number in the stream.
ulCount = pOStream->Read((void *) &dwVersion, sizeof(DWORD));
if (FAILED(hr) || ulCount != sizeof(DWORD))
{
return E_FAIL;
}
if (dwVersion != MSI_FILE_VER)
return E_FAIL;
// The next thing in the stream is a set of three strings, each terminated by
// a newline character. These three strings are the time/date, machine name and
// user name from the saving system. The length of the total string precedes
// the string.
DWORD dwSize;
ulCount = pOStream->Read(&dwSize,sizeof(DWORD));
if ( ulCount != sizeof(DWORD))
return E_FAIL;
char * szBuffer = new char[dwSize];
if (szBuffer == NULL)
return E_FAIL;
ulCount = pOStream->Read((void *) szBuffer,dwSize);
if (ulCount != dwSize)
{
delete szBuffer;
return E_FAIL;
}
// We don't actually care about these values (now at least).
/*
CString strData(szBuffer, dwSize);
m_strTimeDateStamp = strData.SpanExcluding("\n");
strData = strData.Right(strData.GetLength() - m_strTimeDateStamp.GetLength() - 1);
m_strMachineName = strData.SpanExcluding("\n");
strData = strData.Right(strData.GetLength() - m_strMachineName.GetLength() - 1);
m_strUserName = strData.SpanExcluding("\n");
*/
delete szBuffer;
// Next, read the map from CLSIDs to stream names. This also includes some
// other information about the controls. First we should find a DWORD with
// the count of controls.
DWORD dwControlCount;
ulCount = pOStream->Read(&dwControlCount,sizeof(DWORD));
delete pOStream;
if (ulCount != sizeof(int))
return E_FAIL;
SAVED_CONTROL_INFO controlInfo;
CString strCLSID, strStreamName;
//a-stephl
CMapStringToString mapStreams;
for (DWORD i = 0; i < dwControlCount; i++)
{
if (FAILED(pStream->Read((void *) &controlInfo, sizeof(SAVED_CONTROL_INFO), &dwCount)) || dwCount != sizeof(SAVED_CONTROL_INFO))
return E_FAIL;
strCLSID = controlInfo.szCLSID;
strStreamName = controlInfo.szStreamName;
// We don't currently care about this information...
/*
strSize.Format("%ld", controlInfo.dwSize);
strInfo.FormatMessage(IDS_OCX_INFO, controlInfo.szName, controlInfo.szVersion, strSize);
m_mapCLSIDToInfo.SetAt(strCLSID, strInfo);
*/
mapStreams.SetAt(strCLSID, strStreamName);
}
// Read and build the category tree. Read the first level, which must be 0.
int iLevel;
if (FAILED(pStream->Read((void *) &iLevel, sizeof(int), &dwCount)) || dwCount != sizeof(int))
return E_FAIL;
if (iLevel == 0)
{
LARGE_INTEGER li; li.HighPart = -1; li.LowPart = (ULONG)(0 - sizeof(int));
if (FAILED(pStream->Seek(li, STREAM_SEEK_CUR, NULL)))
return E_FAIL;
if (!SUCCEEDED(RecurseLoad410Tree(ppRootCat,pStream,pStorage,mapStreams)))
{
return E_FAIL;
}
// After RecurseLoadTree is through, we should be able to read a -1
// for the next level.
if (FAILED(pStream->Read((void *) &iLevel, sizeof(int), &dwCount)) || dwCount != sizeof(int) || iLevel != -1)
{
return E_FAIL;
}
ASSERT(iLevel == -1 && "unexpected value read after RecurseLoadTree");
}
else
return E_FAIL;
CString strAppend;
strAppend.Format(_T(" (%s)"), strFileName);
(*ppRootCat)->m_strCaption += strAppend;
return S_OK;
}
//-----------------------------------------------------------------------------
// This function (which doesn't really use recursion - the name is left over
// from 4.10 MSInfo) read the category tree from the MSInfo stream and creates
// the necessary COCXFolder objects to represent it.
//-----------------------------------------------------------------------------
HRESULT CMSInfo4Category::RecurseLoad410Tree(CMSInfo4Category** ppRoot, CComPtr<IStream> pStream,CComPtr<IStorage> pStorage,CMapStringToString& mapStreams)
{
// This array of folders is used to keep track of the last folder read
// on each level. This is useful for getting the parent and previous
// sibling when reading a new folder.
CMSInfo4Category* pRoot = NULL;
// The iLevel variable keeps track of the current tree level we are
// reading a folder for. A -1 indicates the end of the tree.
DWORD dwCount;
int iLevel = 1;
if (FAILED(pStream->Read((void *) &iLevel, sizeof(int), &dwCount)) || dwCount != sizeof(int))
return E_FAIL;
int iLastLevel = iLevel;
HRESULT hr;
CMSInfo4Category* pLastCat = NULL;
for(;iLevel != -1;)
{
CMSInfo4Category* pCat = new CMSInfo4Category();
hr = pCat->LoadFromStream(pStream,pStorage);
if (FAILED(hr))
{
delete pCat;
return hr;
}
if (!pRoot)
{
pRoot = pCat;
}
//CString strCLSID(pCat->m_bstrCLSID);
if (!mapStreams.Lookup(pCat->m_strCLSID,pCat->m_strStream))
{
ASSERT(1);
}
if (iLevel == iLastLevel)
{
pCat->m_pPrevSibling = pLastCat;
if (pLastCat)
{
pCat->m_pParent = pLastCat->m_pParent;
pLastCat->m_pNextSibling = pCat;
}
}
else if (iLevel - 1 == iLastLevel)
{
//we've just stepped from parent to child
pCat->m_pPrevSibling = NULL;
if (pLastCat)
{
pCat->m_pParent = pLastCat;
pLastCat->m_pFirstChild = pCat;
}
}
else if (iLevel < iLastLevel)
{
//we need to trace back up chain to find common parent
DWORD iLevelDiff = iLastLevel - iLevel;
for(DWORD i = 0; i < iLevelDiff; i++)
{
if (!pLastCat)
{
break;
}
pLastCat = (CMSInfo4Category*) pLastCat->m_pParent;
}
pCat->m_pPrevSibling = pLastCat;
if (pLastCat)
{
pCat->m_pParent = pLastCat->m_pParent;
pLastCat->m_pNextSibling = pCat;
}
}
pLastCat = pCat;
iLastLevel = iLevel;
if (FAILED(pStream->Read((void *) &iLevel, sizeof(int), &dwCount)) || dwCount != sizeof(int))
return E_FAIL;
}
//a-kjaw
if( CMSInfo4Category::m_bIsControlInstalled == FALSE)
{
CString strCaption, strMessage;
::AfxSetResourceHandle(_Module.GetResourceInstance());
strCaption.LoadString(IDS_SYSTEMINFO);
strMessage.LoadString(IDS_NOWI2KRESKIT);
::MessageBox(NULL, strMessage, strCaption, MB_OK | MB_ICONEXCLAMATION);
CMSInfo4Category::m_bIsControlInstalled = TRUE;
}
//a-kjaw
*ppRoot = pRoot;
// We read a -1 to exit the loop, then we are through with the
// category tree. Backup (so any other recursion trees will read
// the -1 as well) and return TRUE.
if (iLevel == -1)
{
LARGE_INTEGER li; li.HighPart = -1; li.LowPart = (ULONG)(0 - sizeof(int));
if (FAILED(pStream->Seek(li, STREAM_SEEK_CUR, NULL)))
return E_FAIL;
}
return S_OK;
}
//-----------------------------------------------------------------------------
// This function creates a CMSInfo4Category object based on the information read
// from the stream.
//-----------------------------------------------------------------------------
HRESULT CMSInfo4Category::LoadFromStream(CComPtr<IStream> pStream,CComPtr<IStorage> pStorage)
{
// Read in the values from the stream. Make sure they're all there before
// we create the COCXFolder.
BOOL fUsesView = FALSE;
BOOL fControl = FALSE;
DWORD dwView = 0;
CLSID clsidCategory;
char szName[100];
if (FAILED(pStream->Read((void *) &fUsesView, sizeof(BOOL), NULL))) return E_FAIL;
if (FAILED(pStream->Read((void *) &fControl, sizeof(BOOL), NULL))) return E_FAIL;
if (FAILED(pStream->Read((void *) &dwView, sizeof(DWORD), NULL))) return E_FAIL;
if (FAILED(pStream->Read((void *) &clsidCategory, sizeof(CLSID), NULL))) return E_FAIL;
if (FAILED(pStream->Read((void *) &szName, sizeof(char) * 100, NULL))) return E_FAIL;
// USES_CONVERSION;
// LPOLESTR lpName = A2W(szName);
this->m_clsid = clsidCategory;
///////a-kjaw
CComPtr<IUnknown> pUnk;
HRESULT hr = S_OK;
if( !IsEqualGUID(m_clsid , GUID_NULL) )
hr = CoCreateInstance( m_clsid , NULL, CLSCTX_ALL , IID_IUnknown ,
(LPVOID*)&pUnk);
if (FAILED(hr))
{
m_bIsControlInstalled = FALSE;
}
///////a-kjaw
//StringFromCLSID(this->m_clsid,&m_bstrCLSID);
LPOLESTR lpstrCLSID;
StringFromCLSID(this->m_clsid,&lpstrCLSID);
m_strCLSID = lpstrCLSID;
CoTaskMemFree(lpstrCLSID);
this->m_pStorage = pStorage;
this->m_dwView = dwView;
this->m_strName = szName;
m_strCaption = szName;
return S_OK;
}
HRESULT CMSInfo4Category::Refresh()
{
return S_OK;
}
HRESULT CMSInfo4Category::CreateControl(HWND hWnd,CRect& rct)
{
try
{
/*LPOLESTR lpCLSID;
if (FAILED(StringFromCLSID(m_clsid, &lpCLSID)))
return E_FAIL;*/
HRESULT hr = E_FAIL;
if (m_pUnknown == NULL)
{
hr = CoCreateInstance(m_clsid,NULL,CLSCTX_INPROC_SERVER,IID_IUnknown,(void**) &m_pUnknown);
}
// Get the stream for this control, and load it.
if (!SUCCEEDED(hr))
{
return hr;
}
DWORD grfMode = STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE;
CComPtr<IStream> pStream;
USES_CONVERSION;
CComBSTR bstrStream = m_strStream;//A2W(m_strStream);
hr = m_pStorage->OpenStream(bstrStream, NULL, grfMode, 0, &pStream);
if (!SUCCEEDED(hr))
{
return hr;
}
else
{
COleStreamFile olefile(pStream.Detach());
CMSIControl* p4Ctrl = new CMSIControl(m_clsid);
CWnd* pWnd = CWnd::FromHandle(hWnd);
AfxEnableControlContainer();
//if (!p4Ctrl->Create(NULL, WS_VISIBLE | WS_CHILD, rct, pWnd, 0, &olefile, FALSE, NULL))
if (!p4Ctrl->Create(NULL, /*WS_VISIBLE |*/ WS_CHILD, rct, pWnd, 0, &olefile, FALSE, NULL))
{
return E_FAIL;
}
olefile.Close();
p4Ctrl->MSInfoUpdateView();
p4Ctrl->MSInfoRefresh();
//Add Control and CLSID to map of CLSID's
CMSInfo4Category::s_pNfo4DataSource->AddControlMapping(m_strCLSID,p4Ctrl);
}
}
catch (COleException* pException)
{
ASSERT(0);
pException->Delete();
}
catch (CException* pException)
{
ASSERT(0);
pException->Delete();
}
catch (...)
{
ASSERT(0);
}
return S_OK;
}
//---------------------------------------------------------------------------
// GetDISPID returns the DISPID for a given string, by looking it up using
// IDispatch->GetIDsOfNames. This avoids hardcoding DISPIDs in this class.
//---------------------------------------------------------------------------
BOOL CMSInfo4Category::GetDISPID(IDispatch * pDispatch, LPOLESTR szMember, DISPID *pID)
{
BOOL result = FALSE;
DISPID dispid;
if (SUCCEEDED(pDispatch->GetIDsOfNames(IID_NULL, &szMember, 1, LOCALE_SYSTEM_DEFAULT, &dispid)))
{
*pID = dispid;
result = TRUE;
}
return result;
}
HRESULT CMSInfo4Category::ShowControl(HWND hWnd, CRect rctList, BOOL fShow)
{
try
{
//CString strCLSID(m_bstrCLSID);
CMSIControl* p4Ctrl = NULL;
if (!CMSInfo4Category::s_pNfo4DataSource->GetControlFromCLSID(m_strCLSID,p4Ctrl))
{
if (!SUCCEEDED(CreateControl(hWnd,rctList)))
{
//could not serialize control
return E_FAIL;
}
if(!CMSInfo4Category::s_pNfo4DataSource->GetControlFromCLSID(m_strCLSID,p4Ctrl))
{
if (!IsDisplayableCategory())
{
//this is one of the parent nodes, which does not display info
CMSInfo4Category::s_pNfo4DataSource->UpdateCurrentControl(NULL);
return S_OK;
}
return E_FAIL;
}
}
else
{
ResizeControl(rctList);
}
ASSERT(p4Ctrl && "Invalid OCX pointer");
if (fShow)
{
CMSInfo4Category::s_pNfo4DataSource->UpdateCurrentControl(p4Ctrl);
p4Ctrl->ShowWindow(SW_SHOW);
p4Ctrl->SetMSInfoView(this->m_dwView);
p4Ctrl->MSInfoUpdateView();
p4Ctrl->MSInfoRefresh();
}
else
p4Ctrl->ShowWindow(SW_HIDE);
}
catch (CException* pException)
{
ASSERT(0);
pException->Delete();
}
catch (...)
{
ASSERT(0);
}
return S_OK;
}
//TD: Move into nfodata.cpp?
CNFO4DataSource::CNFO4DataSource()
{
m_pCurrentControl = NULL;
}
CNFO4DataSource::~CNFO4DataSource()
{
CString strKey;
CMSIControl* pCtrl;
// m_pCurrentControl->DestroyWindow();
for(POSITION mapPos = m_mapCLSIDToControl.GetStartPosition( );;)
{
if (!mapPos)
{
break;
}
m_mapCLSIDToControl.GetNextAssoc(mapPos, strKey, (void*&)pCtrl);
pCtrl->DestroyWindow();
delete pCtrl;
}
}
void CNFO4DataSource::UpdateCurrentControl(CMSIControl* pControl)
{
if (m_pCurrentControl && pControl != m_pCurrentControl)
{
m_pCurrentControl->ShowWindow(SW_HIDE);
}
m_pCurrentControl = pControl;
}
//---------------------------------------------------------------------------
// Creates the datasource, and the root CMSInfo4Category
//---------------------------------------------------------------------------
HRESULT CNFO4DataSource::Create(CString strFileName)
{
CMSInfo4Category * pNewRoot = NULL;
CMSInfo4Category::SetDataSource(this);
HRESULT hr = CMSInfo4Category::ReadMSI4NFO(strFileName, &pNewRoot);
if (SUCCEEDED(hr) && pNewRoot)
m_pRoot = pNewRoot;
return hr;
}
void CMSInfo4Category::Print(CMSInfoPrintHelper* pPrintHelper, BOOL bRecursive)
{
#ifdef A_STEPHL
// ASSERT(0);
#endif
CString strOut;
CString strBracket;
VERIFY(strBracket.LoadString(IDS_LEFTBRACKET) && "Failed to find resource IDS_LEFTBRACKET");
strOut = strBracket;
CString strName, strCaption;
GetNames(&strCaption,&strName);
strOut += strCaption;
VERIFY(strBracket.LoadString(IDS_RIGHTBRACKET) && "Failed to find resource IDS_RIGHTBRACKET");
strOut += strBracket;
pPrintHelper->PrintLine("");
pPrintHelper->PrintLine(strOut);
int iRowCount,iColCount;
this->GetCategoryDimensions(&iColCount,&iRowCount);
CString strColHeader;
//TD: put in resources
CString strColSpacing = " ";
pPrintHelper->PrintLine("");
/*if (1 == iColCount && 0 == iRowCount)
{
//this is a parent node, with no data of its own
CString strCatHeading;
strCatHeading.LoadString(IDS_CATEGORYHEADING);
pPrintHelper->PrintLine(strCatHeading);
}*/
// When allocating the
// buffer for the information, allocate 5 extra bytes (1 for the null, and
// 4 to hold "\r\n\r\n").
CString strLine;
CMSIControl* pControl = NULL;
if (!CMSInfo4Category::s_pNfo4DataSource->GetControlFromCLSID(m_strCLSID,pControl))
{
//need to make sure it's not "empty parent" category, like HARDWARE RESOURCES
if ("{00000000-0000-0000-0000-000000000000}" == m_strCLSID)
{
//this is a parent node, with no data of its own
CString strCatHeading;
strCatHeading.LoadString(IDS_CATEGORYHEADING);
pPrintHelper->PrintLine(strCatHeading);
}
else
{
pPrintHelper->PrintLine("");
strLine.LoadString(IDS_NOOCX);
pPrintHelper->PrintLine(strLine);
CString strDetail;
strDetail.LoadString(IDS_NOOCXDETAIL);
pPrintHelper->PrintLine(strDetail);
}
}
else
{
//pControl->SetMSInfoView(this->m_dwView);
//pControl->MSInfoUpdateView();
//pControl->MSInfoRefresh();
long lBufferLength = pControl->MSInfoGetData(m_dwView, NULL, 0);
if (lBufferLength < 0)
{
ASSERT(1);
}
else
{
char * pBuffer = new char[lBufferLength + 5];
if (pBuffer)
{
strcpy(pBuffer, "\r\n\r\n");
if (!pControl->MSInfoGetData(m_dwView, (long *) (&pBuffer[4]), lBufferLength + 1) == lBufferLength)
{
ASSERT(1);
}
else
{
//process pBuffer for strings to print
CString strBuff(pBuffer);
CString strCharSet = _T("\r\n");
strCharSet += _T("\r"); //strCharSet += 10;
strCharSet += _T("\n"); //strCharSet += 13;
/*for(int i = 0; ;)
{
i = strBuff.FindOneOf(strCharSet);
strLine = strBuff.Left(i);
pPrintHelper->PrintLine(strLine);
i+=2;
strBuff = strBuff.Right(strBuff.GetLength() - i);
//a-stephl: to fix OSR4.1 bug#135918
if (i > strBuff.GetLength())
{
pPrintHelper->PrintLine(strBuff);
break;
}
}*/
//a-stephl: to fix OSR4.1 bug#135918
//for(int i = 0; ;)
int i = 0;
while( i > 0)
{
i = strBuff.FindOneOf(strCharSet);
if (-1 == i)
{
pPrintHelper->PrintLine(strBuff);
}
strLine = strBuff.Left(i);
pPrintHelper->PrintLine(strLine);
i+=2;
strBuff = strBuff.Right(strBuff.GetLength() - i);
}
//end a-stephl: to fix OSR4.1 bug#135918
delete pBuffer;
}
}
}
}
if (bRecursive && this->m_pFirstChild != NULL)
{
for(CMSInfo4Category* pChild = (CMSInfo4Category*) this->GetFirstChild();pChild != NULL;pChild = (CMSInfo4Category*) pChild->GetNextSibling())
{
pChild->Print(pPrintHelper,TRUE);
}
}
}
void CMSInfo4Category::Print(HDC hDC, BOOL bRecursive,int nStartPage, int nEndPage)
{
//nStartPage and nEndPage mark a page range to print;
//if both are 0, then print everything
CMSInfoPrintHelper* pPrintHelper = new CMSInfoPrintHelper(hDC,nStartPage,nEndPage);
//header info..do we need this?
// WCHAR wHeader = 0xFEFF;
//pTxtFile->Write( &wHeader, 2);
CTime tNow = CTime::GetCurrentTime();
CString strTimeFormat;
strTimeFormat.LoadString(IDS_TIME_FORMAT);
CString strHeaderText = tNow.Format(strTimeFormat);
pPrintHelper->PrintLine(strHeaderText);
pPrintHelper->PrintLine("");
Print(pPrintHelper,bRecursive);
delete pPrintHelper;
}
HRESULT CMSInfo4Category::RefreshAllForPrint(HWND hWnd, CRect rctList)
{
if (this->m_pFirstChild != NULL)
{
for(CMSInfo4Category* pChild = (CMSInfo4Category*) this->GetFirstChild();pChild != NULL;pChild = (CMSInfo4Category*) pChild->GetNextSibling())
{
CMSIControl* p4Ctrl;
//if (pChild->GetClsid() !=
if (!CMSInfo4Category::s_pNfo4DataSource->GetControlFromCLSID(pChild->m_strCLSID,p4Ctrl))
{
if (FAILED(pChild->CreateControl(hWnd,rctList)))
{
return E_FAIL;
}
if (CMSInfo4Category::s_pNfo4DataSource->GetControlFromCLSID(pChild->m_strCLSID,p4Ctrl))
{
p4Ctrl->ShowWindow(SW_HIDE);
}
else //if (!CMSInfo4Category::s_pNfo4DataSource->GetControlFromCLSID(pChild->m_strCLSID,p4Ctrl))
{
//ASSERT(!pChild->IsDisplayableCategory() && "Invalid Class ID");
//OCX is not installed on this system
}
}
pChild->RefreshAllForPrint(hWnd,rctList);
}
}
return S_OK;
}
BOOL CMSInfo4Category::IsDisplayableCategory()
{
if ("{00000000-0000-0000-0000-000000000000}" == this->m_strCLSID)
{
return FALSE;
}
return TRUE;
}
//-----------------------------------------------------------------------------
//Saves category information as text, recursing children in bRecursive is true
//-----------------------------------------------------------------------------
BOOL CMSInfo4Category::SaveAsText(CMSInfoTextFile* pTxtFile, BOOL bRecursive)
{
CString strOut;
CString strBracket;
VERIFY(strBracket.LoadString(IDS_LEFTBRACKET) && "Failed to find resource IDS_LEFTBRACKET");
strOut = strBracket;
CString strName, strCaption;
GetNames(&strCaption,&strName);
strOut += strCaption;
VERIFY(strBracket.LoadString(IDS_RIGHTBRACKET) && "Failed to find resource IDS_RIGHTBRACKET");
strOut += strBracket;
pTxtFile->WriteString("\r\n\r\n");
pTxtFile->WriteString(strOut);
CMSIControl* pControl = NULL;
if (!CMSInfo4Category::s_pNfo4DataSource->GetControlFromCLSID(m_strCLSID,pControl))
{
ASSERT(1);
}
else
{
pControl->MSInfoUpdateView();
pControl->MSInfoRefresh();
long lBufferLength = pControl->MSInfoGetData(m_dwView, NULL, 0);
if (lBufferLength < 0)
{
ASSERT(1);
}
else
{
char * pBuffer = new char[lBufferLength + 5];
if (pBuffer)
{
strcpy(pBuffer, "\r\n\r\n");
if (!pControl->MSInfoGetData(m_dwView, (long *) (&pBuffer[4]), lBufferLength + 1) == lBufferLength)
{
ASSERT(0 && "could not get data from control");
}
else
{
//process pBuffer for strings to print
CString strBuff(pBuffer);
pTxtFile->WriteString(pBuffer);
delete pBuffer;
}
}
}
}
if (bRecursive && this->m_pFirstChild != NULL)
{
for(CMSInfo4Category* pChild = (CMSInfo4Category*) this->GetFirstChild();pChild != NULL;pChild = (CMSInfo4Category*) pChild->GetNextSibling())
{
pChild->SaveAsText(pTxtFile,TRUE);
}
}
return TRUE;
}