1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_shell.hxx"
26 #include "internal/config.hxx"
27 #include "internal/global.hxx"
28 
29 #ifndef PROPSEETS_HXX_INCLUDED
30 #include "internal/propsheets.hxx"
31 #endif
32 #include "internal/utilities.hxx"
33 #include "internal/resource.h"
34 #include "listviewbuilder.hxx"
35 
36 #if defined _MSC_VER
37 #pragma warning(push, 1)
38 #endif
39 #include <shellapi.h>
40 #if defined _MSC_VER
41 #pragma warning(pop)
42 #endif
43 
44 #include <string>
45 #include <vector>
46 #include <utility>
47 #include <strsafe.h>
48 
49 
50 /*---------------------------------------------
51 	INFO - INFO - INFO - INFO - INFO - INFO
52 
53 	See MSDN "Using Windows XP Visual Styles"
54 	for hints how to enable the new common
55 	control library for our property sheet.
56 
57 	INFO - INFO - INFO - INFO - INFO - INFO
58 ----------------------------------------------*/
59 
60 //-----------------------------
61 //
62 //-----------------------------
63 
64 CPropertySheet::CPropertySheet(long RefCnt) :
65 	m_RefCnt(RefCnt)
66 {
67     OutputDebugStringFormat("CPropertySheet::CTor [%d], [%d]", m_RefCnt, g_DllRefCnt );
68 	InterlockedIncrement(&g_DllRefCnt);
69 }
70 
71 //-----------------------------
72 //
73 //-----------------------------
74 
75 CPropertySheet::~CPropertySheet()
76 {
77     OutputDebugStringFormat("CPropertySheet::DTor [%d], [%d]", m_RefCnt, g_DllRefCnt );
78 	InterlockedDecrement(&g_DllRefCnt);
79 }
80 
81 //-----------------------------
82 // IUnknown methods
83 //-----------------------------
84 
85 HRESULT STDMETHODCALLTYPE CPropertySheet::QueryInterface(
86 	REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject)
87 {
88 	*ppvObject = 0;
89 
90 	IUnknown* pUnk = 0;
91 	if (IID_IUnknown == riid || IID_IShellExtInit == riid)
92 	{
93 		pUnk = static_cast<IShellExtInit*>(this);
94 		pUnk->AddRef();
95 		*ppvObject = pUnk;
96 		return S_OK;
97 	}
98 	else if (IID_IShellPropSheetExt == riid)
99 	{
100 		pUnk = static_cast<IShellPropSheetExt*>(this);
101 		pUnk->AddRef();
102 		*ppvObject = pUnk;
103 		return S_OK;
104 	}
105 
106 	return E_NOINTERFACE;
107 }
108 
109 //-----------------------------
110 //
111 //-----------------------------
112 
113 ULONG STDMETHODCALLTYPE CPropertySheet::AddRef(void)
114 {
115     OutputDebugStringFormat("CPropertySheet::AddRef [%d]", m_RefCnt );
116 	return InterlockedIncrement(&m_RefCnt);
117 }
118 
119 //-----------------------------
120 //
121 //-----------------------------
122 
123 ULONG STDMETHODCALLTYPE CPropertySheet::Release(void)
124 {
125     OutputDebugStringFormat("CPropertySheet::Release [%d]", m_RefCnt );
126 	long refcnt = InterlockedDecrement(&m_RefCnt);
127 
128 	if (0 == refcnt)
129 		delete this;
130 
131 	return refcnt;
132 }
133 
134 //-----------------------------
135 // IShellExtInit
136 //-----------------------------
137 
138 HRESULT STDMETHODCALLTYPE CPropertySheet::Initialize(
139 	LPCITEMIDLIST /*pidlFolder*/, LPDATAOBJECT lpdobj, HKEY /*hkeyProgID*/)
140 {
141 	InitCommonControls();
142 
143 	STGMEDIUM medium;
144 	FORMATETC fe = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
145 
146 	HRESULT hr = lpdobj->GetData(&fe, &medium);
147 
148 	// save the file name
149     if (SUCCEEDED(hr) &&
150 		(1 == DragQueryFileA(
151 			reinterpret_cast<HDROP>(medium.hGlobal),
152 			0xFFFFFFFF,
153 			NULL,
154 			0)))
155 	{
156 	    UINT size = DragQueryFile( reinterpret_cast<HDROP>(medium.hGlobal), 0, 0, 0 );
157 	    if ( size != 0 )
158 	    {
159 	        TCHAR * buffer = new TCHAR[ size + 1 ];
160 	        UINT result_size = DragQueryFile( reinterpret_cast<HDROP>(medium.hGlobal),
161 	                                          0, buffer, size + 1 );
162 	        if ( result_size != 0 )
163 	        {
164 	            std::wstring fname = getShortPathName( buffer );
165 	            std::string fnameA = WStringToString( fname );
166 	            ZeroMemory( m_szFileName, sizeof( m_szFileName ) );
167 	            strncpy( m_szFileName, fnameA.c_str(), ( sizeof( m_szFileName ) - 1 ) );
168 	            hr = S_OK;
169 	        }
170 	        else
171 	            hr = E_INVALIDARG;
172             delete [] buffer;
173 	    }
174 	    else
175 	        hr = E_INVALIDARG;
176     }
177     else
178         hr = E_INVALIDARG;
179 
180 	ReleaseStgMedium(&medium);
181 
182     return hr;
183 }
184 
185 //-----------------------------
186 // IShellPropSheetExt
187 //-----------------------------
188 
189 HRESULT STDMETHODCALLTYPE CPropertySheet::AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
190 {
191     // Get OS version (we don't need the summary page on Windows Vista or later)
192     OSVERSIONINFO sInfoOS;
193 
194     ZeroMemory( &sInfoOS, sizeof(OSVERSIONINFO) );
195     sInfoOS.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
196     GetVersionEx( &sInfoOS );
197     bool bIsVistaOrLater = (sInfoOS.dwMajorVersion >= 6);
198 
199 	std::wstring proppage_header;
200 
201 	PROPSHEETPAGE psp;
202 	ZeroMemory(&psp, sizeof(PROPSHEETPAGEA));
203 
204 	// add the summary property page
205     psp.dwSize      = sizeof(PROPSHEETPAGE);
206     psp.dwFlags     = PSP_DEFAULT | PSP_USETITLE | PSP_USECALLBACK;
207     psp.hInstance   = GetModuleHandle(MODULE_NAME);
208     psp.lParam      = reinterpret_cast<LPARAM>(this);
209 	psp.pfnCallback = reinterpret_cast<LPFNPSPCALLBACK>(CPropertySheet::PropPageSummaryCallback);
210 
211     HPROPSHEETPAGE hPage = NULL;
212 
213 	if ( !bIsVistaOrLater )
214 	{
215 	    proppage_header = GetResString(IDS_PROPPAGE_SUMMARY_TITLE);
216 
217         psp.pszTemplate = MAKEINTRESOURCE(IDD_PROPPAGE_SUMMARY);
218         psp.pszTitle    = proppage_header.c_str();
219         psp.pfnDlgProc  = reinterpret_cast<DLGPROC>(CPropertySheet::PropPageSummaryProc);
220 
221         hPage = CreatePropertySheetPage(&psp);
222 
223         // keep this instance alive, will be released when the
224         // the page is about to be destroyed in the callback function
225 
226         if (hPage)
227         {
228             if (lpfnAddPage(hPage, lParam))
229                 AddRef();
230             else
231                 DestroyPropertySheetPage(hPage);
232         }
233 	}
234 
235 	// add the statistics property page
236 	proppage_header = GetResString(IDS_PROPPAGE_STATISTICS_TITLE);
237 
238     psp.pszTemplate = MAKEINTRESOURCE(IDD_PROPPAGE_STATISTICS);
239     psp.pszTitle    = proppage_header.c_str();
240     psp.pfnDlgProc  = reinterpret_cast<DLGPROC>(CPropertySheet::PropPageStatisticsProc);
241 
242     hPage = CreatePropertySheetPage(&psp);
243 
244     if (hPage)
245 	{
246 		if (lpfnAddPage(hPage, lParam))
247 			AddRef();
248 		else
249 			DestroyPropertySheetPage(hPage);
250 	}
251 
252 	// always return success else
253 	// no property sheet will be
254 	// displayed at all
255 	return NOERROR;
256 }
257 
258 //-----------------------------
259 //
260 //-----------------------------
261 
262 HRESULT STDMETHODCALLTYPE CPropertySheet::ReplacePage(
263 	UINT /*uPageID*/, LPFNADDPROPSHEETPAGE /*lpfnReplaceWith*/, LPARAM /*lParam*/)
264 {
265 	return E_NOTIMPL;
266 }
267 
268 //-----------------------------
269 //
270 //-----------------------------
271 
272 UINT CALLBACK CPropertySheet::PropPageSummaryCallback(
273 	HWND /*hwnd*/, UINT uMsg, LPPROPSHEETPAGE ppsp)
274 {
275 	CPropertySheet* pImpl =
276 		reinterpret_cast<CPropertySheet*>(ppsp->lParam);
277 
278 	// release this instance, acquired
279 	// in the AddPages method
280 	if (PSPCB_RELEASE == uMsg)
281 	{
282 		pImpl->Release();
283 	}
284 
285 	return TRUE;
286 }
287 
288 
289 //-----------------------------
290 //
291 //-----------------------------
292 
293 BOOL CALLBACK CPropertySheet::PropPageSummaryProc(HWND hwnd, UINT uiMsg, WPARAM /*wParam*/, LPARAM lParam)
294 {
295 	switch (uiMsg)
296 	{
297 	case WM_INITDIALOG:
298 		{
299 			LPPROPSHEETPAGE psp = reinterpret_cast<LPPROPSHEETPAGE>(lParam);
300 			CPropertySheet* pImpl = reinterpret_cast<CPropertySheet*>(psp->lParam);
301 			pImpl->InitPropPageSummary(hwnd, psp);
302 			return TRUE;
303 		}
304 	}
305 
306 	return FALSE;
307 }
308 
309 //-----------------------------
310 //
311 //-----------------------------
312 
313 BOOL CALLBACK CPropertySheet::PropPageStatisticsProc(HWND hwnd, UINT uiMsg, WPARAM /*wParam*/, LPARAM lParam)
314 {
315 	switch (uiMsg)
316 	{
317 	case WM_INITDIALOG:
318 		{
319 			LPPROPSHEETPAGE psp = reinterpret_cast<LPPROPSHEETPAGE>(lParam);
320 			CPropertySheet* pImpl = reinterpret_cast<CPropertySheet*>(psp->lParam);
321 			pImpl->InitPropPageStatistics(hwnd, psp);
322 			return TRUE;
323 		}
324 	}
325 
326 	return FALSE;
327 }
328 
329 //##################################
330 void CPropertySheet::InitPropPageSummary(HWND hwnd, LPPROPSHEETPAGE /*lppsp*/)
331 {
332     try
333     {
334         CMetaInfoReader metaInfo(m_szFileName);
335 
336         SetWindowText(GetDlgItem(hwnd,IDC_TITLE),    metaInfo.getTagData( META_INFO_TITLE ).c_str() );
337         SetWindowText(GetDlgItem(hwnd,IDC_AUTHOR),   metaInfo.getTagData( META_INFO_AUTHOR ).c_str() );
338         SetWindowText(GetDlgItem(hwnd,IDC_SUBJECT),  metaInfo.getTagData( META_INFO_SUBJECT ).c_str() );
339         SetWindowText(GetDlgItem(hwnd,IDC_KEYWORDS), metaInfo.getTagData( META_INFO_KEYWORDS ).c_str() );
340 
341         // comments read from meta.xml use "\n" for return, but this will not displayable in Edit control, add
342         // "\r" before "\n" to form "\r\n" in order to display return in Edit control.
343         std::wstring tempStr = metaInfo.getTagData( META_INFO_DESCRIPTION ).c_str();
344         std::wstring::size_type itor = tempStr.find ( L"\n" , 0 );
345         while (itor != std::wstring::npos)
346         {
347             tempStr.insert(itor, L"\r");
348             itor = tempStr.find(L"\n", itor + 2);
349         }
350         SetWindowText(GetDlgItem(hwnd,IDC_COMMENTS), tempStr.c_str());
351     }
352     catch (const std::exception&)
353     {
354     }
355 }
356 
357 //---------------------------------
358 /**
359 */
360 void CPropertySheet::InitPropPageStatistics(HWND hwnd, LPPROPSHEETPAGE /*lppsp*/)
361 {
362     try
363     {
364         CMetaInfoReader metaInfo(m_szFileName);
365 
366         document_statistic_reader_ptr doc_stat_reader = create_document_statistic_reader(m_szFileName, &metaInfo);
367 
368         statistic_group_list_t sgl;
369         doc_stat_reader->read(&sgl);
370 
371         list_view_builder_ptr lv_builder = create_list_view_builder(
372             GetDlgItem(hwnd, IDC_STATISTICSLIST),
373             GetResString(IDS_PROPERTY),
374             GetResString(IDS_PROPERTY_VALUE));
375 
376         lv_builder->build(sgl);
377     }
378     catch (const std::exception&)
379     {
380     }
381 }
382