GME  13
GMEOLEData.cpp
Go to the documentation of this file.
00001 #include <stdafx.h>
00002 #include <afxadv.h>
00003 #include "afxcoll.h"
00004 #include "afxtempl.h"
00005 #include "meta.h"
00006 #include "mga.h"
00007 #include "parser.h"
00008 
00009 #include <algorithm>
00010 #include "CommonMfc.h"
00011 
00012 #include "GMEstd.h"
00013 
00014 #include "GMEOLEData.h"
00015 
00016 #ifdef min
00017 #undef min
00018 #endif
00019 
00020 CLIPFORMAT CGMEDataSource::cfGMEDesc =  (CLIPFORMAT)(RegisterClipboardFormat(_T("GME Descriptor")));
00021 int CGMEDataSource::myData = 0;
00022 
00023 /* --------------------------- CGMEDataDescriptor --------------------------- */
00024 //static // called externally, to destruct certain lists
00025 void CGMEDataDescriptor::destructList( CTypedPtrList<CPtrList, CRect *>& pList)// it is a CRectList
00026 {
00027         POSITION pos = pList.GetHeadPosition();
00028         while(pos)
00029                 delete pList.GetNext(pos);
00030         pList.RemoveAll();
00031 }
00032 
00033 CGMEDataDescriptor::CGMEDataDescriptor(CTypedPtrList<CPtrList, CRect *> &list, CTypedPtrList<CPtrList, CRect *> &annList,CPoint dragPoint,CPoint offs)
00034 {
00035         POSITION pos = list.GetHeadPosition();
00036         while(pos) {
00037                 CRect *rect = new CRect(list.GetNext(pos));
00038                 rect->OffsetRect(-dragPoint.x,-dragPoint.y);
00039                 rects.AddTail(rect);
00040         }
00041 
00042         pos =  annList.GetHeadPosition();
00043         while (pos) {
00044                 CRect *rect = new CRect(annList.GetNext(pos));
00045                 rect->OffsetRect(-dragPoint.x,-dragPoint.y);
00046                 annRects.AddTail(rect);
00047         }
00048 
00049         offset = offs;
00050         pFile = 0;
00051 }
00052 
00053 void CGMEDataDescriptor::Reset()
00054 {
00055         POSITION pos = rects.GetHeadPosition();
00056         while(pos)
00057                 delete rects.GetNext(pos);
00058         rects.RemoveAll();
00059 
00060         pos = annRects.GetHeadPosition();
00061         while(pos)
00062                 delete annRects.GetNext(pos);
00063         annRects.RemoveAll();
00064 }
00065 
00066 void CGMEDataDescriptor::Serialize(CArchive& ar)
00067 {
00068         if(ar.IsStoring()) {
00069                 ar << (int)rects.GetCount();
00070                 POSITION pos = rects.GetHeadPosition();
00071                 while(pos)
00072                         ar << *(rects.GetNext(pos));
00073                 
00074                 ar << (int)annRects.GetCount();
00075                 pos = annRects.GetHeadPosition();
00076                 while(pos)
00077                         ar << *(annRects.GetNext(pos));
00078                 
00079                 ar << offset;
00080         }
00081         else {
00082                 Reset();
00083                 int n;
00084                 ar >> n;
00085                 for(int i = 0; i < n; i++) {
00086                         CRect *rect = new CRect();
00087                         ar >> *rect;
00088                         rects.AddTail(rect);
00089                 }
00090 
00091                 ar >> n;
00092                 for(int j = 0; j < n; j++) {
00093                         CRect *rect = new CRect();
00094                         ar >> *rect;
00095                         annRects.AddTail(rect);
00096                 }
00097                 ar >> offset;
00098         }
00099 }
00100 
00101 bool CGMEDataDescriptor::Load(COleDataObject* pDataObject)
00102 {
00103         ASSERT( pDataObject != NULL );
00104 
00105         if(pDataObject->IsDataAvailable(CGMEDataSource::cfGMEDesc))     {
00106                 ASSERT(pFile == 0);
00107                 pFile = pDataObject->GetFileData(CGMEDataSource::cfGMEDesc);
00108                 ASSERT( pFile != NULL );
00109                 CArchive ar(pFile,CArchive::load);
00110                 Serialize(ar);
00111                 return true;
00112         }
00113         return false;
00114 }
00115 
00116 int CGMEDataDescriptor::GetCount()
00117 {
00118         /* return (rects.GetCount() + annRects.GetCount()); */
00119         return rects.GetCount(); 
00120 }
00121 
00122 void CGMEDataDescriptor::Clean()
00123 {
00124         delete pFile;
00125         pFile = 0;
00126 }
00127 
00128 void CGMEDataDescriptor::Draw(CDC *pDC,CPoint &pt)
00129 {
00130         POSITION pos = rects.GetHeadPosition();
00131         while(pos) {
00132                 CRect rect = *(rects.GetNext(pos));
00133 
00134                 rect.OffsetRect(pt);
00135                 CPoint align = rect.CenterPoint();
00136 
00137                 // Emulate the grid.
00138                 long gs = GME_GRID_SIZE;
00139                 rect.MoveToXY(rect.left / gs * gs, rect.top / gs * gs);
00140 
00141                 pDC->DrawFocusRect(&rect);
00142         }
00143         
00144         pos = annRects.GetHeadPosition();
00145         while (pos) {
00146                 CRect rect = *(annRects.GetNext(pos));
00147 
00148                 rect.OffsetRect(pt);
00149                 pDC->DrawFocusRect(&rect);
00150         }
00151 }
00152 
00153 
00154 // This function has been simplified for GMEActiveBrowser
00155 // No annotations and grid alignment
00156 void CGMEDataDescriptor::SimpleDraw(CDC *pDC, CPoint &pt)
00157 {
00158         POSITION pos = rects.GetHeadPosition();
00159         while(pos) {
00160                 CRect rect = *(rects.GetNext(pos));
00161 
00162                 rect.OffsetRect(pt);
00163 
00164                 pDC->DrawFocusRect(&rect);
00165 
00166         }
00167         
00168 }
00169 
00170 
00171 void CGMEDataDescriptor::GetBoundingRect(CRect &rBoundingRect)
00172 {
00173         rBoundingRect=CRect(0,0,0,0);
00174 
00175         CRect Rect;
00176         POSITION pos=rects.GetHeadPosition();
00177         
00178         while(pos)
00179         {
00180                 Rect=*(rects.GetNext(pos));
00181                 rBoundingRect.UnionRect(rBoundingRect,Rect);
00182         }
00183         
00184 
00185 }
00186 
00187 
00188 /* --------------------------- CGMEDataSource ------------------------------- */
00189 
00190 bool CGMEDataSource::IsGmeNativeDataAvailable(COleDataObject *pDataObject, IMgaProject *project)
00191 {
00192         ASSERT( project != NULL );
00193 
00194         CComPtr<IDataObject> p = pDataObject->GetIDataObject(FALSE);
00195         CComPtr<IMgaDataSource> source;
00196         if( p!= NULL && p.QueryInterface(&source) == S_OK )
00197         {
00198                 CComPtr<IUnknown> unknown;
00199                 HRESULT hr = source->get_Project(&unknown);
00200                 if (hr == HRESULT_FROM_WIN32(RPC_S_CALL_FAILED)) // crashrpt 17f8cc45-c369-464b-8162-5dc7bf3bf04c
00201                         return false;
00202                 COMTHROW(hr);
00203                 ASSERT( unknown != NULL );
00204 
00205                 if (unknown == NULL)
00206                 {
00207                         // Likely a race, crashrpt e27fb137-199a-4ff8-842e-301655495738
00208                         return false;
00209                 }
00210 
00211                 CComPtr<IMgaProject> source_project;
00212                 // KMS: fixing crashrpt 8895373f-396e-490f-b882-036ba9d42961: this QI may fail
00213                 hr = unknown.QueryInterface(&source_project);
00214                 if ( source_project == NULL ) {
00215                         ASSERT(false);
00216                         return false;
00217                 }
00218 
00219                 return source_project.IsEqualObject(project);
00220         }
00221         return false;
00222 }
00223 
00224 bool CGMEDataSource::IsXMLDataAvailable(COleDataObject *pDataObject)
00225 {
00226         ASSERT( pDataObject != NULL );
00227 
00228         return pDataObject->IsDataAvailable(CF_UNICODETEXT) != FALSE;
00229 }
00230 
00231 bool CGMEDataSource::ParseXMLData(COleDataObject *pDataObject, IMgaObject *target, bool merge = false)
00232 {
00233         ASSERT( pDataObject != NULL );
00234         ASSERT( target != NULL );
00235 
00236         // create a temporary filename
00237       TCHAR *fname = _ttempnam(_T("c:\\temp"), _T("GMEtmp"));
00238         CString filename = fname;
00239         free(fname);
00240 
00241         try
00242         {
00243                 // get the memory file
00244                 CFile *memfile = pDataObject->GetFileData(CF_UNICODETEXT);
00245                 if( memfile == NULL )
00246                         return false;
00247                 // FIXME: memfile->GetLength() isn't the same as pFile->GetLength() in OnRenderFileData
00248 
00249                 // copy
00250                 CFile file;
00251                 if( file.Open(filename, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary) == 0 )
00252                         return false;
00253 
00254                 wchar_t buff[10240];
00255                 UINT c;
00256                 do
00257                 {
00258                         c = memfile->Read(buff, sizeof(buff));
00259 
00260                         c = wcsnlen(buff, c/sizeof(wchar_t)) * sizeof(wchar_t);
00261 
00262                         file.Write(buff, c);
00263                 } while( c == sizeof(buff) );
00264                 file.Close();
00265 
00266                 // clear the memory file
00267                 delete memfile;
00268 
00269                 // parse
00270                 CComPtr<IMgaParser> parser;
00271                 COMTHROW( parser.CoCreateInstance(L"Mga.MgaParser") );
00272                 ASSERT( parser != NULL );
00273 
00274                 CComBstrObj acckind, version; 
00275                 VARIANT_BOOL is_acc_target;
00276                 COMTHROW( parser->GetClipXMLInfo( PutInBstr(filename), target, &is_acc_target, PutOut( acckind), PutOut( version)) );
00277                 CString ver = _T("0"); // defval
00278                 if( version) // clipboard main token found, otherwise use defval
00279                         CopyTo( version, ver);
00280 
00281 
00282                 CComObjPtr<IMgaProject> t_project;
00283                 COMTHROW(target->get_Project( PutOut(t_project)));
00284                 CComPtr<IGMEOLEApp> t_GME = CGMEDataSource::get_GME( t_project);
00285                 
00286                 CComBSTR msg, done;
00287                 COMTHROW(done.Append(_T("Done.")));
00288                 if( ver == _T("0"))
00289                 {
00290                         COMTHROW(msg.Append(_T("Inserting XML data...")));
00291                         if( t_GME) COMTHROW( t_GME->ConsoleMessage( msg, MSG_INFO));
00292                         COMTHROW( parser->ParseFCOs(target, PutInBstr(filename)) );
00293                         if( t_GME) COMTHROW( t_GME->ConsoleMessage( done, MSG_INFO));
00294                 }
00295                 else if( ver == _T("4"))
00296                 {
00297                         COMTHROW(msg.Append(_T("Inserting XML SmartCopied data...")));
00298                         if( t_GME) COMTHROW( t_GME->ConsoleMessage( msg, MSG_INFO));
00299                         COMTHROW( parser->ParseClos4( target, PutInBstr(filename), merge?MERGE:ADDITION ));
00300                         if( t_GME) COMTHROW( t_GME->ConsoleMessage( done, MSG_INFO));
00301                 }
00302                 else if ( ver == _T("1") || ver == _T(""))
00303                 {
00304                         COMTHROW(msg.Append(_T("Inserting XML CopyClosured data...")));
00305                         if( t_GME) COMTHROW( t_GME->ConsoleMessage( msg, MSG_INFO));
00306                         COMTHROW( parser->ParseClos1(target, PutInBstr(filename)) );
00307                         if( t_GME) COMTHROW( t_GME->ConsoleMessage( done, MSG_INFO));
00308                 }
00309                 else
00310                 {
00311                         COMTHROW(msg.Append(_T("Error: Unknown clipboard closure format")));
00312                         if( t_GME) COMTHROW( t_GME->ConsoleMessage( msg, MSG_INFO));
00313 
00314                         ASSERT(0);
00315                 }
00316                 
00317                         
00318                 CFile::Remove(filename);
00319 
00320                 return true;
00321         }
00322         catch(hresult_exception &e)
00323         {
00324                 CFile::Remove(filename);
00325 
00326                 try
00327                 {
00328                         CComObjPtr<IErrorInfo> errinfo;
00329                         COMTHROW( GetErrorInfo(0, PutOut(errinfo)) );
00330                         ASSERT( errinfo != NULL );
00331 
00332                         CString desc;
00333                         COMTHROW( errinfo->GetDescription(PutOut(desc)) );
00334 
00335                         AfxMessageBox(CString(_T("Error while parsing XML file: ")) + desc);
00336                 }
00337                 catch(hresult_exception &)
00338                 {
00339                         AfxMessageBox(_T("Fatal error while parsing XML file!"));
00340                 }
00341 
00342                 throw e;
00343         }
00344 
00345         return false;
00346 }
00347 
00348 void CGMEDataSource::CacheDescriptor(CGMEDataDescriptor* desc)
00349 {
00350         CacheGlobalData(cfGMEDesc, CreateDescriptor(desc));
00351         DelayXMLDump();
00352 }
00353 
00354 HGLOBAL CGMEDataSource::CreateDescriptor(CGMEDataDescriptor* desc)
00355 {
00356         ASSERT(desc);
00357 
00358         CSharedFile file;
00359         CArchive ar(&file, CArchive::store);
00360         desc->Serialize(ar);
00361         ar.Close();
00362         return file.Detach();
00363 }
00364 
00365 void CGMEDataSource::DelayXMLDump()
00366 {
00367         FORMATETC fe = {
00368     CF_UNICODETEXT, NULL, DVASPECT_CONTENT, -1, TYMED_ISTREAM|TYMED_HGLOBAL
00369         };
00370           
00371         DelayRenderFileData(CF_UNICODETEXT, &fe);
00372 }
00373 
00374 BOOL CGMEDataSource::OnRenderFileData(LPFORMATETC lpFormatEtc, CFile* pFile)
00375 {
00376         if( lpFormatEtc->cfFormat == CF_UNICODETEXT )
00377         {
00378                 ASSERT( pFile != NULL );
00379 
00380                 // TODO: we have to dump it directly to the shared memory file
00381 
00382                 try
00383                 {
00384                         TCHAR *fname = _ttempnam(_T("c:\\temp"), _T("tmp"));
00385                         CString filename = fname;
00386                         free(fname);
00387                 
00388                         CComPtr<IMgaDumper> dumper;
00389                         COMTHROW( dumper.CoCreateInstance(L"Mga.MgaDumper") );
00390 
00391                         CComObjPtr<IMgaFCOs> fcos;
00392                         if ( data) // check whether it is set
00393                                 COMTHROW( ::QueryInterface( data, fcos) );
00394 
00395                         CComObjPtr<IMgaFolders> folds;
00396                         if ( folders) // check whether it is set
00397                                 COMTHROW( ::QueryInterface( folders, folds) );
00398 
00399                         CComObjPtr<IMgaRegNodes> regd;
00400                         if ( regdata) // check whether it is set
00401                                 COMTHROW( ::QueryInterface( regdata, regd) );
00402 
00403                         COMTHROW( dumper->DumpFCOs( project, fcos, folds, regd, PutInBstr(filename)) );
00404 
00405                         CFile file;
00406                         if( file.Open(filename, CFile::modeRead | CFile::typeBinary) == 0 )
00407                                 return FALSE;
00408                         
00409                         const int buffsize = 10240;
00410                         unsigned char buff[buffsize];
00411                         file.Read(buff, 2); // skip BOM
00412                         UINT c;
00413                         do
00414                         {
00415                                 c = file.Read(buff, buffsize);
00416                                 pFile->Write(buff, c);
00417                         } while( c == buffsize );
00418                         pFile->Write(L"", sizeof(wchar_t));
00419 
00420                         file.Close();
00421                         CFile::Remove(filename);
00422                 }
00423                 catch(hresult_exception &)
00424                 {
00425                         return FALSE;
00426                 }
00427                 catch(CFileException *)
00428                 {
00429                         return FALSE;
00430                 }
00431 
00432                 return TRUE;
00433         }
00434 
00435         return FALSE;
00436 }
00437 
00438 // ****************************************************************************************************
00439 // *********************************   CGMEClosureDataSource  *****************************************
00440 // ****************************************************************************************************
00441 BOOL CGMEClosureDataSource::OnRenderFileData(LPFORMATETC lpFormatEtc, CFile* pFile)
00442 {
00443         if( lpFormatEtc->cfFormat == CF_UNICODETEXT )
00444         {
00445                 ASSERT( pFile != NULL );
00446 
00447                 // TODO: we have to dump it directly to the shared memory file
00448 
00449                 try
00450                 {
00451                         TCHAR *fname = _ttempnam(_T("c:\\temp"), _T("tmp"));
00452                         CString filename = fname;
00453                         free(fname);
00454                 
00455                         CComPtr<IMgaDumper> dumper;
00456                         COMTHROW( dumper.CoCreateInstance(L"Mga.MgaDumper") );
00457 
00458                         CComObjPtr<IMgaFCOs> fcos;
00459                         if ( data) // is it set?
00460                                 COMTHROW( ::QueryInterface(data, fcos) );
00461 
00462                         CComObjPtr<IMgaFolders> fols;
00463                         if ( folders) // is it set?
00464                                 COMTHROW( ::QueryInterface( folders, fols) );
00465 
00466                         bool is_top_set = false;
00467                         CComObjPtr<IMgaFCOs> top_fcos;
00468                         CComObjPtr<IMgaFolders> top_folds;
00469 
00470                         if ( m_topFcos)
00471                         {
00472                                 COMTHROW( ::QueryInterface( m_topFcos, top_fcos) );
00473                                 is_top_set = true;
00474                         }
00475 
00476                         if ( m_topFolders)
00477                         {
00478                                 COMTHROW( ::QueryInterface( m_topFolders, top_folds) );
00479                                 is_top_set = true;
00480                         }
00481 
00482                         if ( is_top_set)
00483                                 COMTHROW( dumper->DumpClosR( fcos, fols, PutInBstr( filename), top_fcos, top_folds, m_options, m_absPathPart, m_acceptingKinds) );
00484                         else // if top objects are not set dump starting from RootFolder
00485                                 COMTHROW( dumper->DumpClos( fcos, fols, PutInBstr( filename), m_options) );
00486 
00487                         CFile file;
00488                         if( file.Open(filename, CFile::modeRead | CFile::typeBinary) == 0 )
00489                                 return FALSE;
00490 
00491                         const int buffsize = 10240;
00492                         unsigned char buff[buffsize];
00493                         UINT c;
00494                         do
00495                         {
00496                                 c = file.Read(buff, buffsize);
00497                                 pFile->Write(buff, c);
00498                         } while( c == buffsize );
00499 
00500                         pFile->Write(L"", sizeof(wchar_t));
00501 
00502                         file.Close();
00503                         CFile::Remove(filename);
00504                 }
00505                 catch(hresult_exception &)
00506                 {
00507                         return FALSE;
00508                 }
00509                 catch(CFileException *)
00510                 {
00511                         return FALSE;
00512                 }
00513 
00514                 return TRUE;
00515         }
00516 
00517         return FALSE;
00518 }
00519 
00520 BEGIN_MESSAGE_MAP(CGMEDataSource, COleDataSource)
00521         //{{AFX_MSG_MAP(CGMEDataSource)
00522                 // NOTE - the ClassWizard will add and remove mapping macros here.
00523         //}}AFX_MSG_MAP
00524 END_MESSAGE_MAP()
00525 
00526 // Interface Maps
00527 
00528 BEGIN_DISPATCH_MAP(CGMEDataSource, COleDataSource)
00529         //{{AFX_DISPATCH_MAP(CGMEDataSource)
00530         DISP_PROPERTY_EX(CGMEDataSource, "Data", DispGetData, DispSetData, VT_DISPATCH)
00531         DISP_PROPERTY_EX(CGMEDataSource, "Folders", DispGetFolders, DispSetFolders, VT_DISPATCH)
00532         DISP_PROPERTY_EX(CGMEDataSource, "RegistryData", DispGetRegistryData, DispSetRegistryData, VT_DISPATCH)
00533         DISP_PROPERTY_EX(CGMEDataSource, "Project", DispGetProject, DispSetProject, VT_DISPATCH)
00534         //}}AFX_DISPATCH_MAP
00535 END_DISPATCH_MAP()
00536 
00537 
00538 BEGIN_INTERFACE_MAP(CGMEDataSource, COleDataSource)
00539         INTERFACE_PART(CGMEDataSource, IID_IMgaDataSource, MgaDataSource)
00540         DUAL_ERRORINFO_PART(CGMEDataSource)
00541 END_INTERFACE_MAP()
00542 
00543 DELEGATE_DUAL_INTERFACE(CGMEDataSource, MgaDataSource)
00544 
00545 // Implement ISupportErrorInfo to indicate we support the
00546 // OLE Automation error handler.
00547 IMPLEMENT_DUAL_ERRORINFO(CGMEDataSource, IID_IMgaDataSource)
00548 
00549 
00550 STDMETHODIMP CGMEDataSource::XMgaDataSource::get_Data(IUnknown **p)
00551 {
00552         METHOD_PROLOGUE(CGMEDataSource, MgaDataSource)
00553         CHECK_OUT(p);
00554 
00555         if( pThis->data != NULL )
00556                 return pThis->data.QueryInterface(p);
00557 
00558         return S_OK;
00559 }
00560 
00561 STDMETHODIMP CGMEDataSource::XMgaDataSource::get_Folders(IUnknown **p)
00562 {
00563         METHOD_PROLOGUE(CGMEDataSource, MgaDataSource)
00564         CHECK_OUT(p);
00565 
00566         if( pThis->folders != NULL )
00567                 return pThis->folders.QueryInterface(p);
00568 
00569         return S_OK;
00570 }
00571 
00572 STDMETHODIMP CGMEDataSource::XMgaDataSource::get_RegistryData(IUnknown **p)
00573 {
00574         METHOD_PROLOGUE(CGMEDataSource, MgaDataSource)
00575         CHECK_OUT(p);
00576 
00577         if( pThis->regdata != NULL )
00578                 return pThis->regdata.QueryInterface(p);
00579 
00580         return S_OK;
00581 }
00582 
00583 STDMETHODIMP CGMEDataSource::XMgaDataSource::get_Project(IUnknown **p)
00584 {
00585         METHOD_PROLOGUE(CGMEDataSource, MgaDataSource)
00586         CHECK_OUT(p);
00587 
00588         return pThis->project.QueryInterface(p);
00589 }
00590 
00591 
00592 
00593 
00594 /*static*/ CComPtr<IGMEOLEApp> CGMEDataSource::get_GME(CComObjPtr<IMgaProject> project)
00595 {
00596         CComPtr<IGMEOLEApp> gme;
00597         if ( (project != NULL)) {               
00598                 CComBSTR bstrName(L"GME.Application");
00599                 CComPtr<IMgaClient> pClient;
00600                 HRESULT hr = project->GetClientByName(bstrName, &pClient);
00601                 if (SUCCEEDED(hr) && pClient) {
00602                         CComPtr<IDispatch> pDispatch;
00603                         hr = pClient->get_OLEServer(&pDispatch);
00604                         if (SUCCEEDED(hr) && pDispatch) {
00605                                 hr = pDispatch.QueryInterface(&gme);
00606                                 if (FAILED(hr)) {
00607                                         gme = NULL;
00608                                 }
00609                         }
00610                 }
00611         }
00612         return gme;
00613 } 
00614 
00615 LPDISPATCH CGMEDataSource::DispGetData() 
00616 {
00617         CComPtr<IDispatch> p;
00618         if( data != NULL ) {
00619                 data.QueryInterface(&p);
00620         }
00621 
00622         return p.Detach();
00623 }
00624 
00625 void CGMEDataSource::DispSetData(LPDISPATCH) 
00626 {
00627         SetNotSupported();
00628 }
00629 
00630 LPDISPATCH CGMEDataSource::DispGetFolders() 
00631 {
00632         CComPtr<IDispatch> p;
00633         if( folders != NULL ) {
00634                 folders.QueryInterface(&p);
00635         }
00636 
00637         return p.Detach();
00638 }
00639 
00640 void CGMEDataSource::DispSetFolders(LPDISPATCH) 
00641 {
00642         SetNotSupported();
00643 }
00644 
00645 LPDISPATCH CGMEDataSource::DispGetRegistryData() 
00646 {
00647         CComPtr<IDispatch> p;
00648         if(  regdata != NULL ) {
00649                 regdata.QueryInterface(&p);
00650         }
00651 
00652         return p.Detach();
00653 }
00654 
00655 void CGMEDataSource::DispSetRegistryData(LPDISPATCH) 
00656 {
00657         SetNotSupported();
00658 }
00659 
00660 LPDISPATCH CGMEDataSource::DispGetProject() 
00661 {
00662         CComPtr<IDispatch> p;
00663         if( project != NULL ) {
00664                 COMTHROW(project.QueryInterface(&p));
00665         }
00666 
00667         return p.Detach();
00668 }
00669 
00670 void CGMEDataSource::DispSetProject(LPDISPATCH) 
00671 {
00672         SetNotSupported();
00673 }
00674 
00675