3 * Copyright (C) 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS "Welcome"/AutoRun application
22 * FILE: base/setup/welcome/welcome.c
23 * PROGRAMMERS: Eric Kohl
24 * Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * Hermes Belusca-Maito
28 * This utility can be customized by using localized INI configuration files.
29 * The default strings are stored in the utility's resources.
43 #include <reactos/buildno.h>
47 #define LIGHT_BLUE RGB(214, 239, 247)
48 #define DARK_BLUE RGB(107, 123, 140)
50 #define TITLE_WIDTH 480
51 #define TITLE_HEIGHT 93
53 /* GLOBALS ******************************************************************/
55 TCHAR szWindowClass
[] = TEXT("WelcomeWindowClass");
62 HWND hWndCheckButton
= NULL
;
63 HWND hWndCloseButton
= NULL
;
65 BOOL bDisplayCheckBox
= FALSE
;
66 BOOL bDisplayExitBtn
= TRUE
;
68 #define BUFFER_SIZE 1024
70 #define TOPIC_TITLE_LENGTH 80
71 #define TOPIC_DESC_LENGTH 1024
79 * TRUE : szCommand contains a command (e.g. executable to run);
80 * FALSE: szCommand contains a custom "Welcome"/AutoRun action.
85 TCHAR szTitle
[TOPIC_TITLE_LENGTH
];
86 TCHAR szDesc
[TOPIC_DESC_LENGTH
];
91 DWORD dwNumberTopics
= 0;
92 PTOPIC
* pTopics
= NULL
;
96 TCHAR szDefaultTitle
[TOPIC_TITLE_LENGTH
];
97 TCHAR szDefaultDesc
[TOPIC_DESC_LENGTH
];
99 #define TOPIC_BTN_ID_BASE 100
101 INT nTopic
= -1; // Active (focused) topic
102 INT nDefaultTopic
= -1; // Default selected topic
105 HBITMAP hTitleBitmap
= NULL
;
106 HBITMAP hDefaultTopicBitmap
= NULL
;
108 HFONT hFontTopicButton
;
109 HFONT hFontTopicTitle
;
110 HFONT hFontTopicDescription
;
111 HFONT hFontCheckButton
;
122 MainWndProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
125 /* FUNCTIONS ****************************************************************/
127 INT
GetLocaleName(IN LCID Locale
, OUT LPTSTR lpLCData
, IN SIZE_T cchData
)
131 /* Try to retrieve the locale language name (LOCALE_SNAME is supported on Vista+) */
132 cchRet
= GetLocaleInfo(Locale
, LOCALE_SNAME
, lpLCData
, cchData
);
133 if (cchRet
|| (GetLastError() != ERROR_INVALID_FLAGS
))
137 * We failed because LOCALE_SNAME was unrecognized, so try to manually build
138 * a language name in the form xx-YY (WARNING: this method has its limitations).
140 cchRet
= GetLocaleInfo(Locale
, LOCALE_SISO639LANGNAME
, lpLCData
, cchData
);
144 lpLCData
+= (cchRet
- 1);
145 cchData
-= (cchRet
- 1);
149 /* Try to get the second part; we add the '-' separator only if we succeed */
150 cchRet2
= GetLocaleInfo(Locale
, LOCALE_SISO3166CTRYNAME
, lpLCData
+ 1, cchData
- 1);
153 cchRet
+= cchRet2
; // 'cchRet' already counts '-'.
160 VOID
TranslateEscapes(IN OUT LPTSTR lpString
)
162 LPTSTR pEscape
= NULL
; // Next backslash escape sequence.
164 while (lpString
&& *lpString
)
166 /* Find the next backslash escape sequence */
167 pEscape
= _tcschr(lpString
, _T('\\'));
171 /* Go past the escape backslash */
172 lpString
= pEscape
+ 1;
174 /* Find which sequence it is */
178 // *pEscape = _T('\0'); // Enable if one wants to convert \<NULL> into <NULL>.
179 // lpString = pEscape + 1; // Loop will stop at the next iteration.
182 /* New-line and carriage return */
183 case _T('n'): case _T('r'):
184 // case _T('\\'): // others?
185 // So far we only need to deal with the newlines.
187 if (*lpString
== _T('n'))
189 else if (*lpString
== _T('r'))
192 memmove(lpString
, lpString
+ 1, (_tcslen(lpString
+ 1) + 1) * sizeof(TCHAR
));
196 /* \xhhhh hexadecimal character specification */
200 *pEscape
= (WCHAR
)_tcstoul(lpString
+ 1, &lpStringNew
, 16);
201 memmove(lpString
, lpStringNew
, (_tcslen(lpStringNew
) + 1) * sizeof(TCHAR
));
205 /* Unknown escape sequence, ignore it */
214 * Expands the path for the ReactOS Installer "reactos.exe".
215 * See also base/system/userinit/userinit.c!StartInstaller()
219 IN LPCTSTR lpInstallerName
,
220 OUT LPTSTR lpInstallerPath
,
223 SYSTEM_INFO SystemInfo
;
224 SIZE_T cchInstallerNameLen
;
228 cchInstallerNameLen
= _tcslen(lpInstallerName
);
229 if (PathSize
< cchInstallerNameLen
)
231 /* The buffer is not large enough to contain the installer file name */
232 *lpInstallerPath
= 0;
237 * First, try to find the installer using the default drive, under
238 * the directory whose name corresponds to the currently-running
241 GetSystemInfo(&SystemInfo
);
243 *lpInstallerPath
= 0;
244 GetModuleFileName(NULL
, lpInstallerPath
, PathSize
- cchInstallerNameLen
- 1);
245 ptr
= _tcschr(lpInstallerPath
, _T('\\'));
249 *lpInstallerPath
= 0;
251 /* Append the corresponding CPU architecture */
252 switch (SystemInfo
.wProcessorArchitecture
)
254 case PROCESSOR_ARCHITECTURE_INTEL
:
255 StringCchCat(lpInstallerPath
, PathSize
, TEXT("I386"));
258 case PROCESSOR_ARCHITECTURE_MIPS
:
259 StringCchCat(lpInstallerPath
, PathSize
, TEXT("MIPS"));
262 case PROCESSOR_ARCHITECTURE_ALPHA
:
263 StringCchCat(lpInstallerPath
, PathSize
, TEXT("ALPHA"));
266 case PROCESSOR_ARCHITECTURE_PPC
:
267 StringCchCat(lpInstallerPath
, PathSize
, TEXT("PPC"));
270 case PROCESSOR_ARCHITECTURE_SHX
:
271 StringCchCat(lpInstallerPath
, PathSize
, TEXT("SHX"));
274 case PROCESSOR_ARCHITECTURE_ARM
:
275 StringCchCat(lpInstallerPath
, PathSize
, TEXT("ARM"));
278 case PROCESSOR_ARCHITECTURE_IA64
:
279 StringCchCat(lpInstallerPath
, PathSize
, TEXT("IA64"));
282 case PROCESSOR_ARCHITECTURE_ALPHA64
:
283 StringCchCat(lpInstallerPath
, PathSize
, TEXT("ALPHA64"));
286 case PROCESSOR_ARCHITECTURE_AMD64
:
287 StringCchCat(lpInstallerPath
, PathSize
, TEXT("AMD64"));
290 // case PROCESSOR_ARCHITECTURE_MSIL: /* .NET CPU-independent code */
291 case PROCESSOR_ARCHITECTURE_UNKNOWN
:
293 SystemInfo
.wProcessorArchitecture
= PROCESSOR_ARCHITECTURE_UNKNOWN
;
297 if (SystemInfo
.wProcessorArchitecture
!= PROCESSOR_ARCHITECTURE_UNKNOWN
)
298 StringCchCat(lpInstallerPath
, PathSize
, TEXT("\\"));
299 StringCchCat(lpInstallerPath
, PathSize
, lpInstallerName
);
301 dwAttribs
= GetFileAttributes(lpInstallerPath
);
302 if ((dwAttribs
!= INVALID_FILE_ATTRIBUTES
) &&
303 !(dwAttribs
& FILE_ATTRIBUTE_DIRECTORY
))
305 /* We have found the installer */
310 * We failed. Try to find the installer from either the current
311 * ReactOS installation directory, or from our current directory.
313 *lpInstallerPath
= 0;
314 if (GetWindowsDirectory(lpInstallerPath
, PathSize
- cchInstallerNameLen
- 1))
315 StringCchCat(lpInstallerPath
, PathSize
, TEXT("\\"));
316 StringCchCat(lpInstallerPath
, PathSize
, lpInstallerName
);
318 dwAttribs
= GetFileAttributes(lpInstallerPath
);
319 if ((dwAttribs
!= INVALID_FILE_ATTRIBUTES
) &&
320 !(dwAttribs
& FILE_ATTRIBUTE_DIRECTORY
))
322 /* We have found the installer */
326 /* Installer not found */
327 *lpInstallerPath
= 0;
331 VOID
InitializeTopicList(VOID
)
337 PTOPIC
AddNewTopic(VOID
)
339 PTOPIC pTopic
, *pTopicsTmp
;
341 /* Allocate (or reallocate) the list of topics */
343 pTopicsTmp
= HeapAlloc(GetProcessHeap(), 0, (dwNumberTopics
+ 1) * sizeof(*pTopics
));
345 pTopicsTmp
= HeapReAlloc(GetProcessHeap(), 0, pTopics
, (dwNumberTopics
+ 1) * sizeof(*pTopics
));
347 return NULL
; // Cannot reallocate more
348 pTopics
= pTopicsTmp
;
350 /* Allocate a new topic entry */
351 pTopic
= HeapAlloc(GetProcessHeap(), 0, sizeof(*pTopic
));
353 return NULL
; // Cannot reallocate more
354 pTopics
[dwNumberTopics
++] = pTopic
;
356 /* Return the allocated topic entry */
362 IN LPTSTR szText OPTIONAL
,
363 IN LPTSTR szTitle OPTIONAL
,
364 IN LPTSTR szDesc OPTIONAL
,
365 IN LPTSTR szCommand OPTIONAL
,
366 IN LPTSTR szArgs OPTIONAL
,
367 IN LPTSTR szAction OPTIONAL
)
369 PTOPIC pTopic
= AddNewTopic();
373 if (szText
&& *szText
)
374 StringCchCopy(pTopic
->szText
, ARRAYSIZE(pTopic
->szText
), szText
);
378 if (szTitle
&& *szTitle
)
379 StringCchCopy(pTopic
->szTitle
, ARRAYSIZE(pTopic
->szTitle
), szTitle
);
381 *pTopic
->szTitle
= 0;
383 if (szDesc
&& *szDesc
)
385 StringCchCopy(pTopic
->szDesc
, ARRAYSIZE(pTopic
->szDesc
), szDesc
);
386 TranslateEscapes(pTopic
->szDesc
);
393 if (szCommand
&& *szCommand
)
395 pTopic
->bIsCommand
= TRUE
;
397 /* Check for special applications: ReactOS Installer */
398 if (_tcsicmp(szCommand
, TEXT("reactos.exe")) == 0)
400 ExpandInstallerPath(szCommand
, pTopic
->szCommand
, ARRAYSIZE(pTopic
->szCommand
));
404 /* Expand any environment string in the command line */
405 DWORD dwSize
= ExpandEnvironmentStringsW(szCommand
, NULL
, 0);
406 if (dwSize
<= ARRAYSIZE(pTopic
->szCommand
))
407 ExpandEnvironmentStringsW(szCommand
, pTopic
->szCommand
, ARRAYSIZE(pTopic
->szCommand
));
409 StringCchCopy(pTopic
->szCommand
, ARRAYSIZE(pTopic
->szCommand
), szCommand
);
414 pTopic
->bIsCommand
= FALSE
;
415 *pTopic
->szCommand
= 0;
418 /* Only care about command arguments if we actually have a command */
419 if (*pTopic
->szCommand
)
421 if (szArgs
&& *szArgs
)
423 StringCchCopy(pTopic
->szArgs
, ARRAYSIZE(pTopic
->szArgs
), szArgs
);
427 /* Check for special applications: ReactOS Shell */
428 if (/* pTopic->szCommand && */ *pTopic
->szCommand
&&
429 _tcsicmp(pTopic
->szCommand
, TEXT("explorer.exe")) == 0)
432 TCHAR CurrentDir
[MAX_PATH
];
433 GetCurrentDirectory(ARRAYSIZE(CurrentDir
), CurrentDir
);
435 StringCchCopy(pTopic
->szArgs
, ARRAYSIZE(pTopic
->szArgs
), TEXT("\\"));
448 /* Only care about custom actions if we actually don't have a command */
449 if (!*pTopic
->szCommand
&& szAction
&& *szAction
)
452 * Re-use the pTopic->szCommand member. We distinguish with respect to
453 * a regular command by using the pTopic->bIsCommand flag.
455 pTopic
->bIsCommand
= FALSE
;
456 StringCchCopy(pTopic
->szCommand
, ARRAYSIZE(pTopic
->szCommand
), szAction
);
457 TranslateEscapes(pTopic
->szCommand
);
464 LoadLocalizedResourcesInternal(VOID
)
466 #define MAX_NUMBER_INTERNAL_TOPICS 3
469 LPTSTR lpszCommand
, lpszAction
;
470 TOPIC newTopic
, *pTopic
;
472 for (i
= 0; i
< MAX_NUMBER_INTERNAL_TOPICS
; ++i
)
474 lpszCommand
= NULL
, lpszAction
= NULL
;
476 /* Retrieve the information */
477 if (!LoadString(hInstance
, IDS_TOPIC_BUTTON0
+ i
, newTopic
.szText
, ARRAYSIZE(newTopic
.szText
)))
478 *newTopic
.szText
= 0;
479 if (!LoadString(hInstance
, IDS_TOPIC_TITLE0
+ i
, newTopic
.szTitle
, ARRAYSIZE(newTopic
.szTitle
)))
480 *newTopic
.szTitle
= 0;
481 if (!LoadString(hInstance
, IDS_TOPIC_DESC0
+ i
, newTopic
.szDesc
, ARRAYSIZE(newTopic
.szDesc
)))
482 *newTopic
.szDesc
= 0;
484 if (!LoadString(hInstance
, IDS_TOPIC_COMMAND0
+ i
, newTopic
.szCommand
, ARRAYSIZE(newTopic
.szCommand
)))
485 *newTopic
.szCommand
= 0;
487 /* Only care about command arguments if we actually have a command */
488 if (*newTopic
.szCommand
)
490 lpszCommand
= newTopic
.szCommand
;
491 if (!LoadString(hInstance
, IDS_TOPIC_CMD_ARGS0
+ i
, newTopic
.szArgs
, ARRAYSIZE(newTopic
.szArgs
)))
492 *newTopic
.szArgs
= 0;
494 /* Only care about custom actions if we actually don't have a command */
495 else // if (!*newTopic.szCommand)
497 lpszAction
= newTopic
.szCommand
;
498 if (!LoadString(hInstance
, IDS_TOPIC_ACTION0
+ i
, newTopic
.szCommand
, ARRAYSIZE(newTopic
.szCommand
)))
499 *newTopic
.szCommand
= 0;
502 /* Allocate a new topic */
503 pTopic
= AddNewTopicEx(newTopic
.szText
,
510 break; // Cannot reallocate more
515 LoadLocalizedResourcesFromINI(LCID Locale
, LPTSTR lpResPath
)
520 TCHAR szBuffer
[LOCALE_NAME_MAX_LENGTH
];
521 TCHAR szIniPath
[MAX_PATH
];
522 LPTSTR lpszSections
= NULL
, lpszSection
= NULL
;
523 LPTSTR lpszCommand
, lpszAction
;
524 TOPIC newTopic
, *pTopic
;
526 /* Retrieve the locale name (on which the INI file name is based) */
527 dwRet
= (DWORD
)GetLocaleName(Locale
, szBuffer
, ARRAYSIZE(szBuffer
));
530 /* Fall back to english (US) */
531 StringCchCopy(szBuffer
, ARRAYSIZE(szBuffer
), TEXT("en-US"));
534 /* Build the INI file name */
535 StringCchPrintf(szIniPath
, ARRAYSIZE(szIniPath
),
536 TEXT("%s\\%s.ini"), lpResPath
, szBuffer
);
538 /* Verify that the file exists, otherwise fall back to english (US) */
539 dwAttribs
= GetFileAttributes(szIniPath
);
540 if ((dwAttribs
== INVALID_FILE_ATTRIBUTES
) ||
541 (dwAttribs
& FILE_ATTRIBUTE_DIRECTORY
))
543 StringCchCopy(szBuffer
, ARRAYSIZE(szBuffer
), TEXT("en-US"));
545 StringCchPrintf(szIniPath
, ARRAYSIZE(szIniPath
),
546 TEXT("%s\\%s.ini"), lpResPath
, szBuffer
);
549 /* Verify that the file exists, otherwise fall back to internal (localized) resource */
550 dwAttribs
= GetFileAttributes(szIniPath
);
551 if ((dwAttribs
== INVALID_FILE_ATTRIBUTES
) ||
552 (dwAttribs
& FILE_ATTRIBUTE_DIRECTORY
))
554 return FALSE
; // For localized resources, see the general function.
557 /* Try to load the default localized strings */
558 GetPrivateProfileString(TEXT("Defaults"), TEXT("AppTitle"), TEXT("ReactOS - Welcome") /* default */,
559 szAppTitle
, ARRAYSIZE(szAppTitle
), szIniPath
);
560 GetPrivateProfileString(TEXT("Defaults"), TEXT("DefaultTopicTitle"), TEXT("") /* default */,
561 szDefaultTitle
, ARRAYSIZE(szDefaultTitle
), szIniPath
);
562 if (!GetPrivateProfileString(TEXT("Defaults"), TEXT("DefaultTopicDescription"), TEXT("") /* default */,
563 szDefaultDesc
, ARRAYSIZE(szDefaultDesc
), szIniPath
))
569 TranslateEscapes(szDefaultDesc
);
572 /* Allocate a buffer big enough to hold all the section names */
573 for (dwSize
= BUFFER_SIZE
; ; dwSize
+= BUFFER_SIZE
)
575 lpszSections
= HeapAlloc(GetProcessHeap(), 0, dwSize
* sizeof(TCHAR
));
577 return TRUE
; // FIXME!
578 dwRet
= GetPrivateProfileSectionNames(lpszSections
, dwSize
, szIniPath
);
579 if (dwRet
< dwSize
- 2)
581 HeapFree(GetProcessHeap(), 0, lpszSections
);
584 /* Loop over the sections and load the topics */
585 lpszSection
= lpszSections
;
586 for (; lpszSection
&& *lpszSection
; lpszSection
+= (_tcslen(lpszSection
) + 1))
588 /* Ignore everything that is not a topic */
589 if (_tcsnicmp(lpszSection
, TEXT("Topic"), 5) != 0)
592 lpszCommand
= NULL
, lpszAction
= NULL
;
594 /* Retrieve the information */
595 GetPrivateProfileString(lpszSection
, TEXT("MenuText"), TEXT("") /* default */,
596 newTopic
.szText
, ARRAYSIZE(newTopic
.szText
), szIniPath
);
597 GetPrivateProfileString(lpszSection
, TEXT("Title"), TEXT("") /* default */,
598 newTopic
.szTitle
, ARRAYSIZE(newTopic
.szTitle
), szIniPath
);
599 GetPrivateProfileString(lpszSection
, TEXT("Description"), TEXT("") /* default */,
600 newTopic
.szDesc
, ARRAYSIZE(newTopic
.szDesc
), szIniPath
);
602 GetPrivateProfileString(lpszSection
, TEXT("ConfigCommand"), TEXT("") /* default */,
603 newTopic
.szCommand
, ARRAYSIZE(newTopic
.szCommand
), szIniPath
);
605 /* Only care about command arguments if we actually have a command */
606 if (*newTopic
.szCommand
)
608 lpszCommand
= newTopic
.szCommand
;
609 GetPrivateProfileString(lpszSection
, TEXT("ConfigArgs"), TEXT("") /* default */,
610 newTopic
.szArgs
, ARRAYSIZE(newTopic
.szArgs
), szIniPath
);
612 /* Only care about custom actions if we actually don't have a command */
613 else // if (!*newTopic.szCommand)
615 lpszAction
= newTopic
.szCommand
;
616 GetPrivateProfileString(lpszSection
, TEXT("Action"), TEXT("") /* default */,
617 newTopic
.szCommand
, ARRAYSIZE(newTopic
.szCommand
), szIniPath
);
620 /* Allocate a new topic */
621 pTopic
= AddNewTopicEx(newTopic
.szText
,
628 break; // Cannot reallocate more
631 HeapFree(GetProcessHeap(), 0, lpszSections
);
637 LoadConfiguration(VOID
)
640 BOOL bLoadDefaultResources
;
641 TCHAR szAppPath
[MAX_PATH
];
642 TCHAR szIniPath
[MAX_PATH
];
643 TCHAR szResPath
[MAX_PATH
];
645 /* Initialize the topic list */
646 InitializeTopicList();
649 * First, try to load the default internal (localized) strings.
650 * They can be redefined by the localized INI files.
652 if (!LoadString(hInstance
, IDS_APPTITLE
, szAppTitle
, ARRAYSIZE(szAppTitle
)))
653 StringCchCopy(szAppTitle
, ARRAYSIZE(szAppTitle
), TEXT("ReactOS - Welcome"));
654 if (!LoadString(hInstance
, IDS_DEFAULT_TOPIC_TITLE
, szDefaultTitle
, ARRAYSIZE(szDefaultTitle
)))
656 if (!LoadString(hInstance
, IDS_DEFAULT_TOPIC_DESC
, szDefaultDesc
, ARRAYSIZE(szDefaultDesc
)))
659 /* Retrieve the full path to this application */
660 GetModuleFileName(NULL
, szAppPath
, ARRAYSIZE(szAppPath
));
663 LPTSTR lpFileName
= _tcsrchr(szAppPath
, _T('\\'));
670 /* Build the full INI file path name */
671 StringCchPrintf(szIniPath
, ARRAYSIZE(szIniPath
), TEXT("%s\\welcome.ini"), szAppPath
);
673 /* Verify that the file exists, otherwise use the default configuration */
674 dwAttribs
= GetFileAttributes(szIniPath
);
675 if ((dwAttribs
== INVALID_FILE_ATTRIBUTES
) ||
676 (dwAttribs
& FILE_ATTRIBUTE_DIRECTORY
))
678 /* Use the default internal (localized) resources */
679 LoadLocalizedResourcesInternal();
683 /* Load the settings from the INI configuration file */
684 bDisplayCheckBox
= !!GetPrivateProfileInt(TEXT("Welcome"), TEXT("DisplayCheckBox"), FALSE
/* default */, szIniPath
);
685 bDisplayExitBtn
= !!GetPrivateProfileInt(TEXT("Welcome"), TEXT("DisplayExitButton"), TRUE
/* default */, szIniPath
);
687 /* Load the default internal (localized) resources if needed */
688 bLoadDefaultResources
= !!GetPrivateProfileInt(TEXT("Welcome"), TEXT("LoadDefaultResources"), FALSE
/* default */, szIniPath
);
689 if (bLoadDefaultResources
)
690 LoadLocalizedResourcesInternal();
692 GetPrivateProfileString(TEXT("Welcome"), TEXT("ResourceDir"), TEXT("") /* default */,
693 szResPath
, ARRAYSIZE(szResPath
), szIniPath
);
695 /* Set the current directory to the one of this application, and retrieve the resources */
696 SetCurrentDirectory(szAppPath
);
697 if (!LoadLocalizedResourcesFromINI(LOCALE_USER_DEFAULT
, szResPath
))
700 * Loading localized resources from INI file failed, try to load the
701 * internal resources only if they were not already loaded earlier.
703 if (!bLoadDefaultResources
)
704 LoadLocalizedResourcesInternal();
714 while (dwNumberTopics
--)
716 if (pTopics
[dwNumberTopics
])
717 HeapFree(GetProcessHeap(), 0, pTopics
[dwNumberTopics
]);
719 HeapFree(GetProcessHeap(), 0, pTopics
);
726 ShowLastWin32Error(HWND hWnd
)
728 LPTSTR lpMessageBuffer
= NULL
;
729 DWORD dwError
= GetLastError();
731 if (dwError
== ERROR_SUCCESS
)
734 if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
|
735 FORMAT_MESSAGE_FROM_SYSTEM
|
736 FORMAT_MESSAGE_IGNORE_INSERTS
,
740 (LPTSTR
)&lpMessageBuffer
,
746 MessageBox(hWnd
, lpMessageBuffer
, szAppTitle
, MB_OK
| MB_ICONERROR
);
747 LocalFree(lpMessageBuffer
);
752 _tWinMain(HINSTANCE hInst
,
753 HINSTANCE hPrevInstance
,
757 HANDLE hMutex
= NULL
;
766 DWORD dwStyle
= WS_OVERLAPPED
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
|
767 WS_CAPTION
| WS_SYSMENU
| WS_MINIMIZEBOX
;
770 ULONG ulInnerWidth
= TITLE_WIDTH
;
771 ULONG ulInnerHeight
= (TITLE_WIDTH
* 3) / 4;
772 ULONG ulTitleHeight
= TITLE_HEIGHT
+ 3;
774 UNREFERENCED_PARAMETER(hPrevInstance
);
775 UNREFERENCED_PARAMETER(lpszCmdLine
);
777 /* Ensure only one instance is running */
778 hMutex
= CreateMutex(NULL
, FALSE
, szWindowClass
);
779 if (hMutex
&& (GetLastError() == ERROR_ALREADY_EXISTS
))
781 /* If already started, find its window */
782 hWndMain
= FindWindow(szWindowClass
, NULL
);
784 /* Activate window */
785 ShowWindow(hWndMain
, SW_SHOWNORMAL
);
786 SetForegroundWindow(hWndMain
);
788 /* Close the mutex handle and quit */
794 /* Mirroring is enabled from within the resources */
795 switch (GetUserDefaultUILanguage())
797 case MAKELANGID(LANG_HEBREW
, SUBLANG_DEFAULT
):
798 SetProcessDefaultLayout(LAYOUT_RTL
);
809 hMainIcon
= LoadIcon(hInstance
, MAKEINTRESOURCE(IDI_MAIN
));
811 /* Register the window class */
812 wndclass
.cbSize
= sizeof(wndclass
);
813 wndclass
.style
= CS_HREDRAW
| CS_VREDRAW
;
814 wndclass
.lpfnWndProc
= (WNDPROC
)MainWndProc
;
815 wndclass
.cbClsExtra
= 0;
816 wndclass
.cbWndExtra
= 0;
817 wndclass
.hInstance
= hInstance
;
818 wndclass
.hIcon
= hMainIcon
;
819 wndclass
.hIconSm
= NULL
;
820 wndclass
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
821 wndclass
.hbrBackground
= NULL
;
822 wndclass
.lpszMenuName
= NULL
;
823 wndclass
.lpszClassName
= szWindowClass
;
825 RegisterClassEx(&wndclass
);
827 /* Load the banner bitmap, and compute the window dimensions */
828 hTitleBitmap
= LoadBitmap(hInstance
, MAKEINTRESOURCE(IDB_TITLE_BITMAP
));
831 GetObject(hTitleBitmap
, sizeof(BitmapInfo
), &BitmapInfo
);
832 ulInnerWidth
= BitmapInfo
.bmWidth
;
833 ulInnerHeight
= (ulInnerWidth
* 3) / 4;
834 ulTitleHeight
= BitmapInfo
.bmHeight
+ 3;
835 DeleteObject(hTitleBitmap
);
837 ulInnerHeight
-= GetSystemMetrics(SM_CYCAPTION
);
840 rcWindow
.bottom
= ulInnerHeight
- 1;
842 rcWindow
.right
= ulInnerWidth
- 1;
844 AdjustWindowRect(&rcWindow
, dwStyle
, FALSE
);
845 xWidth
= rcWindow
.right
- rcWindow
.left
;
846 yHeight
= rcWindow
.bottom
- rcWindow
.top
;
848 /* Compute the window position */
849 xPos
= (GetSystemMetrics(SM_CXSCREEN
) - xWidth
) / 2;
850 yPos
= (GetSystemMetrics(SM_CYSCREEN
) - yHeight
) / 2;
852 rcTitlePanel
.top
= 0;
853 rcTitlePanel
.bottom
= ulTitleHeight
;
854 rcTitlePanel
.left
= 0;
855 rcTitlePanel
.right
= ulInnerWidth
- 1;
857 rcLeftPanel
.top
= rcTitlePanel
.bottom
;
858 rcLeftPanel
.bottom
= ulInnerHeight
- 1;
859 rcLeftPanel
.left
= 0;
860 rcLeftPanel
.right
= ulInnerWidth
/ 3;
862 rcRightPanel
.top
= rcLeftPanel
.top
;
863 rcRightPanel
.bottom
= rcLeftPanel
.bottom
;
864 rcRightPanel
.left
= rcLeftPanel
.right
;
865 rcRightPanel
.right
= ulInnerWidth
- 1;
867 /* Load the configuration and the resources */
870 /* Create main window */
871 hWndMain
= CreateWindow(szWindowClass
,
883 hSystemMenu
= GetSystemMenu(hWndMain
, FALSE
);
886 RemoveMenu(hSystemMenu
, SC_SIZE
, MF_BYCOMMAND
);
887 RemoveMenu(hSystemMenu
, SC_MAXIMIZE
, MF_BYCOMMAND
);
890 ShowWindow(hWndMain
, nCmdShow
);
891 UpdateWindow(hWndMain
);
893 while (GetMessage(&msg
, NULL
, 0, 0) != FALSE
)
895 /* Check for ENTER key presses */
896 if (msg
.message
== WM_KEYDOWN
&& msg
.wParam
== VK_RETURN
)
899 * The user pressed the ENTER key. Retrieve the handle to the
900 * child window that has the keyboard focus, and send it a
901 * WM_COMMAND message.
903 hWndFocus
= GetFocus();
906 SendMessage(hWndMain
, WM_COMMAND
,
907 (WPARAM
)GetDlgCtrlID(hWndFocus
), (LPARAM
)hWndFocus
);
910 /* Allow using keyboard navigation */
911 else if (!IsDialogMessage(hWndMain
, &msg
))
913 TranslateMessage(&msg
);
914 DispatchMessage(&msg
);
921 /* Close the mutex handle and quit */
928 ButtonSubclassWndProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
930 static WPARAM wParamOld
= 0;
931 static LPARAM lParamOld
= 0;
935 if (uMsg
== WM_MOUSEMOVE
)
937 /* Ignore mouse-move messages on the same point */
938 if ((wParam
== wParamOld
) && (lParam
== lParamOld
))
941 /* Retrieve the topic index of this button */
942 i
= GetWindowLongPtr(hWnd
, GWLP_ID
) - TOPIC_BTN_ID_BASE
;
945 * Change the focus to this button if the current topic index differs
946 * (we will receive WM_SETFOCUS afterwards).
954 else if (uMsg
== WM_SETFOCUS
)
956 /* Retrieve the topic index of this button */
957 i
= GetWindowLongPtr(hWnd
, GWLP_ID
) - TOPIC_BTN_ID_BASE
;
959 /* Change the current topic index and repaint the description panel */
963 InvalidateRect(hWndMain
, &rcRightPanel
, TRUE
);
966 else if (uMsg
== WM_KILLFOCUS
)
969 * We lost focus, either because the user changed button focus,
970 * or because the main window to which we belong went inactivated.
971 * If we are in the latter case, we ignore the focus change.
972 * If we are in the former case, we reset to the default topic.
974 if (GetParent(hWnd
) == GetForegroundWindow())
977 InvalidateRect(hWndMain
, &rcRightPanel
, TRUE
);
981 return CallWindowProc(fnOldBtn
, hWnd
, uMsg
, wParam
, lParam
);
986 RunAction(INT nTopic
)
988 PCWSTR Command
= NULL
, Args
= NULL
;
993 Command
= pTopics
[nTopic
]->szCommand
;
994 if (/* !Command && */ !*Command
)
997 /* Check for known actions */
998 if (!pTopics
[nTopic
]->bIsCommand
)
1000 if (!_tcsicmp(Command
, TEXT("<exit>")))
1003 if (!_tcsnicmp(Command
, TEXT("<msg>"), 5))
1005 MessageBox(hWndMain
, Command
+ 5, TEXT("ReactOS"), MB_OK
| MB_TASKMODAL
);
1010 /* Run the command */
1012 Args
= pTopics
[nTopic
]->szArgs
;
1013 if (!*Args
) Args
= NULL
;
1014 ShellExecute(NULL
, NULL
,
1016 NULL
, SW_SHOWDEFAULT
);
1024 GetButtonHeight(HDC hDC
,
1033 rect
.right
= dwWidth
- 20;
1037 hOldFont
= (HFONT
)SelectObject(hDC
, hFont
);
1038 DrawText(hDC
, szText
, -1, &rect
, DT_TOP
| DT_CALCRECT
| DT_WORDBREAK
);
1039 SelectObject(hDC
, hOldFont
);
1041 return (rect
.bottom
-rect
.top
+ 14);
1046 OnCreate(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
1056 UNREFERENCED_PARAMETER(wParam
);
1057 UNREFERENCED_PARAMETER(lParam
);
1059 hbrLightBlue
= CreateSolidBrush(LIGHT_BLUE
);
1060 hbrDarkBlue
= CreateSolidBrush(DARK_BLUE
);
1062 ZeroMemory(&lf
, sizeof(lf
));
1064 lf
.lfEscapement
= 0;
1065 lf
.lfOrientation
= 0; // TA_BASELINE;
1066 // lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = FALSE;
1067 lf
.lfCharSet
= ANSI_CHARSET
;
1068 lf
.lfOutPrecision
= OUT_DEFAULT_PRECIS
;
1069 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
1070 lf
.lfQuality
= DEFAULT_QUALITY
;
1071 lf
.lfPitchAndFamily
= FF_DONTCARE
;
1072 if (LoadString(hInstance
, IDS_FONTNAME
, lf
.lfFaceName
, ARRAYSIZE(lf
.lfFaceName
)) == 0)
1073 StringCchCopy(lf
.lfFaceName
, ARRAYSIZE(lf
.lfFaceName
), TEXT("Tahoma"));
1075 /* Topic title font */
1078 lf
.lfWeight
= FW_NORMAL
;
1079 hFontTopicTitle
= CreateFontIndirect(&lf
);
1081 /* Topic description font */
1084 lf
.lfWeight
= FW_THIN
;
1085 hFontTopicDescription
= CreateFontIndirect(&lf
);
1087 /* Topic button font */
1090 lf
.lfWeight
= FW_BOLD
;
1091 hFontTopicButton
= CreateFontIndirect(&lf
);
1093 /* Load title bitmap */
1095 hTitleBitmap
= LoadBitmap(hInstance
, MAKEINTRESOURCE(IDB_TITLE_BITMAP
));
1097 /* Load topic bitmaps */
1098 hDefaultTopicBitmap
= LoadBitmap(hInstance
, MAKEINTRESOURCE(IDB_DEFAULT_TOPIC_BITMAP
));
1099 for (i
= 0; i
< dwNumberTopics
; i
++)
1101 // FIXME: Not implemented yet!
1102 // pTopics[i]->hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TOPIC_BITMAP0 + i));
1103 pTopics
[i
]->hBitmap
= NULL
;
1106 ScreenDC
= GetWindowDC(hWnd
);
1107 hdcMem
= CreateCompatibleDC(ScreenDC
);
1108 ReleaseDC(hWnd
, ScreenDC
);
1110 /* Load and create the menu buttons */
1111 dwTop
= rcLeftPanel
.top
;
1112 for (i
= 0; i
< dwNumberTopics
; i
++)
1114 if (*pTopics
[i
]->szText
)
1116 dwHeight
= GetButtonHeight(hdcMem
,
1119 rcLeftPanel
.right
- rcLeftPanel
.left
);
1121 pTopics
[i
]->hWndButton
= CreateWindow(TEXT("BUTTON"),
1123 (*pTopics
[i
]->szCommand
? 0 : WS_DISABLED
) |
1124 WS_CHILDWINDOW
| WS_VISIBLE
| WS_TABSTOP
|
1125 BS_MULTILINE
| BS_OWNERDRAW
,
1128 rcLeftPanel
.right
- rcLeftPanel
.left
,
1131 (HMENU
)IntToPtr(TOPIC_BTN_ID_BASE
+ i
), // Similar to SetWindowLongPtr(GWLP_ID)
1135 SendMessage(pTopics
[i
]->hWndButton
, WM_SETFONT
, (WPARAM
)hFontTopicButton
, MAKELPARAM(TRUE
, 0));
1136 fnOldBtn
= (WNDPROC
)SetWindowLongPtr(pTopics
[i
]->hWndButton
, GWLP_WNDPROC
, (DWORD_PTR
)ButtonSubclassWndProc
);
1140 pTopics
[i
]->hWndButton
= NULL
;
1146 /* Create the checkbox */
1147 if (bDisplayCheckBox
)
1149 nLength
= LoadString(hInstance
, IDS_CHECKTEXT
, szText
, ARRAYSIZE(szText
));
1154 lf
.lfWeight
= FW_THIN
;
1155 hFontCheckButton
= CreateFontIndirect(&lf
);
1157 hWndCheckButton
= CreateWindow(TEXT("BUTTON"),
1159 WS_CHILDWINDOW
| WS_VISIBLE
| WS_TABSTOP
|
1160 BS_AUTOCHECKBOX
| BS_MULTILINE
/**/| BS_FLAT
/**/,
1161 rcLeftPanel
.left
+ 8,
1162 rcLeftPanel
.bottom
- 8 - 13,
1163 rcLeftPanel
.right
- rcLeftPanel
.left
- 16,
1166 (HMENU
)IDC_CHECKBUTTON
,
1169 SendMessage(hWndCheckButton
, WM_SETFONT
, (WPARAM
)hFontCheckButton
, MAKELPARAM(TRUE
, 0));
1173 hFontCheckButton
= NULL
;
1174 hWndCheckButton
= NULL
;
1178 /* Create the "Exit" button */
1179 if (bDisplayExitBtn
)
1181 nLength
= LoadString(hInstance
, IDS_CLOSETEXT
, szText
, ARRAYSIZE(szText
));
1184 hWndCloseButton
= CreateWindow(TEXT("BUTTON"),
1186 WS_CHILDWINDOW
| WS_VISIBLE
| WS_TABSTOP
| BS_FLAT
,
1187 rcRightPanel
.right
- 8 - 57,
1188 rcRightPanel
.bottom
- 8 - 21,
1192 (HMENU
)IDC_CLOSEBUTTON
,
1196 SendMessage(hWndCloseButton
, WM_SETFONT
, (WPARAM
)hFontTopicButton
, MAKELPARAM(TRUE
, 0));
1200 hWndCloseButton
= NULL
;
1209 OnCommand(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
1211 UNREFERENCED_PARAMETER(lParam
);
1213 /* Retrieve the low-word from wParam */
1214 wParam
= LOWORD(wParam
);
1216 /* Execute action */
1217 if (wParam
== IDC_CLOSEBUTTON
)
1219 DestroyWindow(hWnd
);
1221 else if (wParam
- TOPIC_BTN_ID_BASE
< dwNumberTopics
)
1223 if (RunAction(wParam
- TOPIC_BTN_ID_BASE
) == FALSE
)
1224 DestroyWindow(hWnd
); // Corresponds to a <exit> action.
1232 PaintBanner(HDC hdc
, LPRECT rcPanel
)
1238 hOldBitmap
= (HBITMAP
)SelectObject(hdcMem
, hTitleBitmap
);
1242 rcPanel
->right
- rcPanel
->left
,
1243 rcPanel
->bottom
- 3,
1244 hdcMem
, 0, 0, SRCCOPY
);
1245 SelectObject(hdcMem
, hOldBitmap
);
1247 /* Dark blue line */
1248 hOldBrush
= (HBRUSH
)SelectObject(hdc
, hbrDarkBlue
);
1251 rcPanel
->bottom
- 3,
1252 rcPanel
->right
- rcPanel
->left
,
1255 SelectObject(hdc
, hOldBrush
);
1260 OnPaint(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
1266 HBITMAP hOldBitmap
= NULL
;
1269 RECT rcTitle
, rcDescription
;
1271 TCHAR szVersion
[50];
1272 LPTSTR lpTitle
= NULL
, lpDesc
= NULL
;
1274 UNREFERENCED_PARAMETER(wParam
);
1275 UNREFERENCED_PARAMETER(lParam
);
1277 hdc
= BeginPaint(hWnd
, &ps
);
1280 PaintBanner(hdc
, &rcTitlePanel
);
1283 hOldBrush
= (HBRUSH
)SelectObject(hdc
, hbrLightBlue
);
1287 rcLeftPanel
.right
- rcLeftPanel
.left
,
1288 rcLeftPanel
.bottom
- rcLeftPanel
.top
,
1290 SelectObject(hdc
, hOldBrush
);
1293 hOldBrush
= (HBRUSH
)SelectObject(hdc
, GetStockObject(WHITE_BRUSH
));
1297 rcRightPanel
.right
- rcRightPanel
.left
,
1298 rcRightPanel
.bottom
- rcRightPanel
.top
,
1300 SelectObject(hdc
, hOldBrush
);
1302 /* Draw dark vertical line */
1303 hPen
= CreatePen(PS_SOLID
, 0, DARK_BLUE
);
1304 hOldPen
= (HPEN
)SelectObject(hdc
, hPen
);
1305 MoveToEx(hdc
, rcRightPanel
.left
, rcRightPanel
.top
, NULL
);
1306 LineTo(hdc
, rcRightPanel
.left
, rcRightPanel
.bottom
);
1307 SelectObject(hdc
, hOldPen
);
1310 /* Draw topic bitmap */
1311 if ((nTopic
== -1) && (hDefaultTopicBitmap
))
1313 GetObject(hDefaultTopicBitmap
, sizeof(bmpInfo
), &bmpInfo
);
1314 hOldBitmap
= (HBITMAP
)SelectObject(hdcMem
, hDefaultTopicBitmap
);
1316 rcRightPanel
.right
- bmpInfo
.bmWidth
,
1317 rcRightPanel
.bottom
- bmpInfo
.bmHeight
,
1325 else if ((nTopic
!= -1) && (pTopics
[nTopic
]->hBitmap
))
1327 GetObject(pTopics
[nTopic
]->hBitmap
, sizeof(bmpInfo
), &bmpInfo
);
1328 hOldBitmap
= (HBITMAP
)SelectObject(hdcMem
, pTopics
[nTopic
]->hBitmap
);
1330 rcRightPanel
.right
- bmpInfo
.bmWidth
,
1331 rcRightPanel
.bottom
- bmpInfo
.bmHeight
,
1342 lpTitle
= szDefaultTitle
;
1343 lpDesc
= szDefaultDesc
;
1347 lpTitle
= pTopics
[nTopic
]->szTitle
;
1348 lpDesc
= pTopics
[nTopic
]->szDesc
;
1351 SetBkMode(hdc
, TRANSPARENT
);
1353 /* Draw version information */
1354 StringCchCopy(szVersion
, ARRAYSIZE(szVersion
),
1355 TEXT("ReactOS ") TEXT(KERNEL_VERSION_STR
));
1358 * Compute the original rect (position & size) of the version info,
1359 * depending whether the checkbox is displayed (version info in the
1360 * right panel) or not (version info in the left panel).
1362 if (bDisplayCheckBox
)
1363 rcTitle
= rcRightPanel
;
1365 rcTitle
= rcLeftPanel
;
1367 rcTitle
.left
= rcTitle
.left
+ 8;
1368 rcTitle
.right
= rcTitle
.right
- 5;
1369 rcTitle
.top
= rcTitle
.bottom
- 43;
1370 rcTitle
.bottom
= rcTitle
.bottom
- 8;
1372 hOldFont
= (HFONT
)SelectObject(hdc
, hFontTopicDescription
);
1373 DrawText(hdc
, szVersion
, -1, &rcTitle
, DT_BOTTOM
| DT_CALCRECT
| DT_SINGLELINE
);
1374 SetTextColor(hdc
, GetSysColor(COLOR_WINDOWTEXT
));
1375 DrawText(hdc
, szVersion
, -1, &rcTitle
, DT_BOTTOM
| DT_SINGLELINE
);
1376 SelectObject(hdc
, hOldFont
);
1378 /* Draw topic title */
1379 rcTitle
.left
= rcRightPanel
.left
+ 12;
1380 rcTitle
.right
= rcRightPanel
.right
- 8;
1381 rcTitle
.top
= rcRightPanel
.top
+ 8;
1382 rcTitle
.bottom
= rcTitle
.top
+ 57;
1383 hOldFont
= (HFONT
)SelectObject(hdc
, hFontTopicTitle
);
1384 DrawText(hdc
, lpTitle
, -1, &rcTitle
, DT_TOP
| DT_CALCRECT
);
1385 SetTextColor(hdc
, DARK_BLUE
);
1386 DrawText(hdc
, lpTitle
, -1, &rcTitle
, DT_TOP
);
1387 SelectObject(hdc
, hOldFont
);
1389 /* Draw topic description */
1390 rcDescription
.left
= rcRightPanel
.left
+ 12;
1391 rcDescription
.right
= rcRightPanel
.right
- 8;
1392 rcDescription
.top
= rcTitle
.bottom
+ 8;
1393 rcDescription
.bottom
= rcRightPanel
.bottom
- 20;
1394 hOldFont
= (HFONT
)SelectObject(hdc
, hFontTopicDescription
);
1395 SetTextColor(hdc
, GetSysColor(COLOR_WINDOWTEXT
));
1396 DrawText(hdc
, lpDesc
, -1, &rcDescription
, DT_TOP
| DT_WORDBREAK
);
1397 SelectObject(hdc
, hOldFont
);
1399 SetBkMode(hdc
, OPAQUE
);
1401 SelectObject(hdcMem
, hOldBrush
);
1402 SelectObject(hdcMem
, hOldBitmap
);
1404 EndPaint(hWnd
, &ps
);
1411 OnDrawItem(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
1413 LPDRAWITEMSTRUCT lpDis
= (LPDRAWITEMSTRUCT
)lParam
;
1419 UNREFERENCED_PARAMETER(hWnd
);
1420 UNREFERENCED_PARAMETER(wParam
);
1423 /* Neither the checkbox button nor the close button implement owner-drawing */
1424 if (lpDis
->hwndItem
== hWndCheckButton
)
1426 if (lpDis
->hwndItem
== hWndCloseButton
)
1428 DrawFrameControl(lpDis
->hDC
,
1431 DFCS_BUTTONPUSH
| DFCS_FLAT
);
1436 if (lpDis
->CtlID
== (ULONG
)(TOPIC_BTN_ID_BASE
+ nTopic
))
1437 hOldBrush
= (HBRUSH
)SelectObject(lpDis
->hDC
, GetStockObject(WHITE_BRUSH
));
1439 hOldBrush
= (HBRUSH
)SelectObject(lpDis
->hDC
, hbrLightBlue
);
1444 lpDis
->rcItem
.right
,
1445 lpDis
->rcItem
.bottom
,
1447 SelectObject(lpDis
->hDC
, hOldBrush
);
1449 hPen
= CreatePen(PS_SOLID
, 0, DARK_BLUE
);
1450 hOldPen
= (HPEN
)SelectObject(lpDis
->hDC
, hPen
);
1451 MoveToEx(lpDis
->hDC
, lpDis
->rcItem
.left
, lpDis
->rcItem
.bottom
- 1, NULL
);
1452 LineTo(lpDis
->hDC
, lpDis
->rcItem
.right
, lpDis
->rcItem
.bottom
- 1);
1453 SelectObject(lpDis
->hDC
, hOldPen
);
1456 InflateRect(&lpDis
->rcItem
, -10, -4);
1457 OffsetRect(&lpDis
->rcItem
, 0, 1);
1458 GetWindowText(lpDis
->hwndItem
, szText
, ARRAYSIZE(szText
));
1459 SetTextColor(lpDis
->hDC
, GetSysColor(IsWindowEnabled(lpDis
->hwndItem
) ?
1460 COLOR_WINDOWTEXT
: COLOR_GRAYTEXT
));
1461 iBkMode
= SetBkMode(lpDis
->hDC
, TRANSPARENT
);
1462 DrawText(lpDis
->hDC
, szText
, -1, &lpDis
->rcItem
, DT_TOP
| DT_LEFT
| DT_WORDBREAK
);
1463 SetBkMode(lpDis
->hDC
, iBkMode
);
1470 OnMouseMove(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
1472 static WPARAM wParamOld
= 0;
1473 static LPARAM lParamOld
= 0;
1475 /* Ignore mouse-move messages on the same point */
1476 if ((wParam
== wParamOld
) && (lParam
== lParamOld
))
1480 * If the user moves the mouse over the main window, outside of the
1481 * topic buttons, reset the current topic to the default one and
1482 * change the focus to some other default button (to keep keyboard
1483 * navigation possible).
1487 INT nOldTopic
= nTopic
;
1489 /* Also repaint the buttons, otherwise nothing repaints... */
1490 InvalidateRect(pTopics
[nOldTopic
]->hWndButton
, NULL
, TRUE
);
1492 /* Set the focus to some other default button */
1493 if (hWndCheckButton
)
1494 SetFocus(hWndCheckButton
);
1495 else if (hWndCloseButton
)
1496 SetFocus(hWndCloseButton
);
1499 /* Repaint the description panel */
1500 InvalidateRect(hWndMain
, &rcRightPanel
, TRUE
);
1511 OnCtlColorStatic(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
1513 UNREFERENCED_PARAMETER(hWnd
);
1515 if ((HWND
)lParam
== hWndCheckButton
)
1517 SetBkMode((HDC
)wParam
, TRANSPARENT
);
1518 return (LRESULT
)hbrLightBlue
;
1526 OnActivate(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
1528 UNREFERENCED_PARAMETER(hWnd
);
1529 UNREFERENCED_PARAMETER(lParam
);
1531 if (wParam
!= WA_INACTIVE
)
1534 * The main window is re-activated, set the focus back to
1535 * either the current topic or a default button.
1538 SetFocus(pTopics
[nTopic
]->hWndButton
);
1539 else if (hWndCheckButton
)
1540 SetFocus(hWndCheckButton
);
1541 else if (hWndCloseButton
)
1542 SetFocus(hWndCloseButton
);
1544 // InvalidateRect(hWndMain, &rcRightPanel, TRUE);
1552 OnDestroy(HWND hWnd
, WPARAM wParam
, LPARAM lParam
)
1556 UNREFERENCED_PARAMETER(hWnd
);
1557 UNREFERENCED_PARAMETER(wParam
);
1558 UNREFERENCED_PARAMETER(lParam
);
1560 for (i
= 0; i
< dwNumberTopics
; i
++)
1562 if (pTopics
[i
]->hWndButton
)
1563 DestroyWindow(pTopics
[i
]->hWndButton
);
1566 if (hWndCloseButton
)
1567 DestroyWindow(hWndCloseButton
);
1569 if (hWndCheckButton
)
1570 DestroyWindow(hWndCheckButton
);
1574 /* Delete bitmaps */
1575 DeleteObject(hDefaultTopicBitmap
);
1576 DeleteObject(hTitleBitmap
);
1577 for (i
= 0; i
< dwNumberTopics
; i
++)
1579 if (pTopics
[i
]->hBitmap
)
1580 DeleteObject(pTopics
[i
]->hBitmap
);
1583 DeleteObject(hFontTopicTitle
);
1584 DeleteObject(hFontTopicDescription
);
1585 DeleteObject(hFontTopicButton
);
1587 if (hFontCheckButton
)
1588 DeleteObject(hFontCheckButton
);
1590 DeleteObject(hbrLightBlue
);
1591 DeleteObject(hbrDarkBlue
);
1598 MainWndProc(HWND hWnd
,
1606 return OnCreate(hWnd
, wParam
, lParam
);
1609 return OnCommand(hWnd
, wParam
, lParam
);
1612 return OnActivate(hWnd
, wParam
, lParam
);
1615 return OnPaint(hWnd
, wParam
, lParam
);
1618 return OnDrawItem(hWnd
, wParam
, lParam
);
1620 case WM_CTLCOLORSTATIC
:
1621 return OnCtlColorStatic(hWnd
, wParam
, lParam
);
1624 return OnMouseMove(hWnd
, wParam
, lParam
);
1627 OnDestroy(hWnd
, wParam
, lParam
);
1632 return DefWindowProc(hWnd
, uMsg
, wParam
, lParam
);