//----------------------------------------------------------------------------- IPlatformBitmap* IPlatformBitmap::createFromPath (UTF8StringPtr absolutePath) { UTF8StringHelper path (absolutePath); IStream* stream = 0; if (SUCCEEDED (SHCreateStreamOnFileEx (path, STGM_READ|STGM_SHARE_DENY_WRITE, 0, false, 0, &stream))) { #if VSTGUI_DIRECT2D_SUPPORT if (getD2DFactory ()) { D2DBitmap* result = new D2DBitmap (); if (result->loadFromStream (stream)) { stream->Release (); return result; } stream->Release (); result->forget (); return 0; } #endif GdiplusBitmap* bitmap = new GdiplusBitmap (); if (bitmap->loadFromStream (stream)) { stream->Release (); return bitmap; } bitmap->forget (); stream->Release (); } return 0; }
// // Function to create a readable IStream over the file whose name is the // concatenation of the path and fileName parameters. For simplicity, file // names including path are assumed to be 100 characters or less. A real // application should be able to handle longer names and allocate the // necessary buffer dynamically. // // Parameters: // path - Path of the folder containing the file to be opened, ending with a // slash ('\') character // fileName - Name, not including path, of the file to be opened // stream - Output parameter pointing to the created instance of IStream over // the specified file when this function succeeds. // HRESULT GetFileStream( _In_ LPCWSTR path, _In_ LPCWSTR fileName, _Outptr_ IStream** stream) { HRESULT hr = S_OK; const int MaxFileNameLength = 100; WCHAR fullFileName[MaxFileNameLength + 1]; // Create full file name by concatenating path and fileName hr = StringCchCopyW(fullFileName, MaxFileNameLength, path); if (SUCCEEDED(hr)) { hr = StringCchCat(fullFileName, MaxFileNameLength, fileName); } // Create stream for reading the file if (SUCCEEDED(hr)) { hr = SHCreateStreamOnFileEx( fullFileName, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, // default file attributes FALSE, // do not create new file NULL, // no template stream); } return hr; }
// Creates a set of sample files in the current user's Documents directory to use as items in the // custom category inserted into the Jump List. HRESULT CreateSampleFiles() { PWSTR pszPathDocuments; HRESULT hr = SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_CREATE, NULL, &pszPathDocuments); if (SUCCEEDED(hr)) { for (UINT i = 0; SUCCEEDED(hr) && i < ARRAYSIZE(c_rgpszFiles); i++) { WCHAR szPathSample[MAX_PATH]; hr = PathCombine(szPathSample, pszPathDocuments, c_rgpszFiles[i]) ? S_OK : E_FAIL; if (SUCCEEDED(hr)) { IStream *pstm; hr = SHCreateStreamOnFileEx(szPathSample, (STGM_WRITE | STGM_FAILIFTHERE), FILE_ATTRIBUTE_NORMAL, TRUE, NULL, &pstm); if (SUCCEEDED(hr)) { PCWSTR pszText = L"This is a sample file for the CustomJumpListSample.\r\n"; ULONG cb = (sizeof(pszText[0]) * (lstrlen(pszText) + 1)); hr = IStream_Write(pstm, pszText, cb); pstm->Release(); } else if (HRESULT_FROM_WIN32(ERROR_FILE_EXISTS) == hr) { // If the file exists, we're ok, we'll just reuse it hr = S_OK; } } } CoTaskMemFree(pszPathDocuments); } return hr; }
HRESULT AssemblyStore::ReadFileToStream(LPCWSTR fileName, IStream* pStream) { HRESULT hr = SHCreateStreamOnFileEx (fileName, STGM_READ | STGM_SHARE_DENY_WRITE | STGM_FAILIFTHERE, 0, FALSE, NULL, &pStream); return hr; }
/************************************************************************* * SHCreateStreamOnFileW [SHLWAPI.@] * * See SHCreateStreamOnFileA. */ HRESULT WINAPI SHCreateStreamOnFileW(LPCWSTR lpszPath, DWORD dwMode, IStream **lppStream) { TRACE("(%s,%ld,%p)\n", debugstr_w(lpszPath), dwMode, lppStream); if (!lpszPath || !lppStream) return E_INVALIDARG; return SHCreateStreamOnFileEx(lpszPath, dwMode, 0, FALSE, NULL, lppStream); }
HRESULT CNativeRibbonApp::LoadRibbonViewSettings(IUIRibbon* pRibbonView, const CString& fileName) { CComPtr<IStream> stream; HRESULT hr = SHCreateStreamOnFileEx(fileName, STGM_READ, FILE_ATTRIBUTE_NORMAL, FALSE, nullptr, &stream); if (FAILED(hr)) return hr; hr = pRibbonView->LoadSettingsFromStream(stream); return hr; }
/************************************************************************* * SHCreateStreamOnFileW [SHLWAPI.@] * * See SHCreateStreamOnFileA. */ HRESULT WINAPI SHCreateStreamOnFileW(LPCWSTR lpszPath, DWORD dwMode, IStream **lppStream) { TRACE("(%s,%d,%p)\n", debugstr_w(lpszPath), dwMode, lppStream); if (!lpszPath || !lppStream) return E_INVALIDARG; if ((dwMode & (STGM_CONVERT|STGM_DELETEONRELEASE|STGM_TRANSACTED)) != 0) return E_INVALIDARG; return SHCreateStreamOnFileEx(lpszPath, dwMode, 0, FALSE, NULL, lppStream); }
// // Function to create an Appx Bundle writer with default settings, given the // output file name. // // Parameters: // outputFileName - Name including path to the bundle (.appxbundle file) to // be created. // writer - Output parameter pointing to the created instance of // IAppxBundleWriter when this function succeeds. // HRESULT GetBundleWriter( _In_ LPCWSTR outputFileName, _Outptr_ IAppxBundleWriter** writer) { HRESULT hr = S_OK; IStream* outputStream = NULL; IAppxBundleFactory* appxBundleFactory = NULL; // Create a stream over the output file where the bundle will be written hr = SHCreateStreamOnFileEx( outputFileName, STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, // default file attributes TRUE, // create file if it does not exist NULL, // no template &outputStream); // Create a new Appx Bundle factory if (SUCCEEDED(hr)) { hr = CoCreateInstance( __uuidof(AppxBundleFactory), NULL, CLSCTX_INPROC_SERVER, __uuidof(IAppxBundleFactory), (LPVOID*)(&appxBundleFactory)); } // Create a new bundle writer using the factory if (SUCCEEDED(hr)) { hr = appxBundleFactory->CreateBundleWriter( outputStream, 0, // by specifying 0, the bundle will have an automatically // generated version number based on the current time writer); } // Clean up allocated resources if (appxBundleFactory != NULL) { appxBundleFactory->Release(); appxBundleFactory = NULL; } if (outputStream != NULL) { outputStream->Release(); outputStream = NULL; } return hr; }
// // Function to create an Appx package reader given the input file name. // // Parameters: // inputFileName - Name including path to the Appx package (.appx file) to // be opened. // reader - Output parameter pointing to the created instance of // IAppxPackageReader when this function succeeds. // HRESULT GetPackageReader( _In_ LPCWSTR inputFileName, _Outptr_ IAppxPackageReader** reader) { HRESULT hr = S_OK; IAppxFactory* appxFactory = NULL; IStream* inputStream = NULL; // Create a new Appx factory hr = CoCreateInstance( __uuidof(AppxFactory), NULL, CLSCTX_INPROC_SERVER, __uuidof(IAppxFactory), (LPVOID*)(&appxFactory)); // Create a stream over the input Appx package if (SUCCEEDED(hr)) { hr = SHCreateStreamOnFileEx( inputFileName, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, // default file attributes FALSE, // do not create new file NULL, // no template &inputStream); } // Create a new package reader using the factory. if (SUCCEEDED(hr)) { hr = appxFactory->CreatePackageReader( inputStream, reader); } // Clean up allocated resources if (inputStream != NULL) { inputStream->Release(); inputStream = NULL; } if (appxFactory != NULL) { appxFactory->Release(); appxFactory = NULL; } return hr; }
HRESULT CNativeRibbonApp::SaveRibbonViewSettings(IUIRibbon* pRibbonView, const CString& fileName) { CComPtr<IStream> stream; HRESULT hr = SHCreateStreamOnFileEx(fileName, STGM_WRITE | STGM_CREATE, FILE_ATTRIBUTE_NORMAL, TRUE, nullptr, &stream); if (FAILED(hr)) return hr; hr = pRibbonView->SaveSettingsToStream(stream); if (FAILED(hr)) { stream->Revert(); return hr; } hr = stream->Commit(STGC_DEFAULT); return hr; }
/************************************************************************* * OpenStreamOnFile@24 (MAPI32.147) * * Create a stream on a file. * * PARAMS * lpAlloc [I] Memory allocation function * lpFree [I] Memory free function * ulFlags [I] Flags controlling the opening process * lpszPath [I] Path of file to create stream on * lpszPrefix [I] Prefix of the temporary file name (if ulFlags includes SOF_UNIQUEFILENAME) * lppStream [O] Destination for created stream * * RETURNS * Success: S_OK. lppStream contains the new stream object * Failure: E_INVALIDARG if any parameter is invalid, or an HRESULT error code * describing the error. */ HRESULT WINAPI OpenStreamOnFile(LPALLOCATEBUFFER lpAlloc, LPFREEBUFFER lpFree, ULONG ulFlags, LPWSTR lpszPath, LPWSTR lpszPrefix, LPSTREAM *lppStream) { WCHAR szBuff[MAX_PATH]; DWORD dwMode = STGM_READWRITE, dwAttributes = 0; HRESULT hRet; TRACE("(%p,%p,0x%08x,%s,%s,%p)\n", lpAlloc, lpFree, ulFlags, debugstr_a((LPSTR)lpszPath), debugstr_a((LPSTR)lpszPrefix), lppStream); if (mapiFunctions.OpenStreamOnFile) return mapiFunctions.OpenStreamOnFile(lpAlloc, lpFree, ulFlags, lpszPath, lpszPrefix, lppStream); if (lppStream) *lppStream = NULL; if (ulFlags & SOF_UNIQUEFILENAME) { FIXME("Should generate a temporary name\n"); return E_INVALIDARG; } if (!lpszPath || !lppStream) return E_INVALIDARG; /* FIXME: Should probably munge mode and attributes, and should handle * Unicode arguments (I assume MAPI_UNICODE is set in ulFlags if * we are being passed Unicode strings; MSDN doesn't say). * This implementation is just enough for Outlook97 to start. */ MultiByteToWideChar(CP_ACP, 0, (LPSTR)lpszPath, -1, szBuff, MAX_PATH); hRet = SHCreateStreamOnFileEx(szBuff, dwMode, dwAttributes, TRUE, NULL, lppStream); return hRet; }
// // Function to create a writable IStream over a file with the specified name // under the specified path. This function will also create intermediate // subdirectories if necessary. For simplicity, file names including path are // assumed to be 200 characters or less. A real application should be able to // handle longer names and allocate the necessary buffer dynamically. // // Parameters: // path - Path of the folder containing the file to be opened. This should NOT // end with a slash ('\') character. // fileName - Name, not including path, of the file to be opened // stream - Output parameter pointing to the created instance of IStream over // the specified file when this function succeeds. // HRESULT GetOutputStream( _In_ LPCWSTR path, _In_ LPCWSTR fileName, _Outptr_ IStream** stream) { HRESULT hr = S_OK; const int MaxFileNameLength = 200; WCHAR fullFileName[MaxFileNameLength + 1]; // Create full file name by concatenating path and fileName hr = StringCchCopyW(fullFileName, MaxFileNameLength, path); if (SUCCEEDED(hr)) { hr = StringCchCat(fullFileName, MaxFileNameLength, L"\\"); } if (SUCCEEDED(hr)) { hr = StringCchCat(fullFileName, MaxFileNameLength, fileName); } // Search through fullFileName for the '\' character which denotes // subdirectory and create each subdirectory in order of depth. for (int i = 0; SUCCEEDED(hr) && (i < MaxFileNameLength); i++) { if (fullFileName[i] == L'\0') { break; } else if (fullFileName[i] == L'\\') { // Temporarily set string to terminate at the '\' character // to obtain name of the subdirectory to create fullFileName[i] = L'\0'; if (!CreateDirectory(fullFileName, NULL)) { DWORD lastError = GetLastError(); // It is normal for CreateDirectory to fail if the subdirectory // already exists. Other errors should not be ignored. if (lastError != ERROR_ALREADY_EXISTS) { hr = HRESULT_FROM_WIN32(lastError); } } // Restore original string fullFileName[i] = L'\\'; } } // Create stream for writing the file if (SUCCEEDED(hr)) { hr = SHCreateStreamOnFileEx( fullFileName, STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, // default file attributes TRUE, // create new file if it does not exist NULL, // no template stream); } return hr; }
////////////////////////////////////////////////////////////////////////// // IDataObject ////////////////////////////////////////////////////////////////////////// STDMETHODIMP GitDataObject::GetData(FORMATETC* pformatetcIn, STGMEDIUM* pmedium) { if (!pformatetcIn) return E_INVALIDARG; if (!pmedium) return E_POINTER; pmedium->hGlobal = nullptr; if ((pformatetcIn->tymed & TYMED_ISTREAM) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_FILECONTENTS)) { // supports the IStream format. // The lindex param is the index of the file to return CString filepath; IStream* pIStream = nullptr; // Note: we don't get called for directories since those are simply created and don't // need to be fetched. // Note2: It would be really nice if we could get a stream from the subversion library // from where we could read the file contents. But the Subversion lib is not implemented // to *read* from a remote stream but so that the library *writes* to a stream we pass. // Since we can't get such a read stream, we have to fetch the file in whole first to // a temp location and then pass the shell an IStream for that temp file. if (m_revision.IsEmpty()) { if ((pformatetcIn->lindex >= 0) && (pformatetcIn->lindex < (LONG)m_allPaths.size())) filepath = g_Git.CombinePath(m_allPaths[pformatetcIn->lindex]); } else { filepath = CTempFiles::Instance().GetTempFilePath(true).GetWinPathString(); if ((pformatetcIn->lindex >= 0) && (pformatetcIn->lindex < (LONG)m_allPaths.size())) { if (g_Git.GetOneFile(m_revision.ToString(), m_allPaths[pformatetcIn->lindex], filepath)) { DeleteFile(filepath); return STG_E_ACCESSDENIED; } } } HRESULT res = SHCreateStreamOnFileEx(filepath, STGM_READ, FILE_ATTRIBUTE_NORMAL, FALSE, nullptr, &pIStream); if (res == S_OK) { // http://blogs.msdn.com/b/oldnewthing/archive/2014/09/18/10558763.aspx LARGE_INTEGER liZero = { 0, 0 }; pIStream->Seek(liZero, STREAM_SEEK_END, nullptr); pmedium->pstm = pIStream; pmedium->tymed = TYMED_ISTREAM; return S_OK; } return res; } else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_FILEDESCRIPTOR)) { for (int i = 0; i < m_gitPaths.GetCount(); ++i) { if (m_gitPaths[i].m_Action & (CTGitPath::LOGACTIONS_MISSING | CTGitPath::LOGACTIONS_DELETED) || m_gitPaths[i].IsDirectory()) continue; m_allPaths.push_back(m_gitPaths[i]); } size_t dataSize = sizeof(FILEGROUPDESCRIPTOR) + ((max(1, m_allPaths.size()) - 1) * sizeof(FILEDESCRIPTOR)); HGLOBAL data = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT, dataSize); FILEGROUPDESCRIPTOR* files = (FILEGROUPDESCRIPTOR*)GlobalLock(data); files->cItems = static_cast<UINT>(m_allPaths.size()); int index = 0; for (auto it = m_allPaths.cbegin(); it != m_allPaths.cend(); ++it) { CString temp(m_iStripLength > 0 ? it->GetWinPathString().Mid(m_iStripLength + 1) : (m_iStripLength == 0 ? it->GetWinPathString() : it->GetUIFileOrDirectoryName())); if (temp.GetLength() < MAX_PATH) wcscpy_s(files->fgd[index].cFileName, (LPCTSTR)temp); else { files->cItems--; continue; } files->fgd[index].dwFlags = FD_ATTRIBUTES | FD_PROGRESSUI | FD_FILESIZE | FD_LINKUI; files->fgd[index].dwFileAttributes = FILE_ATTRIBUTE_NORMAL; // Always set the file size to 0 even if we 'know' the file size (infodata.size64). // Because for text files, the file size is too low due to the EOLs getting converted // to CRLF (from LF as stored in the repository). And a too low file size set here // prevents the shell from reading the full file later - it only reads the stream up // to the number of bytes specified here. Which means we would end up with a truncated // text file (binary files are still ok though). files->fgd[index].nFileSizeLow = 0; files->fgd[index].nFileSizeHigh = 0; ++index; } GlobalUnlock(data); pmedium->hGlobal = data; pmedium->tymed = TYMED_HGLOBAL; return S_OK; } // handling CF_PREFERREDDROPEFFECT is necessary to tell the shell that it should *not* ask for the // CF_FILEDESCRIPTOR until the drop actually occurs. If we don't handle CF_PREFERREDDROPEFFECT, the shell // will ask for the file descriptor for every object (file/folder) the mouse pointer hovers over and is // a potential drop target. else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->cfFormat == CF_PREFERREDDROPEFFECT)) { HGLOBAL data = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT, sizeof(DWORD)); DWORD* effect = (DWORD*)GlobalLock(data); (*effect) = DROPEFFECT_COPY; GlobalUnlock(data); pmedium->hGlobal = data; pmedium->tymed = TYMED_HGLOBAL; return S_OK; } else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_TEXT)) { // caller wants text // create the string from the path list CString text; if (!m_gitPaths.IsEmpty()) { // create a single string where the URLs are separated by newlines for (int i = 0; i < m_gitPaths.GetCount(); ++i) { text += m_gitPaths[i].GetWinPathString(); text += L"\r\n"; } } CStringA texta = CUnicodeUtils::GetUTF8(text); pmedium->tymed = TYMED_HGLOBAL; pmedium->hGlobal = GlobalAlloc(GHND, (texta.GetLength() + 1) * sizeof(char)); if (pmedium->hGlobal) { char* pMem = (char*)GlobalLock(pmedium->hGlobal); strcpy_s(pMem, texta.GetLength() + 1, (LPCSTR)texta); GlobalUnlock(pmedium->hGlobal); } pmedium->pUnkForRelease = nullptr; return S_OK; } else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && ((pformatetcIn->cfFormat == CF_UNICODETEXT) || (pformatetcIn->cfFormat == CF_INETURL) || (pformatetcIn->cfFormat == CF_SHELLURL))) { // caller wants Unicode text // create the string from the path list CString text; if (!m_gitPaths.IsEmpty()) { // create a single string where the URLs are separated by newlines for (int i = 0; i < m_gitPaths.GetCount(); ++i) { if (pformatetcIn->cfFormat == CF_UNICODETEXT) text += m_gitPaths[i].GetWinPathString(); else text += g_Git.CombinePath(m_gitPaths[i]); text += L"\r\n"; } } pmedium->tymed = TYMED_HGLOBAL; pmedium->hGlobal = GlobalAlloc(GHND, (text.GetLength() + 1) * sizeof(TCHAR)); if (pmedium->hGlobal) { TCHAR* pMem = (TCHAR*)GlobalLock(pmedium->hGlobal); wcscpy_s(pMem, text.GetLength() + 1, (LPCTSTR)text); GlobalUnlock(pmedium->hGlobal); } pmedium->pUnkForRelease = nullptr; return S_OK; } else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_HDROP)) { int nLength = 0; for (int i = 0; i < m_gitPaths.GetCount(); ++i) { if (m_gitPaths[i].m_Action & (CTGitPath::LOGACTIONS_MISSING | CTGitPath::LOGACTIONS_DELETED) || m_gitPaths[i].IsDirectory()) continue; nLength += g_Git.CombinePath(m_gitPaths[i]).GetLength(); nLength += 1; // '\0' separator } int nBufferSize = sizeof(DROPFILES) + (nLength + 1) * sizeof(TCHAR); auto pBuffer = std::make_unique<char[]>(nBufferSize); SecureZeroMemory(pBuffer.get(), nBufferSize); DROPFILES* df = (DROPFILES*)pBuffer.get(); df->pFiles = sizeof(DROPFILES); df->fWide = 1; TCHAR* pFilenames = (TCHAR*)(pBuffer.get() + sizeof(DROPFILES)); TCHAR* pCurrentFilename = pFilenames; for (int i = 0; i < m_gitPaths.GetCount(); ++i) { if (m_gitPaths[i].m_Action & (CTGitPath::LOGACTIONS_MISSING | CTGitPath::LOGACTIONS_DELETED) || m_gitPaths[i].IsDirectory()) continue; CString str = g_Git.CombinePath(m_gitPaths[i]); wcscpy_s(pCurrentFilename, str.GetLength() + 1, (LPCWSTR)str); pCurrentFilename += str.GetLength(); *pCurrentFilename = '\0'; // separator between file names pCurrentFilename++; } *pCurrentFilename = '\0'; // terminate array pmedium->tymed = TYMED_HGLOBAL; pmedium->hGlobal = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, nBufferSize); if (pmedium->hGlobal) { LPVOID pMem = ::GlobalLock(pmedium->hGlobal); if (pMem) memcpy(pMem, pBuffer.get(), nBufferSize); GlobalUnlock(pmedium->hGlobal); } pmedium->pUnkForRelease = nullptr; return S_OK; } else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_FILE_ATTRIBUTES_ARRAY)) { int nBufferSize = sizeof(FILE_ATTRIBUTES_ARRAY) + m_gitPaths.GetCount() * sizeof(DWORD); auto pBuffer = std::make_unique<char[]>(nBufferSize); SecureZeroMemory(pBuffer.get(), nBufferSize); FILE_ATTRIBUTES_ARRAY* cf = (FILE_ATTRIBUTES_ARRAY*)pBuffer.get(); cf->cItems = m_gitPaths.GetCount(); cf->dwProductFileAttributes = DWORD_MAX; cf->dwSumFileAttributes = 0; for (int i = 0; i < m_gitPaths.GetCount(); ++i) { DWORD fileattribs = FILE_ATTRIBUTE_NORMAL; cf->rgdwFileAttributes[i] = fileattribs; cf->dwProductFileAttributes &= fileattribs; cf->dwSumFileAttributes |= fileattribs; } pmedium->tymed = TYMED_HGLOBAL; pmedium->hGlobal = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, nBufferSize); if (pmedium->hGlobal) { LPVOID pMem = ::GlobalLock(pmedium->hGlobal); if (pMem) memcpy(pMem, pBuffer.get(), nBufferSize); GlobalUnlock(pmedium->hGlobal); } pmedium->pUnkForRelease = nullptr; return S_OK; } for (size_t i = 0; i < m_vecFormatEtc.size(); ++i) { if ((pformatetcIn->tymed == m_vecFormatEtc[i]->tymed) && (pformatetcIn->dwAspect == m_vecFormatEtc[i]->dwAspect) && (pformatetcIn->cfFormat == m_vecFormatEtc[i]->cfFormat)) { CopyMedium(pmedium, m_vecStgMedium[i], m_vecFormatEtc[i]); return S_OK; } } return DV_E_FORMATETC; }