|
1
|
1 // Windows Template Library - WTL version 10.0
|
|
|
2 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.
|
|
|
3 //
|
|
|
4 // This file is a part of the Windows Template Library.
|
|
|
5 // The use and distribution terms for this software are covered by the
|
|
|
6 // Microsoft Public License (http://opensource.org/licenses/MS-PL)
|
|
|
7 // which can be found in the file MS-PL.txt at the root folder.
|
|
|
8
|
|
|
9 #ifndef __ATLMISC_H__
|
|
|
10 #define __ATLMISC_H__
|
|
|
11
|
|
|
12 #pragma once
|
|
|
13
|
|
|
14 #ifndef __ATLAPP_H__
|
|
|
15 #error atlmisc.h requires atlapp.h to be included first
|
|
|
16 #endif
|
|
|
17
|
|
|
18 #ifndef _WTL_NO_COMPATIBILITY_INCLUDES
|
|
|
19 #include <atlstr.h>
|
|
|
20 #include <atltypes.h>
|
|
|
21 #endif // _WTL_NO_COMPATIBILITY_INCLUDES
|
|
|
22
|
|
|
23
|
|
|
24 ///////////////////////////////////////////////////////////////////////////////
|
|
|
25 // Classes in this file:
|
|
|
26 //
|
|
|
27 // CRecentDocumentListBase<T, t_cchItemLen, t_nFirstID, t_nLastID>
|
|
|
28 // CRecentDocumentList
|
|
|
29 // CFindFile
|
|
|
30 // CRegProperty
|
|
|
31 // CRegPropertyImpl<T>
|
|
|
32 //
|
|
|
33 // Global functions:
|
|
|
34 // AtlGetStockPen()
|
|
|
35 // AtlGetStockBrush()
|
|
|
36 // AtlGetStockFont()
|
|
|
37 // AtlGetStockPalette()
|
|
|
38 //
|
|
|
39 // AtlCompactPath()
|
|
|
40
|
|
|
41
|
|
|
42 namespace WTL
|
|
|
43 {
|
|
|
44
|
|
|
45 ///////////////////////////////////////////////////////////////////////////////
|
|
|
46 // CSize scalar operators
|
|
|
47
|
|
|
48 #if !defined(_WTL_NO_SIZE_SCALAR) && defined(__ATLTYPES_H__)
|
|
|
49
|
|
|
50 template <class Num>
|
|
|
51 inline CSize operator *(SIZE s, Num n)
|
|
|
52 {
|
|
|
53 return CSize((int)(s.cx * n), (int)(s.cy * n));
|
|
|
54 };
|
|
|
55
|
|
|
56 template <class Num>
|
|
|
57 inline void operator *=(SIZE & s, Num n)
|
|
|
58 {
|
|
|
59 s = s * n;
|
|
|
60 };
|
|
|
61
|
|
|
62 template <class Num>
|
|
|
63 inline CSize operator /(SIZE s, Num n)
|
|
|
64 {
|
|
|
65 return CSize((int)(s.cx / n), (int)(s.cy / n));
|
|
|
66 };
|
|
|
67
|
|
|
68 template <class Num>
|
|
|
69 inline void operator /=(SIZE & s, Num n)
|
|
|
70 {
|
|
|
71 s = s / n;
|
|
|
72 };
|
|
|
73
|
|
|
74 #endif // !defined(_WTL_NO_SIZE_SCALAR) && defined(__ATLTYPES_H__)
|
|
|
75
|
|
|
76
|
|
|
77 ///////////////////////////////////////////////////////////////////////////////
|
|
|
78 // CRecentDocumentList - MRU List Support
|
|
|
79
|
|
|
80 #ifndef _WTL_MRUEMPTY_TEXT
|
|
|
81 #define _WTL_MRUEMPTY_TEXT _T("(empty)")
|
|
|
82 #endif
|
|
|
83
|
|
|
84 // forward declaration
|
|
|
85 inline bool AtlCompactPath(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen);
|
|
|
86
|
|
|
87 template <class T, int t_cchItemLen = MAX_PATH, int t_nFirstID = ID_FILE_MRU_FIRST, int t_nLastID = ID_FILE_MRU_LAST>
|
|
|
88 class CRecentDocumentListBase
|
|
|
89 {
|
|
|
90 public:
|
|
|
91 // Declarations
|
|
|
92 struct _DocEntry
|
|
|
93 {
|
|
|
94 TCHAR szDocName[t_cchItemLen];
|
|
|
95 bool operator ==(const _DocEntry& de) const
|
|
|
96 { return (lstrcmpi(szDocName, de.szDocName) == 0); }
|
|
|
97 };
|
|
|
98
|
|
|
99 enum
|
|
|
100 {
|
|
|
101 m_nMaxEntries_Min = 2,
|
|
|
102 m_nMaxEntries_Max = t_nLastID - t_nFirstID + 1,
|
|
|
103 m_cchMaxItemLen_Min = 6,
|
|
|
104 m_cchMaxItemLen_Max = t_cchItemLen,
|
|
|
105 m_cchItemNameLen = 11
|
|
|
106 };
|
|
|
107
|
|
|
108 // Data members
|
|
|
109 ATL::CSimpleArray<_DocEntry> m_arrDocs;
|
|
|
110 int m_nMaxEntries; // default is 4
|
|
|
111 HMENU m_hMenu;
|
|
|
112
|
|
|
113 TCHAR m_szNoEntries[t_cchItemLen];
|
|
|
114
|
|
|
115 int m_cchMaxItemLen;
|
|
|
116
|
|
|
117 // Constructor
|
|
|
118 CRecentDocumentListBase() : m_nMaxEntries(4), m_hMenu(NULL), m_cchMaxItemLen(-1)
|
|
|
119 {
|
|
|
120 // These ASSERTs verify values of the template arguments
|
|
|
121 ATLASSERT(t_cchItemLen > m_cchMaxItemLen_Min);
|
|
|
122 ATLASSERT(m_nMaxEntries_Max > m_nMaxEntries_Min);
|
|
|
123 }
|
|
|
124
|
|
|
125 // Attributes
|
|
|
126 HMENU GetMenuHandle() const
|
|
|
127 {
|
|
|
128 return m_hMenu;
|
|
|
129 }
|
|
|
130
|
|
|
131 void SetMenuHandle(HMENU hMenu)
|
|
|
132 {
|
|
|
133 ATLASSERT((hMenu == NULL) || ::IsMenu(hMenu));
|
|
|
134 m_hMenu = hMenu;
|
|
|
135 if((m_hMenu == NULL) || (::GetMenuString(m_hMenu, t_nFirstID, m_szNoEntries, t_cchItemLen, MF_BYCOMMAND) == 0))
|
|
|
136 {
|
|
|
137 T* pT = static_cast<T*>(this);
|
|
|
138 (void)pT; // avoid level 4 warning
|
|
|
139 ATL::Checked::tcsncpy_s(m_szNoEntries, _countof(m_szNoEntries), pT->GetMRUEmptyText(), _TRUNCATE);
|
|
|
140 }
|
|
|
141 }
|
|
|
142
|
|
|
143 int GetMaxEntries() const
|
|
|
144 {
|
|
|
145 return m_nMaxEntries;
|
|
|
146 }
|
|
|
147
|
|
|
148 void SetMaxEntries(int nMaxEntries)
|
|
|
149 {
|
|
|
150 ATLASSERT((nMaxEntries >= m_nMaxEntries_Min) && (nMaxEntries <= m_nMaxEntries_Max));
|
|
|
151 if(nMaxEntries < m_nMaxEntries_Min)
|
|
|
152 nMaxEntries = m_nMaxEntries_Min;
|
|
|
153 else if(nMaxEntries > m_nMaxEntries_Max)
|
|
|
154 nMaxEntries = m_nMaxEntries_Max;
|
|
|
155 m_nMaxEntries = nMaxEntries;
|
|
|
156 }
|
|
|
157
|
|
|
158 int GetMaxItemLength() const
|
|
|
159 {
|
|
|
160 return m_cchMaxItemLen;
|
|
|
161 }
|
|
|
162
|
|
|
163 void SetMaxItemLength(int cchMaxLen)
|
|
|
164 {
|
|
|
165 ATLASSERT(((cchMaxLen >= m_cchMaxItemLen_Min) && (cchMaxLen <= m_cchMaxItemLen_Max)) || (cchMaxLen == -1));
|
|
|
166 if(cchMaxLen != -1)
|
|
|
167 {
|
|
|
168 if(cchMaxLen < m_cchMaxItemLen_Min)
|
|
|
169 cchMaxLen = m_cchMaxItemLen_Min;
|
|
|
170 else if(cchMaxLen > m_cchMaxItemLen_Max)
|
|
|
171 cchMaxLen = m_cchMaxItemLen_Max;
|
|
|
172 }
|
|
|
173 m_cchMaxItemLen = cchMaxLen;
|
|
|
174 T* pT = static_cast<T*>(this);
|
|
|
175 pT->UpdateMenu();
|
|
|
176 }
|
|
|
177
|
|
|
178 // Operations
|
|
|
179 BOOL AddToList(LPCTSTR lpstrDocName)
|
|
|
180 {
|
|
|
181 _DocEntry de;
|
|
|
182 errno_t nRet = ATL::Checked::tcsncpy_s(de.szDocName, _countof(de.szDocName), lpstrDocName, _TRUNCATE);
|
|
|
183 if((nRet != 0) && (nRet != STRUNCATE))
|
|
|
184 return FALSE;
|
|
|
185
|
|
|
186 for(int i = 0; i < m_arrDocs.GetSize(); i++)
|
|
|
187 {
|
|
|
188 if(lstrcmpi(m_arrDocs[i].szDocName, lpstrDocName) == 0)
|
|
|
189 {
|
|
|
190 m_arrDocs.RemoveAt(i);
|
|
|
191 break;
|
|
|
192 }
|
|
|
193 }
|
|
|
194
|
|
|
195 if(m_arrDocs.GetSize() == m_nMaxEntries)
|
|
|
196 m_arrDocs.RemoveAt(0);
|
|
|
197
|
|
|
198 BOOL bRet = m_arrDocs.Add(de);
|
|
|
199 if(bRet)
|
|
|
200 {
|
|
|
201 T* pT = static_cast<T*>(this);
|
|
|
202 bRet = pT->UpdateMenu();
|
|
|
203 }
|
|
|
204 return bRet;
|
|
|
205 }
|
|
|
206
|
|
|
207 // This function is deprecated because it is not safe.
|
|
|
208 // Use the version below that accepts the buffer length.
|
|
|
209 __declspec(deprecated)
|
|
|
210 BOOL GetFromList(int /*nItemID*/, LPTSTR /*lpstrDocName*/)
|
|
|
211 {
|
|
|
212 ATLASSERT(FALSE);
|
|
|
213 return FALSE;
|
|
|
214 }
|
|
|
215
|
|
|
216 BOOL GetFromList(int nItemID, LPTSTR lpstrDocName, int cchLength)
|
|
|
217 {
|
|
|
218 int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1;
|
|
|
219 if((nIndex < 0) || (nIndex >= m_arrDocs.GetSize()))
|
|
|
220 return FALSE;
|
|
|
221 if(lstrlen(m_arrDocs[nIndex].szDocName) >= cchLength)
|
|
|
222 return FALSE;
|
|
|
223 ATL::Checked::tcscpy_s(lpstrDocName, cchLength, m_arrDocs[nIndex].szDocName);
|
|
|
224
|
|
|
225 return TRUE;
|
|
|
226 }
|
|
|
227
|
|
|
228 #ifdef __ATLSTR_H__
|
|
|
229 BOOL GetFromList(int nItemID, ATL::CString& strDocName)
|
|
|
230 {
|
|
|
231 int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1;
|
|
|
232 if((nIndex < 0) || (nIndex >= m_arrDocs.GetSize()))
|
|
|
233 return FALSE;
|
|
|
234 strDocName = m_arrDocs[nIndex].szDocName;
|
|
|
235 return TRUE;
|
|
|
236 }
|
|
|
237 #endif // __ATLSTR_H__
|
|
|
238
|
|
|
239 BOOL RemoveFromList(int nItemID)
|
|
|
240 {
|
|
|
241 int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1;
|
|
|
242 BOOL bRet = m_arrDocs.RemoveAt(nIndex);
|
|
|
243 if(bRet)
|
|
|
244 {
|
|
|
245 T* pT = static_cast<T*>(this);
|
|
|
246 bRet = pT->UpdateMenu();
|
|
|
247 }
|
|
|
248 return bRet;
|
|
|
249 }
|
|
|
250
|
|
|
251 BOOL MoveToTop(int nItemID)
|
|
|
252 {
|
|
|
253 int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1;
|
|
|
254 if((nIndex < 0) || (nIndex >= m_arrDocs.GetSize()))
|
|
|
255 return FALSE;
|
|
|
256 _DocEntry de;
|
|
|
257 de = m_arrDocs[nIndex];
|
|
|
258 m_arrDocs.RemoveAt(nIndex);
|
|
|
259 BOOL bRet = m_arrDocs.Add(de);
|
|
|
260 if(bRet)
|
|
|
261 {
|
|
|
262 T* pT = static_cast<T*>(this);
|
|
|
263 bRet = pT->UpdateMenu();
|
|
|
264 }
|
|
|
265 return bRet;
|
|
|
266 }
|
|
|
267
|
|
|
268 BOOL ReadFromRegistry(LPCTSTR lpstrRegKey)
|
|
|
269 {
|
|
|
270 T* pT = static_cast<T*>(this);
|
|
|
271 ATL::CRegKey rkParent;
|
|
|
272 ATL::CRegKey rk;
|
|
|
273
|
|
|
274 LONG lRet = rkParent.Open(HKEY_CURRENT_USER, lpstrRegKey);
|
|
|
275 if(lRet != ERROR_SUCCESS)
|
|
|
276 return FALSE;
|
|
|
277 lRet = rk.Open(rkParent, pT->GetRegKeyName());
|
|
|
278 if(lRet != ERROR_SUCCESS)
|
|
|
279 return FALSE;
|
|
|
280
|
|
|
281 DWORD dwRet = 0;
|
|
|
282 lRet = rk.QueryDWORDValue(pT->GetRegCountName(), dwRet);
|
|
|
283 if(lRet != ERROR_SUCCESS)
|
|
|
284 return FALSE;
|
|
|
285 SetMaxEntries(dwRet);
|
|
|
286
|
|
|
287 m_arrDocs.RemoveAll();
|
|
|
288
|
|
|
289 TCHAR szRetString[t_cchItemLen] = {};
|
|
|
290 _DocEntry de;
|
|
|
291
|
|
|
292 for(int nItem = m_nMaxEntries; nItem > 0; nItem--)
|
|
|
293 {
|
|
|
294 TCHAR szBuff[m_cchItemNameLen] = {};
|
|
|
295 _stprintf_s(szBuff, m_cchItemNameLen, pT->GetRegItemName(), nItem);
|
|
|
296 ULONG ulCount = t_cchItemLen;
|
|
|
297 lRet = rk.QueryStringValue(szBuff, szRetString, &ulCount);
|
|
|
298 if(lRet == ERROR_SUCCESS)
|
|
|
299 {
|
|
|
300 ATL::Checked::tcscpy_s(de.szDocName, _countof(de.szDocName), szRetString);
|
|
|
301 m_arrDocs.Add(de);
|
|
|
302 }
|
|
|
303 }
|
|
|
304
|
|
|
305 rk.Close();
|
|
|
306 rkParent.Close();
|
|
|
307
|
|
|
308 return pT->UpdateMenu();
|
|
|
309 }
|
|
|
310
|
|
|
311 BOOL WriteToRegistry(LPCTSTR lpstrRegKey)
|
|
|
312 {
|
|
|
313 T* pT = static_cast<T*>(this);
|
|
|
314 (void)pT; // avoid level 4 warning
|
|
|
315 ATL::CRegKey rkParent;
|
|
|
316 ATL::CRegKey rk;
|
|
|
317
|
|
|
318 LONG lRet = rkParent.Create(HKEY_CURRENT_USER, lpstrRegKey);
|
|
|
319 if(lRet != ERROR_SUCCESS)
|
|
|
320 return FALSE;
|
|
|
321 lRet = rk.Create(rkParent, pT->GetRegKeyName());
|
|
|
322 if(lRet != ERROR_SUCCESS)
|
|
|
323 return FALSE;
|
|
|
324
|
|
|
325 lRet = rk.SetDWORDValue(pT->GetRegCountName(), m_nMaxEntries);
|
|
|
326 ATLASSERT(lRet == ERROR_SUCCESS);
|
|
|
327
|
|
|
328 // set new values
|
|
|
329 int nItem;
|
|
|
330 for(nItem = m_arrDocs.GetSize(); nItem > 0; nItem--)
|
|
|
331 {
|
|
|
332 TCHAR szBuff[m_cchItemNameLen] = {};
|
|
|
333 _stprintf_s(szBuff, m_cchItemNameLen, pT->GetRegItemName(), nItem);
|
|
|
334 TCHAR szDocName[t_cchItemLen] = {};
|
|
|
335 GetFromList(t_nFirstID + nItem - 1, szDocName, t_cchItemLen);
|
|
|
336 lRet = rk.SetStringValue(szBuff, szDocName);
|
|
|
337 ATLASSERT(lRet == ERROR_SUCCESS);
|
|
|
338 }
|
|
|
339
|
|
|
340 // delete unused keys
|
|
|
341 for(nItem = m_arrDocs.GetSize() + 1; nItem <= m_nMaxEntries_Max; nItem++)
|
|
|
342 {
|
|
|
343 TCHAR szBuff[m_cchItemNameLen] = {};
|
|
|
344 _stprintf_s(szBuff, m_cchItemNameLen, pT->GetRegItemName(), nItem);
|
|
|
345 rk.DeleteValue(szBuff);
|
|
|
346 }
|
|
|
347
|
|
|
348 rk.Close();
|
|
|
349 rkParent.Close();
|
|
|
350
|
|
|
351 return TRUE;
|
|
|
352 }
|
|
|
353
|
|
|
354 // Implementation
|
|
|
355 BOOL UpdateMenu()
|
|
|
356 {
|
|
|
357 if(m_hMenu == NULL)
|
|
|
358 return FALSE;
|
|
|
359 ATLASSERT(::IsMenu(m_hMenu));
|
|
|
360
|
|
|
361 int nItems = ::GetMenuItemCount(m_hMenu);
|
|
|
362 int nInsertPoint = 0;
|
|
|
363 for(int i = 0; i < nItems; i++)
|
|
|
364 {
|
|
|
365 CMenuItemInfo mi;
|
|
|
366 mi.fMask = MIIM_ID;
|
|
|
367 ::GetMenuItemInfo(m_hMenu, i, TRUE, &mi);
|
|
|
368 if (mi.wID == t_nFirstID)
|
|
|
369 {
|
|
|
370 nInsertPoint = i;
|
|
|
371 break;
|
|
|
372 }
|
|
|
373 }
|
|
|
374
|
|
|
375 ATLASSERT((nInsertPoint < nItems) && "You need a menu item with an ID = t_nFirstID");
|
|
|
376
|
|
|
377 for(int j = t_nFirstID; j < (t_nFirstID + m_nMaxEntries); j++)
|
|
|
378 {
|
|
|
379 // keep the first one as an insertion point
|
|
|
380 if (j != t_nFirstID)
|
|
|
381 ::DeleteMenu(m_hMenu, j, MF_BYCOMMAND);
|
|
|
382 }
|
|
|
383
|
|
|
384 TCHAR szItemText[t_cchItemLen + 6] = {}; // add space for &, 2 digits, and a space
|
|
|
385 int nSize = m_arrDocs.GetSize();
|
|
|
386 int nItem = 0;
|
|
|
387 if(nSize > 0)
|
|
|
388 {
|
|
|
389 for(nItem = 0; nItem < nSize; nItem++)
|
|
|
390 {
|
|
|
391 if(m_cchMaxItemLen == -1)
|
|
|
392 {
|
|
|
393 _stprintf_s(szItemText, t_cchItemLen + 6, _T("&%i %s"), nItem + 1, m_arrDocs[nSize - 1 - nItem].szDocName);
|
|
|
394 }
|
|
|
395 else
|
|
|
396 {
|
|
|
397 TCHAR szBuff[t_cchItemLen] = {};
|
|
|
398 T* pT = static_cast<T*>(this);
|
|
|
399 (void)pT; // avoid level 4 warning
|
|
|
400 bool bRet = pT->CompactDocumentName(szBuff, m_arrDocs[nSize - 1 - nItem].szDocName, m_cchMaxItemLen);
|
|
|
401 (void)bRet; // avoid level 4 warning
|
|
|
402 ATLASSERT(bRet);
|
|
|
403 _stprintf_s(szItemText, t_cchItemLen + 6, _T("&%i %s"), nItem + 1, szBuff);
|
|
|
404 }
|
|
|
405
|
|
|
406 ::InsertMenu(m_hMenu, nInsertPoint + nItem, MF_BYPOSITION | MF_STRING, t_nFirstID + nItem, szItemText);
|
|
|
407 }
|
|
|
408 }
|
|
|
409 else // empty
|
|
|
410 {
|
|
|
411 ::InsertMenu(m_hMenu, nInsertPoint, MF_BYPOSITION | MF_STRING, t_nFirstID, m_szNoEntries);
|
|
|
412 ::EnableMenuItem(m_hMenu, t_nFirstID, MF_GRAYED);
|
|
|
413 nItem++;
|
|
|
414 }
|
|
|
415 ::DeleteMenu(m_hMenu, nInsertPoint + nItem, MF_BYPOSITION);
|
|
|
416
|
|
|
417 return TRUE;
|
|
|
418 }
|
|
|
419
|
|
|
420 // Overrideables
|
|
|
421 // override to provide a different method of compacting document names
|
|
|
422 static bool CompactDocumentName(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen)
|
|
|
423 {
|
|
|
424 return AtlCompactPath(lpstrOut, lpstrIn, cchLen);
|
|
|
425 }
|
|
|
426
|
|
|
427 static LPCTSTR GetRegKeyName()
|
|
|
428 {
|
|
|
429 return _T("Recent Document List");
|
|
|
430 }
|
|
|
431
|
|
|
432 static LPCTSTR GetRegCountName()
|
|
|
433 {
|
|
|
434 return _T("DocumentCount");
|
|
|
435 }
|
|
|
436
|
|
|
437 static LPCTSTR GetRegItemName()
|
|
|
438 {
|
|
|
439 // Note: This string is a format string used with wsprintf().
|
|
|
440 // Resulting formatted string must be m_cchItemNameLen or less
|
|
|
441 // characters long, including the terminating null character.
|
|
|
442 return _T("Document%i");
|
|
|
443 }
|
|
|
444
|
|
|
445 static LPCTSTR GetMRUEmptyText()
|
|
|
446 {
|
|
|
447 return _WTL_MRUEMPTY_TEXT;
|
|
|
448 }
|
|
|
449 };
|
|
|
450
|
|
|
451 class CRecentDocumentList : public CRecentDocumentListBase<CRecentDocumentList>
|
|
|
452 {
|
|
|
453 public:
|
|
|
454 // nothing here
|
|
|
455 };
|
|
|
456
|
|
|
457
|
|
|
458 ///////////////////////////////////////////////////////////////////////////////
|
|
|
459 // CFindFile - file search helper class
|
|
|
460
|
|
|
461 class CFindFile
|
|
|
462 {
|
|
|
463 public:
|
|
|
464 // Data members
|
|
|
465 HANDLE m_hFind;
|
|
|
466 WIN32_FIND_DATA m_fd;
|
|
|
467 LPTSTR m_lpszRoot;
|
|
|
468 const TCHAR m_chDirSeparator;
|
|
|
469 BOOL m_bFound;
|
|
|
470
|
|
|
471 // Constructor/destructor
|
|
|
472 CFindFile() : m_hFind(NULL), m_lpszRoot(NULL), m_chDirSeparator(_T('\\')), m_bFound(FALSE)
|
|
|
473 { }
|
|
|
474
|
|
|
475 ~CFindFile()
|
|
|
476 {
|
|
|
477 Close();
|
|
|
478 }
|
|
|
479
|
|
|
480 // Attributes
|
|
|
481 ULONGLONG GetFileSize() const
|
|
|
482 {
|
|
|
483 ATLASSERT(m_hFind != NULL);
|
|
|
484
|
|
|
485 ULARGE_INTEGER nFileSize = {};
|
|
|
486 if(m_bFound)
|
|
|
487 {
|
|
|
488 nFileSize.LowPart = m_fd.nFileSizeLow;
|
|
|
489 nFileSize.HighPart = m_fd.nFileSizeHigh;
|
|
|
490 }
|
|
|
491 else
|
|
|
492 {
|
|
|
493 nFileSize.QuadPart = 0;
|
|
|
494 }
|
|
|
495
|
|
|
496 return nFileSize.QuadPart;
|
|
|
497 }
|
|
|
498
|
|
|
499 BOOL GetFileName(LPTSTR lpstrFileName, int cchLength) const
|
|
|
500 {
|
|
|
501 ATLASSERT(m_hFind != NULL);
|
|
|
502 if(lstrlen(m_fd.cFileName) >= cchLength)
|
|
|
503 return FALSE;
|
|
|
504
|
|
|
505 if(m_bFound)
|
|
|
506 ATL::Checked::tcscpy_s(lpstrFileName, cchLength, m_fd.cFileName);
|
|
|
507
|
|
|
508 return m_bFound;
|
|
|
509 }
|
|
|
510
|
|
|
511 BOOL GetFilePath(LPTSTR lpstrFilePath, int cchLength) const
|
|
|
512 {
|
|
|
513 ATLASSERT(m_hFind != NULL);
|
|
|
514
|
|
|
515 int nLen = lstrlen(m_lpszRoot);
|
|
|
516 ATLASSERT(nLen > 0);
|
|
|
517 if(nLen == 0)
|
|
|
518 return FALSE;
|
|
|
519
|
|
|
520 bool bAddSep = (m_lpszRoot[nLen - 1] != m_chDirSeparator);
|
|
|
521
|
|
|
522 if((lstrlen(m_lpszRoot) + (bAddSep ? 1 : 0)) >= cchLength)
|
|
|
523 return FALSE;
|
|
|
524
|
|
|
525 ATL::Checked::tcscpy_s(lpstrFilePath, cchLength, m_lpszRoot);
|
|
|
526
|
|
|
527 if(bAddSep)
|
|
|
528 {
|
|
|
529 TCHAR szSeparator[2] = { m_chDirSeparator, 0 };
|
|
|
530 ATL::Checked::tcscat_s(lpstrFilePath, cchLength, szSeparator);
|
|
|
531 }
|
|
|
532
|
|
|
533 ATL::Checked::tcscat_s(lpstrFilePath, cchLength, m_fd.cFileName);
|
|
|
534
|
|
|
535 return TRUE;
|
|
|
536 }
|
|
|
537
|
|
|
538 BOOL GetFileTitle(LPTSTR lpstrFileTitle, int cchLength) const
|
|
|
539 {
|
|
|
540 ATLASSERT(m_hFind != NULL);
|
|
|
541
|
|
|
542 TCHAR szBuff[MAX_PATH] = {};
|
|
|
543 if(!GetFileName(szBuff, MAX_PATH))
|
|
|
544 return FALSE;
|
|
|
545
|
|
|
546 if((lstrlen(szBuff) >= cchLength) || (cchLength < 1))
|
|
|
547 return FALSE;
|
|
|
548
|
|
|
549 // find the last dot
|
|
|
550 LPTSTR pstrDot = _tcsrchr(szBuff, _T('.'));
|
|
|
551 if(pstrDot != NULL)
|
|
|
552 *pstrDot = 0;
|
|
|
553
|
|
|
554 ATL::Checked::tcscpy_s(lpstrFileTitle, cchLength, szBuff);
|
|
|
555
|
|
|
556 return TRUE;
|
|
|
557 }
|
|
|
558
|
|
|
559 BOOL GetFileURL(LPTSTR lpstrFileURL, int cchLength) const
|
|
|
560 {
|
|
|
561 ATLASSERT(m_hFind != NULL);
|
|
|
562
|
|
|
563 LPCTSTR lpstrFileURLPrefix = _T("file://");
|
|
|
564 const int cchPrefix = lstrlen(lpstrFileURLPrefix);
|
|
|
565 if(cchPrefix >= cchLength)
|
|
|
566 return FALSE;
|
|
|
567
|
|
|
568 ATL::Checked::tcscpy_s(lpstrFileURL, cchLength, lpstrFileURLPrefix);
|
|
|
569
|
|
|
570 return GetFilePath(&lpstrFileURL[cchPrefix], cchLength - cchPrefix);
|
|
|
571 }
|
|
|
572
|
|
|
573 BOOL GetRoot(LPTSTR lpstrRoot, int cchLength) const
|
|
|
574 {
|
|
|
575 ATLASSERT(m_hFind != NULL);
|
|
|
576 if(lstrlen(m_lpszRoot) >= cchLength)
|
|
|
577 return FALSE;
|
|
|
578
|
|
|
579 ATL::Checked::tcscpy_s(lpstrRoot, cchLength, m_lpszRoot);
|
|
|
580
|
|
|
581 return TRUE;
|
|
|
582 }
|
|
|
583
|
|
|
584 #ifdef __ATLSTR_H__
|
|
|
585 ATL::CString GetFileName() const
|
|
|
586 {
|
|
|
587 ATLASSERT(m_hFind != NULL);
|
|
|
588
|
|
|
589 ATL::CString ret;
|
|
|
590
|
|
|
591 if(m_bFound)
|
|
|
592 ret = m_fd.cFileName;
|
|
|
593 return ret;
|
|
|
594 }
|
|
|
595
|
|
|
596 ATL::CString GetFilePath() const
|
|
|
597 {
|
|
|
598 ATLASSERT(m_hFind != NULL);
|
|
|
599
|
|
|
600 ATL::CString strResult = m_lpszRoot;
|
|
|
601 int nLen = strResult.GetLength();
|
|
|
602 ATLASSERT(nLen > 0);
|
|
|
603 if(nLen == 0)
|
|
|
604 return strResult;
|
|
|
605
|
|
|
606 if(strResult[nLen - 1] != m_chDirSeparator)
|
|
|
607 strResult += m_chDirSeparator;
|
|
|
608 strResult += GetFileName();
|
|
|
609 return strResult;
|
|
|
610 }
|
|
|
611
|
|
|
612 ATL::CString GetFileTitle() const
|
|
|
613 {
|
|
|
614 ATLASSERT(m_hFind != NULL);
|
|
|
615
|
|
|
616 ATL::CString strResult;
|
|
|
617 GetFileTitle(strResult.GetBuffer(MAX_PATH), MAX_PATH);
|
|
|
618 strResult.ReleaseBuffer();
|
|
|
619
|
|
|
620 return strResult;
|
|
|
621 }
|
|
|
622
|
|
|
623 ATL::CString GetFileURL() const
|
|
|
624 {
|
|
|
625 ATLASSERT(m_hFind != NULL);
|
|
|
626
|
|
|
627 ATL::CString strResult("file://");
|
|
|
628 strResult += GetFilePath();
|
|
|
629 return strResult;
|
|
|
630 }
|
|
|
631
|
|
|
632 ATL::CString GetRoot() const
|
|
|
633 {
|
|
|
634 ATLASSERT(m_hFind != NULL);
|
|
|
635
|
|
|
636 ATL::CString str = m_lpszRoot;
|
|
|
637 return str;
|
|
|
638 }
|
|
|
639 #endif // __ATLSTR_H__
|
|
|
640
|
|
|
641 BOOL GetLastWriteTime(FILETIME* pTimeStamp) const
|
|
|
642 {
|
|
|
643 ATLASSERT(m_hFind != NULL);
|
|
|
644 ATLASSERT(pTimeStamp != NULL);
|
|
|
645
|
|
|
646 if(m_bFound && (pTimeStamp != NULL))
|
|
|
647 {
|
|
|
648 *pTimeStamp = m_fd.ftLastWriteTime;
|
|
|
649 return TRUE;
|
|
|
650 }
|
|
|
651
|
|
|
652 return FALSE;
|
|
|
653 }
|
|
|
654
|
|
|
655 BOOL GetLastAccessTime(FILETIME* pTimeStamp) const
|
|
|
656 {
|
|
|
657 ATLASSERT(m_hFind != NULL);
|
|
|
658 ATLASSERT(pTimeStamp != NULL);
|
|
|
659
|
|
|
660 if(m_bFound && (pTimeStamp != NULL))
|
|
|
661 {
|
|
|
662 *pTimeStamp = m_fd.ftLastAccessTime;
|
|
|
663 return TRUE;
|
|
|
664 }
|
|
|
665
|
|
|
666 return FALSE;
|
|
|
667 }
|
|
|
668
|
|
|
669 BOOL GetCreationTime(FILETIME* pTimeStamp) const
|
|
|
670 {
|
|
|
671 ATLASSERT(m_hFind != NULL);
|
|
|
672
|
|
|
673 if(m_bFound && (pTimeStamp != NULL))
|
|
|
674 {
|
|
|
675 *pTimeStamp = m_fd.ftCreationTime;
|
|
|
676 return TRUE;
|
|
|
677 }
|
|
|
678
|
|
|
679 return FALSE;
|
|
|
680 }
|
|
|
681
|
|
|
682 BOOL MatchesMask(DWORD dwMask) const
|
|
|
683 {
|
|
|
684 ATLASSERT(m_hFind != NULL);
|
|
|
685
|
|
|
686 if(m_bFound)
|
|
|
687 return ((m_fd.dwFileAttributes & dwMask) != 0);
|
|
|
688
|
|
|
689 return FALSE;
|
|
|
690 }
|
|
|
691
|
|
|
692 BOOL IsDots() const
|
|
|
693 {
|
|
|
694 ATLASSERT(m_hFind != NULL);
|
|
|
695
|
|
|
696 // return TRUE if the file name is "." or ".." and
|
|
|
697 // the file is a directory
|
|
|
698
|
|
|
699 BOOL bResult = FALSE;
|
|
|
700 if(m_bFound && IsDirectory())
|
|
|
701 {
|
|
|
702 if((m_fd.cFileName[0] == _T('.')) && ((m_fd.cFileName[1] == _T('\0')) || ((m_fd.cFileName[1] == _T('.')) && (m_fd.cFileName[2] == _T('\0')))))
|
|
|
703 bResult = TRUE;
|
|
|
704 }
|
|
|
705
|
|
|
706 return bResult;
|
|
|
707 }
|
|
|
708
|
|
|
709 BOOL IsReadOnly() const
|
|
|
710 {
|
|
|
711 return MatchesMask(FILE_ATTRIBUTE_READONLY);
|
|
|
712 }
|
|
|
713
|
|
|
714 BOOL IsDirectory() const
|
|
|
715 {
|
|
|
716 return MatchesMask(FILE_ATTRIBUTE_DIRECTORY);
|
|
|
717 }
|
|
|
718
|
|
|
719 BOOL IsCompressed() const
|
|
|
720 {
|
|
|
721 return MatchesMask(FILE_ATTRIBUTE_COMPRESSED);
|
|
|
722 }
|
|
|
723
|
|
|
724 BOOL IsSystem() const
|
|
|
725 {
|
|
|
726 return MatchesMask(FILE_ATTRIBUTE_SYSTEM);
|
|
|
727 }
|
|
|
728
|
|
|
729 BOOL IsHidden() const
|
|
|
730 {
|
|
|
731 return MatchesMask(FILE_ATTRIBUTE_HIDDEN);
|
|
|
732 }
|
|
|
733
|
|
|
734 BOOL IsTemporary() const
|
|
|
735 {
|
|
|
736 return MatchesMask(FILE_ATTRIBUTE_TEMPORARY);
|
|
|
737 }
|
|
|
738
|
|
|
739 BOOL IsNormal() const
|
|
|
740 {
|
|
|
741 return MatchesMask(FILE_ATTRIBUTE_NORMAL);
|
|
|
742 }
|
|
|
743
|
|
|
744 BOOL IsArchived() const
|
|
|
745 {
|
|
|
746 return MatchesMask(FILE_ATTRIBUTE_ARCHIVE);
|
|
|
747 }
|
|
|
748
|
|
|
749 // Operations
|
|
|
750 BOOL FindFile(LPCTSTR pstrName = NULL, bool bAutoLongPath = false)
|
|
|
751 {
|
|
|
752 Close();
|
|
|
753
|
|
|
754 if(pstrName == NULL)
|
|
|
755 pstrName = _T("*.*");
|
|
|
756
|
|
|
757 if(bAutoLongPath && (lstrlen(pstrName) >= MAX_PATH))
|
|
|
758 {
|
|
|
759 LPCTSTR lpstrPrefix = _T("\\\\?\\");
|
|
|
760 int cchLongPath = lstrlen(lpstrPrefix) + lstrlen(pstrName) + 1;
|
|
|
761 ATL::CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
|
|
|
762 LPTSTR lpstrLongPath = buff.Allocate(cchLongPath);
|
|
|
763 if(lpstrLongPath != NULL)
|
|
|
764 {
|
|
|
765 ATL::Checked::tcscpy_s(lpstrLongPath, cchLongPath, lpstrPrefix);
|
|
|
766 ATL::Checked::tcscat_s(lpstrLongPath, cchLongPath, pstrName);
|
|
|
767 m_hFind = ::FindFirstFile(lpstrLongPath, &m_fd);
|
|
|
768 }
|
|
|
769 }
|
|
|
770 else
|
|
|
771 {
|
|
|
772 m_hFind = ::FindFirstFile(pstrName, &m_fd);
|
|
|
773 }
|
|
|
774
|
|
|
775 if(m_hFind == INVALID_HANDLE_VALUE)
|
|
|
776 return FALSE;
|
|
|
777
|
|
|
778 int cchRoot = ::GetFullPathName(pstrName, 0, NULL, NULL);
|
|
|
779 if(cchRoot > 0)
|
|
|
780 ATLTRY(m_lpszRoot = new TCHAR[cchRoot]);
|
|
|
781 if(m_lpszRoot == NULL)
|
|
|
782 return FALSE;
|
|
|
783
|
|
|
784 bool bFullPath = (::GetFullPathName(pstrName, cchRoot, m_lpszRoot, NULL) != 0);
|
|
|
785
|
|
|
786 // passed name isn't a valid path but was found by the API
|
|
|
787 ATLASSERT(bFullPath);
|
|
|
788 if(!bFullPath)
|
|
|
789 {
|
|
|
790 Close();
|
|
|
791 ::SetLastError(ERROR_INVALID_NAME);
|
|
|
792 return FALSE;
|
|
|
793 }
|
|
|
794 else
|
|
|
795 {
|
|
|
796 // find the last separator
|
|
|
797 LPTSTR pstrSep = _tcsrchr(m_lpszRoot, m_chDirSeparator);
|
|
|
798 if(pstrSep != NULL)
|
|
|
799 *pstrSep = _T('\0');
|
|
|
800 }
|
|
|
801
|
|
|
802 m_bFound = TRUE;
|
|
|
803
|
|
|
804 return TRUE;
|
|
|
805 }
|
|
|
806
|
|
|
807 BOOL FindNextFile()
|
|
|
808 {
|
|
|
809 ATLASSERT(m_hFind != NULL);
|
|
|
810
|
|
|
811 if(m_hFind == NULL)
|
|
|
812 return FALSE;
|
|
|
813
|
|
|
814 if(!m_bFound)
|
|
|
815 return FALSE;
|
|
|
816
|
|
|
817 m_bFound = ::FindNextFile(m_hFind, &m_fd);
|
|
|
818
|
|
|
819 return m_bFound;
|
|
|
820 }
|
|
|
821
|
|
|
822 void Close()
|
|
|
823 {
|
|
|
824 m_bFound = FALSE;
|
|
|
825
|
|
|
826 delete [] m_lpszRoot;
|
|
|
827 m_lpszRoot = NULL;
|
|
|
828
|
|
|
829 if((m_hFind != NULL) && (m_hFind != INVALID_HANDLE_VALUE))
|
|
|
830 {
|
|
|
831 ::FindClose(m_hFind);
|
|
|
832 m_hFind = NULL;
|
|
|
833 }
|
|
|
834 }
|
|
|
835 };
|
|
|
836
|
|
|
837
|
|
|
838 ///////////////////////////////////////////////////////////////////////////////
|
|
|
839 // CRegProperty and CRegPropertyImpl<> - properties stored in registry
|
|
|
840
|
|
|
841 // How to use: Derive a class from CRegPropertyImpl, add data members
|
|
|
842 // for properties, and add REGPROP map to map properties to registry value names.
|
|
|
843 // You can then call Read() and Write() methods to read and write properties to/from registry.
|
|
|
844 // You can also use CRegProperty class directly, for one time read/write, or for custom stuff.
|
|
|
845
|
|
|
846 #define REGPROP_CURRENTUSER 0x0000
|
|
|
847 #define REGPROP_LOCALMACHINE 0x0001
|
|
|
848 #define REGPROP_READONLY 0x0002
|
|
|
849 #define REGPROP_WRITEONLY 0x0004
|
|
|
850
|
|
|
851 class CRegProperty
|
|
|
852 {
|
|
|
853 public:
|
|
|
854 // Type declarations
|
|
|
855 struct BinaryProp
|
|
|
856 {
|
|
|
857 void* pBinary;
|
|
|
858 ULONG uSize; // buffer size in bytes, used size after read
|
|
|
859
|
|
|
860 BinaryProp() : pBinary(NULL), uSize(0U)
|
|
|
861 { }
|
|
|
862 };
|
|
|
863
|
|
|
864 struct CharArrayProp
|
|
|
865 {
|
|
|
866 LPTSTR lpstrText;
|
|
|
867 ULONG uSize; // buffer size in chars
|
|
|
868
|
|
|
869 CharArrayProp() : lpstrText(NULL), uSize(0U)
|
|
|
870 { }
|
|
|
871 };
|
|
|
872
|
|
|
873 // Data members
|
|
|
874 ATL::CRegKey m_regkey;
|
|
|
875 WORD m_wFlags;
|
|
|
876
|
|
|
877 // Constructor
|
|
|
878 CRegProperty() : m_wFlags(REGPROP_CURRENTUSER)
|
|
|
879 { }
|
|
|
880
|
|
|
881 // Registry key methods
|
|
|
882 LSTATUS OpenRegKey(LPCTSTR lpstrRegKey, bool bWrite)
|
|
|
883 {
|
|
|
884 ATLASSERT(m_regkey.m_hKey == NULL);
|
|
|
885
|
|
|
886 HKEY hKey = ((m_wFlags & REGPROP_LOCALMACHINE) != 0) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
|
|
|
887 REGSAM sam = KEY_READ | KEY_WRITE;
|
|
|
888 LSTATUS lRet = -1;
|
|
|
889 if(bWrite)
|
|
|
890 lRet = m_regkey.Create(hKey, lpstrRegKey, NULL, 0, ((m_wFlags & REGPROP_WRITEONLY) != 0) ? KEY_WRITE : sam);
|
|
|
891 else
|
|
|
892 lRet = m_regkey.Open(hKey, lpstrRegKey, ((m_wFlags & REGPROP_READONLY) != 0) ? KEY_READ : sam);
|
|
|
893
|
|
|
894 return lRet;
|
|
|
895 }
|
|
|
896
|
|
|
897 void CloseRegKey()
|
|
|
898 {
|
|
|
899 LSTATUS lRet = m_regkey.Close();
|
|
|
900 (void)lRet; // avoid level 4 warning
|
|
|
901 ATLASSERT(lRet == ERROR_SUCCESS);
|
|
|
902 }
|
|
|
903
|
|
|
904 // Flag methods
|
|
|
905 WORD GetFlags() const
|
|
|
906 {
|
|
|
907 return m_wFlags;
|
|
|
908 }
|
|
|
909
|
|
|
910 WORD SetFlags(WORD wFlags, WORD wMask = 0)
|
|
|
911 {
|
|
|
912 WORD wPrevFlags = m_wFlags;
|
|
|
913 if(wMask == 0)
|
|
|
914 m_wFlags = wFlags;
|
|
|
915 else
|
|
|
916 m_wFlags = (m_wFlags & ~wMask) | (wFlags & wMask);
|
|
|
917
|
|
|
918 return wPrevFlags;
|
|
|
919 }
|
|
|
920
|
|
|
921 // Generic read/write methods
|
|
|
922 template <class TProp>
|
|
|
923 LSTATUS ReadProp(LPCTSTR lpstrRegValue, TProp& prop)
|
|
|
924 {
|
|
|
925 ATLASSERT(m_regkey.m_hKey != NULL);
|
|
|
926
|
|
|
927 DWORD dwRet = 0;
|
|
|
928 LSTATUS lRet = m_regkey.QueryDWORDValue(lpstrRegValue, dwRet);
|
|
|
929 if(lRet == ERROR_SUCCESS)
|
|
|
930 prop = static_cast<TProp>(dwRet);
|
|
|
931
|
|
|
932 return lRet;
|
|
|
933 }
|
|
|
934
|
|
|
935 template <class TProp>
|
|
|
936 LSTATUS WriteProp(LPCTSTR lpstrRegValue, TProp& prop)
|
|
|
937 {
|
|
|
938 ATLASSERT(m_regkey.m_hKey != NULL);
|
|
|
939
|
|
|
940 return m_regkey.SetDWORDValue(lpstrRegValue, (DWORD)prop);
|
|
|
941 }
|
|
|
942
|
|
|
943 // Specialization for bool
|
|
|
944 template <>
|
|
|
945 LSTATUS ReadProp(LPCTSTR lpstrRegValue, bool& bProp)
|
|
|
946 {
|
|
|
947 ATLASSERT(m_regkey.m_hKey != NULL);
|
|
|
948
|
|
|
949 DWORD dwRet = 0;
|
|
|
950 LSTATUS lRet = m_regkey.QueryDWORDValue(lpstrRegValue, dwRet);
|
|
|
951 if(lRet == ERROR_SUCCESS)
|
|
|
952 bProp = (dwRet != 0);
|
|
|
953
|
|
|
954 return lRet;
|
|
|
955 }
|
|
|
956
|
|
|
957 template <>
|
|
|
958 LSTATUS WriteProp(LPCTSTR lpstrRegValue, bool& bProp)
|
|
|
959 {
|
|
|
960 ATLASSERT(m_regkey.m_hKey != NULL);
|
|
|
961
|
|
|
962 return m_regkey.SetDWORDValue(lpstrRegValue, bProp ? 1 : 0);
|
|
|
963 }
|
|
|
964
|
|
|
965 // Specialization for HFONT
|
|
|
966 template <>
|
|
|
967 LSTATUS ReadProp(LPCTSTR lpstrRegValue, HFONT& hFont)
|
|
|
968 {
|
|
|
969 ATLASSERT(m_regkey.m_hKey != NULL);
|
|
|
970
|
|
|
971 LOGFONT lf = {};
|
|
|
972 ULONG uSize = sizeof(lf);
|
|
|
973 LSTATUS lRet = m_regkey.QueryBinaryValue(lpstrRegValue, &lf, &uSize);
|
|
|
974 if(lRet == ERROR_SUCCESS)
|
|
|
975 {
|
|
|
976 if(hFont != NULL)
|
|
|
977 ::DeleteObject(hFont);
|
|
|
978
|
|
|
979 hFont = ::CreateFontIndirect(&lf);
|
|
|
980 if(hFont == NULL)
|
|
|
981 lRet = ERROR_INVALID_DATA;
|
|
|
982 }
|
|
|
983
|
|
|
984 return lRet;
|
|
|
985 }
|
|
|
986
|
|
|
987 template <>
|
|
|
988 LSTATUS WriteProp(LPCTSTR lpstrRegValue, HFONT& hFont)
|
|
|
989 {
|
|
|
990 ATLASSERT(m_regkey.m_hKey != NULL);
|
|
|
991
|
|
|
992 CLogFont lf(hFont);
|
|
|
993 return m_regkey.SetBinaryValue(lpstrRegValue, &lf, sizeof(lf));
|
|
|
994 }
|
|
|
995
|
|
|
996 // Specialization for BinaryProp
|
|
|
997 template <>
|
|
|
998 LSTATUS ReadProp(LPCTSTR lpstrRegValue, BinaryProp& binProp)
|
|
|
999 {
|
|
|
1000 ATLASSERT(m_regkey.m_hKey != NULL);
|
|
|
1001
|
|
|
1002 ULONG uSize = 0U;
|
|
|
1003 LSTATUS lRet = m_regkey.QueryBinaryValue(lpstrRegValue, NULL, &uSize);
|
|
|
1004 if(lRet == ERROR_SUCCESS)
|
|
|
1005 {
|
|
|
1006 if(uSize <= binProp.uSize)
|
|
|
1007 lRet = m_regkey.QueryBinaryValue(lpstrRegValue, binProp.pBinary, &binProp.uSize);
|
|
|
1008 else
|
|
|
1009 lRet = ERROR_OUTOFMEMORY;
|
|
|
1010 }
|
|
|
1011
|
|
|
1012 return lRet;
|
|
|
1013 }
|
|
|
1014
|
|
|
1015 template <>
|
|
|
1016 LSTATUS WriteProp(LPCTSTR lpstrRegValue, BinaryProp& binProp)
|
|
|
1017 {
|
|
|
1018 ATLASSERT(m_regkey.m_hKey != NULL);
|
|
|
1019
|
|
|
1020 return m_regkey.SetBinaryValue(lpstrRegValue, binProp.pBinary, binProp.uSize);
|
|
|
1021 }
|
|
|
1022
|
|
|
1023 // Specialization for CharArrayProp
|
|
|
1024 template <>
|
|
|
1025 LSTATUS ReadProp(LPCTSTR lpstrRegValue, CharArrayProp& caProp)
|
|
|
1026 {
|
|
|
1027 ATLASSERT(m_regkey.m_hKey != NULL);
|
|
|
1028
|
|
|
1029 ULONG uSize = 0U;
|
|
|
1030 LSTATUS lRet = m_regkey.QueryStringValue(lpstrRegValue, NULL, &uSize);
|
|
|
1031 if(lRet == ERROR_SUCCESS)
|
|
|
1032 {
|
|
|
1033 if(uSize <= caProp.uSize)
|
|
|
1034 lRet = m_regkey.QueryStringValue(lpstrRegValue, caProp.lpstrText, &caProp.uSize);
|
|
|
1035 else
|
|
|
1036 lRet = ERROR_OUTOFMEMORY;
|
|
|
1037 }
|
|
|
1038
|
|
|
1039 return lRet;
|
|
|
1040 }
|
|
|
1041
|
|
|
1042 template <>
|
|
|
1043 LSTATUS WriteProp(LPCTSTR lpstrRegValue, CharArrayProp& caProp)
|
|
|
1044 {
|
|
|
1045 ATLASSERT(m_regkey.m_hKey != NULL);
|
|
|
1046
|
|
|
1047 return m_regkey.SetStringValue(lpstrRegValue, caProp.lpstrText);
|
|
|
1048 }
|
|
|
1049
|
|
|
1050 // Specialization for CString
|
|
|
1051 #ifdef __ATLSTR_H__
|
|
|
1052 template <>
|
|
|
1053 LSTATUS ReadProp(LPCTSTR lpstrRegValue, ATL::CString& strProp)
|
|
|
1054 {
|
|
|
1055 ATLASSERT(m_regkey.m_hKey != NULL);
|
|
|
1056
|
|
|
1057 ULONG uSize = 0U;
|
|
|
1058 LSTATUS lRet = m_regkey.QueryStringValue(lpstrRegValue, NULL, &uSize);
|
|
|
1059 if(lRet == ERROR_SUCCESS)
|
|
|
1060 {
|
|
|
1061 lRet = m_regkey.QueryStringValue(lpstrRegValue, strProp.GetBufferSetLength(uSize), &uSize);
|
|
|
1062 strProp.ReleaseBuffer();
|
|
|
1063 }
|
|
|
1064
|
|
|
1065 return lRet;
|
|
|
1066 }
|
|
|
1067
|
|
|
1068 template <>
|
|
|
1069 LSTATUS WriteProp(LPCTSTR lpstrRegValue, ATL::CString& strProp)
|
|
|
1070 {
|
|
|
1071 ATLASSERT(m_regkey.m_hKey != NULL);
|
|
|
1072
|
|
|
1073 return m_regkey.SetStringValue(lpstrRegValue, (LPCTSTR)strProp);
|
|
|
1074 }
|
|
|
1075 #endif // __ATLSTR_H__
|
|
|
1076
|
|
|
1077 // Static methods for one time read/write
|
|
|
1078 template <class TProp>
|
|
|
1079 static bool ReadOne(LPCTSTR lpstrRegKey, LPCTSTR lpstrRegValue, TProp& prop, WORD wFlags = REGPROP_CURRENTUSER)
|
|
|
1080 {
|
|
|
1081 CRegProperty rp;
|
|
|
1082 rp.SetFlags(wFlags);
|
|
|
1083 LSTATUS lRet = rp.OpenRegKey(lpstrRegKey, false);
|
|
|
1084 if(lRet == ERROR_SUCCESS)
|
|
|
1085 {
|
|
|
1086 lRet = rp.ReadProp(lpstrRegValue, prop);
|
|
|
1087 rp.CloseRegKey();
|
|
|
1088 }
|
|
|
1089
|
|
|
1090 return (lRet == ERROR_SUCCESS) || (lRet == ERROR_FILE_NOT_FOUND);
|
|
|
1091 }
|
|
|
1092
|
|
|
1093 template <class TProp>
|
|
|
1094 static bool WriteOne(LPCTSTR lpstrRegKey, LPCTSTR lpstrRegValue, TProp& prop, WORD wFlags = REGPROP_CURRENTUSER)
|
|
|
1095 {
|
|
|
1096 CRegProperty rp;
|
|
|
1097 rp.SetFlags(wFlags);
|
|
|
1098 LSTATUS lRet = rp.OpenRegKey(lpstrRegKey, true);
|
|
|
1099 if(lRet == ERROR_SUCCESS)
|
|
|
1100 {
|
|
|
1101 lRet = rp.WriteProp(lpstrRegValue, prop);
|
|
|
1102 rp.CloseRegKey();
|
|
|
1103 }
|
|
|
1104
|
|
|
1105 return (lRet == ERROR_SUCCESS);
|
|
|
1106 }
|
|
|
1107 };
|
|
|
1108
|
|
|
1109
|
|
|
1110 #define BEGIN_REGPROP_MAP(class) \
|
|
|
1111 void ReadWriteAll(bool bWrite) \
|
|
|
1112 {
|
|
|
1113
|
|
|
1114 #define REG_PROPERTY(name, prop) \
|
|
|
1115 this->ReadWriteProp(name, prop, bWrite);
|
|
|
1116
|
|
|
1117 #define END_REGPROP_MAP() \
|
|
|
1118 }
|
|
|
1119
|
|
|
1120 template <class T>
|
|
|
1121 class CRegPropertyImpl : public CRegProperty
|
|
|
1122 {
|
|
|
1123 public:
|
|
|
1124 // Methods
|
|
|
1125 void Read(LPCTSTR lpstrRegKey)
|
|
|
1126 {
|
|
|
1127 T* pT = static_cast<T*>(this);
|
|
|
1128 LSTATUS lRet = pT->OpenRegKey(lpstrRegKey, false);
|
|
|
1129 if(lRet == ERROR_SUCCESS)
|
|
|
1130 {
|
|
|
1131 pT->ReadWriteAll(false);
|
|
|
1132 pT->OnRead(lpstrRegKey);
|
|
|
1133
|
|
|
1134 pT->CloseRegKey();
|
|
|
1135 }
|
|
|
1136 else if(lRet != ERROR_FILE_NOT_FOUND)
|
|
|
1137 {
|
|
|
1138 pT->OnReadError(NULL, lRet);
|
|
|
1139 }
|
|
|
1140 }
|
|
|
1141
|
|
|
1142 void Write(LPCTSTR lpstrRegKey)
|
|
|
1143 {
|
|
|
1144 T* pT = static_cast<T*>(this);
|
|
|
1145 LSTATUS lRet = pT->OpenRegKey(lpstrRegKey, true);
|
|
|
1146 if(lRet == ERROR_SUCCESS)
|
|
|
1147 {
|
|
|
1148 pT->ReadWriteAll(true);
|
|
|
1149 pT->OnWrite(lpstrRegKey);
|
|
|
1150
|
|
|
1151 pT->CloseRegKey();
|
|
|
1152 }
|
|
|
1153 else
|
|
|
1154 {
|
|
|
1155 pT->OnWriteError(NULL, lRet);
|
|
|
1156 }
|
|
|
1157 }
|
|
|
1158
|
|
|
1159 // Implementation
|
|
|
1160 template <class TProp>
|
|
|
1161 void ReadWriteProp(LPCTSTR lpstrRegValue, TProp& prop, bool bWrite)
|
|
|
1162 {
|
|
|
1163 T* pT = static_cast<T*>(this);
|
|
|
1164 if(bWrite)
|
|
|
1165 {
|
|
|
1166 LSTATUS lRet = pT->WriteProp(lpstrRegValue, prop);
|
|
|
1167 if(lRet != ERROR_SUCCESS)
|
|
|
1168 pT->OnWriteError(lpstrRegValue, lRet);
|
|
|
1169 }
|
|
|
1170 else
|
|
|
1171 {
|
|
|
1172 LSTATUS lRet = pT->ReadProp(lpstrRegValue, prop);
|
|
|
1173 if((lRet != ERROR_SUCCESS) && (lRet != ERROR_FILE_NOT_FOUND))
|
|
|
1174 pT->OnReadError(lpstrRegValue, lRet);
|
|
|
1175 }
|
|
|
1176 }
|
|
|
1177
|
|
|
1178 // Overrideable handlers
|
|
|
1179 void OnRead(LPCTSTR /*lpstrRegValue*/)
|
|
|
1180 { }
|
|
|
1181
|
|
|
1182 void OnWrite(LPCTSTR /*lpstrRegValue*/)
|
|
|
1183 { }
|
|
|
1184
|
|
|
1185 void OnReadError(LPCTSTR /*lpstrRegValue*/, LSTATUS /*lError*/)
|
|
|
1186 {
|
|
|
1187 ATLASSERT(FALSE);
|
|
|
1188 }
|
|
|
1189
|
|
|
1190 void OnWriteError(LPCTSTR /*lpstrRegValue*/, LSTATUS /*lError*/)
|
|
|
1191 {
|
|
|
1192 ATLASSERT(FALSE);
|
|
|
1193 }
|
|
|
1194 };
|
|
|
1195
|
|
|
1196
|
|
|
1197 ///////////////////////////////////////////////////////////////////////////////
|
|
|
1198 // Global functions for stock GDI objects
|
|
|
1199
|
|
|
1200 inline HPEN AtlGetStockPen(int nPen)
|
|
|
1201 {
|
|
|
1202 ATLASSERT((nPen == WHITE_PEN) || (nPen == BLACK_PEN) || (nPen == NULL_PEN) || (nPen == DC_PEN));
|
|
|
1203 return (HPEN)::GetStockObject(nPen);
|
|
|
1204 }
|
|
|
1205
|
|
|
1206 inline HBRUSH AtlGetStockBrush(int nBrush)
|
|
|
1207 {
|
|
|
1208 ATLASSERT(((nBrush >= WHITE_BRUSH) && (nBrush <= HOLLOW_BRUSH)) || (nBrush == DC_BRUSH));
|
|
|
1209 return (HBRUSH)::GetStockObject(nBrush);
|
|
|
1210 }
|
|
|
1211
|
|
|
1212 inline HFONT AtlGetStockFont(int nFont)
|
|
|
1213 {
|
|
|
1214 ATLASSERT(((nFont >= OEM_FIXED_FONT) && (nFont <= SYSTEM_FIXED_FONT)) || (nFont == DEFAULT_GUI_FONT));
|
|
|
1215 return (HFONT)::GetStockObject(nFont);
|
|
|
1216 }
|
|
|
1217
|
|
|
1218 inline HPALETTE AtlGetStockPalette(int nPalette)
|
|
|
1219 {
|
|
|
1220 ATLASSERT(nPalette == DEFAULT_PALETTE); // the only one supported
|
|
|
1221 return (HPALETTE)::GetStockObject(nPalette);
|
|
|
1222 }
|
|
|
1223
|
|
|
1224
|
|
|
1225 ///////////////////////////////////////////////////////////////////////////////
|
|
|
1226 // Global function for compacting a path by replacing parts with ellipsis
|
|
|
1227
|
|
|
1228 // helper for multi-byte character sets
|
|
|
1229 inline bool _IsDBCSTrailByte(LPCTSTR lpstr, int nChar)
|
|
|
1230 {
|
|
|
1231 #ifndef _UNICODE
|
|
|
1232 int i = nChar;
|
|
|
1233 for( ; i > 0; i--)
|
|
|
1234 {
|
|
|
1235 if(!::IsDBCSLeadByte(lpstr[i - 1]))
|
|
|
1236 break;
|
|
|
1237 }
|
|
|
1238 return ((nChar > 0) && (((nChar - i) & 1) != 0));
|
|
|
1239 #else // _UNICODE
|
|
|
1240 (void)lpstr; // avoid level 4 warning
|
|
|
1241 (void)nChar; // avoid level 4 warning
|
|
|
1242 return false;
|
|
|
1243 #endif // _UNICODE
|
|
|
1244 }
|
|
|
1245
|
|
|
1246 inline bool AtlCompactPath(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen)
|
|
|
1247 {
|
|
|
1248 ATLASSERT(lpstrOut != NULL);
|
|
|
1249 ATLASSERT(lpstrIn != NULL);
|
|
|
1250 ATLASSERT(cchLen > 0);
|
|
|
1251
|
|
|
1252 LPCTSTR szEllipsis = _T("...");
|
|
|
1253 const int cchEndEllipsis = 3;
|
|
|
1254 const int cchMidEllipsis = 4;
|
|
|
1255
|
|
|
1256 if(lstrlen(lpstrIn) < cchLen)
|
|
|
1257 {
|
|
|
1258 ATL::Checked::tcscpy_s(lpstrOut, cchLen, lpstrIn);
|
|
|
1259 return true;
|
|
|
1260 }
|
|
|
1261
|
|
|
1262 lpstrOut[0] = 0;
|
|
|
1263
|
|
|
1264 // check if the separator is a slash or a backslash
|
|
|
1265 TCHAR chSlash = _T('\\');
|
|
|
1266 for(LPTSTR lpstr = (LPTSTR)lpstrIn; *lpstr != 0; lpstr = ::CharNext(lpstr))
|
|
|
1267 {
|
|
|
1268 if((*lpstr == _T('/')) || (*lpstr == _T('\\')))
|
|
|
1269 chSlash = *lpstr;
|
|
|
1270 }
|
|
|
1271
|
|
|
1272 // find the filename portion of the path
|
|
|
1273 LPCTSTR lpstrFileName = lpstrIn;
|
|
|
1274 for(LPCTSTR pPath = lpstrIn; *pPath; pPath = ::CharNext(pPath))
|
|
|
1275 {
|
|
|
1276 if(((pPath[0] == _T('\\')) || (pPath[0] == _T(':')) || (pPath[0] == _T('/')))
|
|
|
1277 && pPath[1] && (pPath[1] != _T('\\')) && (pPath[1] != _T('/')))
|
|
|
1278 lpstrFileName = pPath + 1;
|
|
|
1279 }
|
|
|
1280 int cchFileName = lstrlen(lpstrFileName);
|
|
|
1281
|
|
|
1282 // handle just the filename without a path
|
|
|
1283 if((lpstrFileName == lpstrIn) && (cchLen > cchEndEllipsis))
|
|
|
1284 {
|
|
|
1285 bool bRet = (ATL::Checked::tcsncpy_s(lpstrOut, cchLen, lpstrIn, cchLen - cchEndEllipsis - 1) == 0);
|
|
|
1286 if(bRet)
|
|
|
1287 {
|
|
|
1288 #ifndef _UNICODE
|
|
|
1289 if(_IsDBCSTrailByte(lpstrIn, cchLen - cchEndEllipsis))
|
|
|
1290 lpstrOut[cchLen - cchEndEllipsis - 1] = 0;
|
|
|
1291 #endif // _UNICODE
|
|
|
1292 ATL::Checked::tcscat_s(lpstrOut, cchLen, szEllipsis);
|
|
|
1293 }
|
|
|
1294 return bRet;
|
|
|
1295 }
|
|
|
1296
|
|
|
1297 // handle just ellipsis
|
|
|
1298 if((cchLen < (cchMidEllipsis + cchEndEllipsis)))
|
|
|
1299 {
|
|
|
1300 for(int i = 0; i < cchLen - 1; i++)
|
|
|
1301 lpstrOut[i] = ((i + 1) == cchMidEllipsis) ? chSlash : _T('.');
|
|
|
1302 lpstrOut[cchLen - 1] = 0;
|
|
|
1303 return true;
|
|
|
1304 }
|
|
|
1305
|
|
|
1306 // calc how much we have to copy
|
|
|
1307 int cchToCopy = cchLen - (cchMidEllipsis + cchFileName) - 1;
|
|
|
1308
|
|
|
1309 if(cchToCopy < 0)
|
|
|
1310 cchToCopy = 0;
|
|
|
1311
|
|
|
1312 #ifndef _UNICODE
|
|
|
1313 if((cchToCopy > 0) && _IsDBCSTrailByte(lpstrIn, cchToCopy))
|
|
|
1314 cchToCopy--;
|
|
|
1315 #endif // _UNICODE
|
|
|
1316
|
|
|
1317 bool bRet = (ATL::Checked::tcsncpy_s(lpstrOut, cchLen, lpstrIn, cchToCopy) == 0);
|
|
|
1318 if(!bRet)
|
|
|
1319 return false;
|
|
|
1320
|
|
|
1321 // add ellipsis
|
|
|
1322 ATL::Checked::tcscat_s(lpstrOut, cchLen, szEllipsis);
|
|
|
1323 TCHAR szSlash[2] = { chSlash, 0 };
|
|
|
1324 ATL::Checked::tcscat_s(lpstrOut, cchLen, szSlash);
|
|
|
1325
|
|
|
1326 // add filename (and ellipsis, if needed)
|
|
|
1327 if(cchLen > (cchMidEllipsis + cchFileName))
|
|
|
1328 {
|
|
|
1329 ATL::Checked::tcscat_s(lpstrOut, cchLen, lpstrFileName);
|
|
|
1330 }
|
|
|
1331 else
|
|
|
1332 {
|
|
|
1333 cchToCopy = cchLen - cchMidEllipsis - cchEndEllipsis - 1;
|
|
|
1334 #ifndef _UNICODE
|
|
|
1335 if((cchToCopy > 0) && _IsDBCSTrailByte(lpstrFileName, cchToCopy))
|
|
|
1336 cchToCopy--;
|
|
|
1337 #endif // _UNICODE
|
|
|
1338 bRet = (ATL::Checked::tcsncpy_s(&lpstrOut[cchMidEllipsis], cchLen - cchMidEllipsis, lpstrFileName, cchToCopy) == 0);
|
|
|
1339 if(bRet)
|
|
|
1340 ATL::Checked::tcscat_s(lpstrOut, cchLen, szEllipsis);
|
|
|
1341 }
|
|
|
1342
|
|
|
1343 return bRet;
|
|
|
1344 }
|
|
|
1345
|
|
|
1346 } // namespace WTL
|
|
|
1347
|
|
|
1348 #endif // __ATLMISC_H__
|