//____________________________________________________________________________ // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1995 - 1996. // // File: psx.cxx // // Contents: // // Classes: // // Functions: // // History: 2/13/1996 RaviR Created // //____________________________________________________________________________ #include "..\pch\headers.hxx" #pragma hdrstop #include "dbg.h" #include "macros.h" #include "resource.h" //#include "jobidl.hxx" #include "util.hxx" // // extern // extern HINSTANCE g_hInstance; #define HINST_THISDLL g_hInstance // // Local constants // TCHAR const FAR c_szNULL[] = TEXT(""); TCHAR const FAR c_szStubWindowClass[] = TEXT("JobPropWnd"); const size_t MAX_FILE_PROP_PAGES = 32; class CHkey { public: CHkey(void) : _h(NULL) {} CHkey(HKEY h) : _h(h) {} virtual ~CHkey() { if (_h != NULL) RegCloseKey(_h); } operator HKEY() { return _h; } HKEY * operator &() { return &_h; } HKEY Attach(HKEY h) { HKEY hTemp = _h; _h = h; return hTemp; } HKEY Detach(void) { HKEY hTemp = _h; _h = NULL; return hTemp; } void Close(void) { if (_h) RegCloseKey(_h); _h = NULL; } protected: HKEY _h; }; ///////////////////////////////////////////////////////////////////////////// // // Display properties // class CJFPropertyThreadData { public: static CJFPropertyThreadData * Create(LPDATAOBJECT pdtobj, LPTSTR pszCaption); ~CJFPropertyThreadData() { if (_pdtobj != NULL) { _pdtobj->Release(); } delete _pszCaption; } LPDATAOBJECT GetDataObject() { return _pdtobj; } LPTSTR GetCaption() { return _pszCaption; } private: CJFPropertyThreadData() : _pdtobj(NULL), _pszCaption(NULL) {} LPDATAOBJECT _pdtobj; LPTSTR _pszCaption; }; CJFPropertyThreadData * CJFPropertyThreadData::Create( LPDATAOBJECT pdtobj, LPTSTR pszCaption) { CJFPropertyThreadData * pData = new CJFPropertyThreadData; if (pData == NULL) { return NULL; } pData->_pszCaption = NewDupString(pszCaption); if (pData->_pszCaption == NULL) { delete pData; return NULL; } pData->_pdtobj = pdtobj; pData->_pdtobj->AddRef(); return pData; } DWORD __stdcall JFPropertiesThread( LPVOID pvData) { CJFPropertyThreadData *pData = (CJFPropertyThreadData *)pvData; HRESULT hrOle = OleInitialize(NULL); __try { if (SUCCEEDED(hrOle)) { JFOpenPropSheet(pData->GetDataObject(), pData->GetCaption()); } } __finally { delete pData; if (SUCCEEDED(hrOle)) { OleUninitialize(); } ExitThread(0); } return 0; } //____________________________________________________________________________ // // Member: CJobsCM::_DisplayJobProperties // // Arguments: [hwnd] -- IN // [pwszJob] -- IN // // Returns: HRESULT. // // History: 1/11/1996 RaviR Created // //____________________________________________________________________________ HRESULT CJobsCM::_DisplayJobProperties( HWND hwnd, CJobID & jid) { TRACE_FUNCTION(DisplayJobProperties); Win4Assert(m_cidl == 1); HRESULT hr = S_OK; LPDATAOBJECT pdtobj = NULL; do { hr = JFGetDataObject(hwnd, m_pszFolderPath, m_cidl, (LPCITEMIDLIST *)m_apidl, (LPVOID *)&pdtobj); CHECK_HRESULT(hr); BREAK_ON_FAIL(hr); CJFPropertyThreadData * pData = NULL; TCHAR tcName[MAX_PATH]; lstrcpy(tcName, ((PJOBID)m_apidl[0])->GetName()); LPTSTR pszExt = PathFindExtension(tcName); if (pszExt) { *pszExt = TEXT('\0'); } pData = CJFPropertyThreadData::Create(pdtobj, tcName); if (pData == NULL) { hr = E_OUTOFMEMORY; CHECK_HRESULT(hr); break; } HANDLE hThread; DWORD idThread; hThread = CreateThread(NULL, 0, JFPropertiesThread, pData, 0, &idThread); if (hThread) { CloseHandle(hThread); } else { delete pData; } } while (0); if (pdtobj != NULL) { pdtobj->Release(); } return hr; } //----------------------------------------------------------------------------- // // PSXA // // An array of IShellPropSheetExt interface pointers // //----------------------------------------------------------------------------- struct PSXA { static PSXA * Alloc(UINT count); static void Delete(PSXA * pPsxa); UINT count; IShellPropSheetExt *intfc[1]; }; PSXA * PSXA::Alloc(UINT count) { UINT cb = sizeof(UINT) + sizeof(IShellPropSheetExt *) * count; PSXA * pPsxa = (PSXA *)new BYTE[cb]; if (pPsxa != NULL) { ZeroMemory(pPsxa, cb); } return pPsxa; } void PSXA::Delete(PSXA * pPsxa) { while (pPsxa->count--) { if (pPsxa->intfc[pPsxa->count] != NULL) { pPsxa->intfc[pPsxa->count]->Release(); } } delete [] ((LPBYTE)pPsxa); } HRESULT GetHkeyForJobObject( HKEY * phkey) { // // Get ProgID for .job files. Get an HKEY for this ProgID. // LRESULT lr = ERROR_SUCCESS; do { HKEY hkey = NULL; lr = RegOpenKeyEx(HKEY_CLASSES_ROOT, TSZ_DOTJOB, 0, KEY_QUERY_VALUE, &hkey); if (lr != ERROR_SUCCESS) { CHECK_LASTERROR(lr); break; } DWORD dwType = 0; TCHAR buff[200]; ULONG cb = sizeof(buff); lr = RegQueryValueEx(hkey, NULL, NULL, &dwType, (LPBYTE)buff, &cb); RegCloseKey(hkey); if (lr != ERROR_SUCCESS) { CHECK_LASTERROR(lr); break; } hkey = NULL; // reset lr = RegOpenKeyEx(HKEY_CLASSES_ROOT, buff, 0, KEY_READ, &hkey); if (lr != ERROR_SUCCESS) { CHECK_LASTERROR(lr); break; } *phkey = hkey; } while (0); return HRESULT_FROM_WIN32(lr); } LPTSTR I_GetWord( LPTSTR psz) { static TCHAR * s_psz = NULL; if (psz != NULL) { s_psz = psz; } psz = s_psz; // skip the space or comma characters while (*psz == TEXT(' ') || *psz == TEXT(',')) { ++psz; } s_psz = psz; while (*s_psz != TEXT('\0')) { if (*s_psz == TEXT(' ') || *s_psz == TEXT(',')) { *s_psz = TEXT('\0'); ++s_psz; break; } ++s_psz; } return psz; } inline HRESULT I_CLSIDFromString( LPTSTR pszClsid, LPCLSID pclsid) { #ifdef UNICODE return CLSIDFromString(pszClsid, pclsid); #else WCHAR wBuff[64]; HRESULT hr = AnsiToUnicode(wBuff, pszClsid, 64); if (FAILED(hr)) { return hr; } return CLSIDFromString(wBuff, pclsid); #endif } inline BOOL I_IsPresent( CLSID aclsid[], UINT count) { for (UINT i=0; i < count; i++) { if (IsEqualCLSID(aclsid[i], aclsid[count])) { return TRUE; } } return FALSE; } HRESULT GetPropSheetExtArray( HKEY hkeyIn, PSXA ** ppPsxa) { *ppPsxa = NULL; // init // // From HKEY determine the clsids. Bind to each clsid // and get the IShellPropSheetExt interface ptrs. // HRESULT hr = S_OK; LRESULT lr = ERROR_SUCCESS; CHkey hkey; UINT count = 0; CLSID aclsid[20]; TCHAR szClsid[64]; ULONG SIZEOF_SZCLSID = sizeof(szClsid); do { TCHAR buff[MAX_PATH * 2]; ULONG SIZEOF_BUFF = sizeof(buff); ULONG cb = SIZEOF_BUFF; lr = RegOpenKeyEx(hkeyIn, STRREG_SHEX_PROPSHEET, 0, KEY_READ, &hkey); BREAK_ON_ERROR(lr); lr = RegQueryValueEx(hkey, NULL, NULL, NULL, (LPBYTE)buff, &cb); CHECK_LASTERROR(lr); if (lr == ERROR_SUCCESS & cb > 0) { LPTSTR psz = I_GetWord(buff); CHkey hkeyTemp = NULL; while (*psz != TEXT('\0')) { hkeyTemp.Close(); lr = RegOpenKeyEx(hkey, psz, 0, KEY_READ, &hkeyTemp); BREAK_ON_ERROR(lr); cb = SIZEOF_SZCLSID; lr = RegQueryValueEx(hkeyTemp, NULL, NULL, NULL, (LPBYTE)szClsid, &cb); BREAK_ON_ERROR(lr); hr = I_CLSIDFromString(szClsid, &aclsid[count]); BREAK_ON_FAIL(hr); ++count; psz = I_GetWord(NULL); } } for (int i=0; ; i++) { cb = SIZEOF_SZCLSID; lr = RegEnumKeyEx(hkey, i, szClsid, &cb, NULL, NULL, NULL, NULL); BREAK_ON_ERROR(lr); // Is it a classid? hr = I_CLSIDFromString(szClsid, &aclsid[count]); if (FAILED(hr)) // no - see if the value is a classid { CHkey hkey3; lr = RegOpenKeyEx(hkey, szClsid, 0, KEY_READ, &hkey3); if (lr == ERROR_SUCCESS) { cb = SIZEOF_SZCLSID; lr = RegQueryValueEx(hkey3, NULL, NULL, NULL, (LPBYTE)szClsid, &cb); if (lr == ERROR_SUCCESS) { hr = I_CLSIDFromString(szClsid, &aclsid[count]); } } } if (SUCCEEDED(hr)) { // is it already present ? if (I_IsPresent(aclsid, count) == FALSE) { ++count; } } } } while (0); if (count <= 0) { DEBUG_OUT((DEB_USER1, "No pages to display.\n")); return E_FAIL; } do { // // Now create the IShellPropSheetExt interface ptrs. // PSXA * pPsxa = PSXA::Alloc(count); if (pPsxa == NULL) { hr = E_OUTOFMEMORY; CHECK_HRESULT(hr); break; } for (UINT k=0; k < count; k++) { hr = CoCreateInstance(aclsid[k], NULL, CLSCTX_ALL, IID_IShellPropSheetExt, (void **)&pPsxa->intfc[pPsxa->count]); CHECK_HRESULT(hr); if (SUCCEEDED(hr)) { ++pPsxa->count; } } if (pPsxa->count > 0) { *ppPsxa = pPsxa; hr = S_OK; } else { hr = E_FAIL; } } while (0); return hr; } // // This function is a callback function from property sheet page extensions. // BOOL CALLBACK I_AddPropSheetPage(HPROPSHEETPAGE hpage, LPARAM lParam) { PROPSHEETHEADER * ppsh = (PROPSHEETHEADER *)lParam; if (ppsh->nPages < MAX_FILE_PROP_PAGES) { ppsh->phpage[ppsh->nPages++] = hpage; return TRUE; } return FALSE; } LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { switch(iMessage) { case WM_CREATE: break; case WM_DESTROY: break; case WM_NOTIFY: break; // case STUBM_SETDATA: // SetWindowLongPtr(hWnd, 0, wParam); // break; // // case STUBM_GETDATA: // return GetWindowLongPtr(hWnd, 0); default: return DefWindowProc(hWnd, iMessage, wParam, lParam) ; break; } return 0L; } HWND I_CreateStubWindow(void) { WNDCLASS wndclass; if (!GetClassInfo(HINST_THISDLL, c_szStubWindowClass, &wndclass)) { wndclass.style = 0; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = HINST_THISDLL; wndclass.hIcon = NULL; wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = c_szStubWindowClass; if (!RegisterClass(&wndclass)) return NULL; } return CreateWindowEx(WS_EX_TOOLWINDOW, c_szStubWindowClass, c_szNULL, WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL, HINST_THISDLL, NULL); } HRESULT JFOpenPropSheet( LPDATAOBJECT pdtobj, LPTSTR pszCaption) { HRESULT hr = S_OK; CHkey hkey; PSXA * pPsxa = NULL; PROPSHEETHEADER psh; HPROPSHEETPAGE ahpage[MAX_FILE_PROP_PAGES]; do { // // Get HKEY for the .job class object // hr = GetHkeyForJobObject(&hkey); BREAK_ON_FAIL(hr); // // Get the IShellPropSheetExt interface ptrs for classes wishing to // add pages. // hr = GetPropSheetExtArray(hkey, &pPsxa); BREAK_ON_FAIL(hr); // For each IShellPropSheetExt interface ptr initialize(IShellExtInit) // and call the AddPages. psh.dwSize = sizeof(psh); psh.dwFlags = PSH_PROPTITLE; psh.hwndParent = I_CreateStubWindow(); psh.hInstance = g_hInstance; psh.hIcon = NULL; psh.pszCaption = pszCaption; //psh.pszCaption = MAKEINTRESOURCE(IDS_JOB_PSH_CAPTION); psh.nPages = 0; // incremented in callback psh.nStartPage = 0; psh.phpage = ahpage; IShellExtInit * pShExtInit = NULL; for (UINT n=0; n < pPsxa->count; n++) { hr = pPsxa->intfc[n]->QueryInterface(IID_IShellExtInit, (void **)&pShExtInit); CHECK_HRESULT(hr); if (SUCCEEDED(hr)) { hr = pShExtInit->Initialize(NULL, pdtobj, hkey); CHECK_HRESULT(hr); pShExtInit->Release(); if (SUCCEEDED(hr)) { hr = pPsxa->intfc[n]->AddPages(I_AddPropSheetPage, (LPARAM)&psh); CHECK_HRESULT(hr); } } } PSXA::Delete(pPsxa); // create a modeless property sheet. // Open the property sheet, only if we have some pages. if (psh.nPages > 0) { _try { hr = E_FAIL; if (PropertySheet(&psh) >= 0) // IDOK or IDCANCEL (< 0 is error) { hr = S_OK; } DEBUG_OUT((DEB_USER1, "PropertySheet returned.\n")); } _except(EXCEPTION_EXECUTE_HANDLER) { hr = E_FAIL; CHECK_HRESULT(hr); } } } while (0); if (psh.hwndParent) { DestroyWindow(psh.hwndParent); } return hr; }