SCRNSAVE.C
资源名称:MSDN_VC98.zip [点击查看]
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:22k
源码类别:
Windows编程
开发平台:
Visual C++
- /*++
- Copyright (c) 1997 Microsoft Corporation
- Module Name:
- scrnsave.c
- Abstract:
- This source file implements the seven required functions for a
- Windows NT 5.0 migration DLL. The DLL demonstrates how the
- interface works by performing the Windows 9x screen saver
- upgrade.
- The source here is a subset of the actual screen saver DLL
- that ships with Windows NT Setup.
- This sample demonstrates:
- - How to detect installation of your application
- - A typical implementation of QueryVersion, Initialize9x,
- MigrateUser9x, MigrateSystem9x, InitializeNT,
- MigrateUserNT and MigraetSystemNT
- - How to provide language-dependent incompatibility
- messages to the user
- - How to remove Setup's incompatibility messages via
- [Handled] section
- - Saving settings to a temporarly file in the working
- directory
- - Mix use of ANSI and UNICODE
- - Use of the SetupLogError API
- - Deleting files
- - Handling the move from system to system32
- Author:
- Jim Schmidt 11-Apr-1997
- Revision History:
- --*/
- #include "pch.h"
- //
- // Constants
- //
- #define CP_USASCII 1252
- #define END_OF_CODEPAGES -1
- //
- // Code page array
- //
- INT g_CodePageArray[] = {
- CP_USASCII,
- END_OF_CODEPAGES
- };
- //
- // Multi-sz (i.e., double-nul terminated) list of files to find
- //
- CHAR g_ExeNamesBuf[] = "Blank Screen.scr "
- "Curves and Colors.scr "
- "Flying Through Space.scr "
- "Scrolling Marquee.scr "
- "Mystify Your Mind.scr ";
- //
- // Copies of the working directory and source directory
- //
- LPSTR g_WorkingDirectory = NULL;
- LPSTR g_SourceDirectories = NULL; // multi-sz
- LPSTR g_SettingsFile = NULL;
- LPSTR g_MigrateDotInf = NULL;
- //
- // Registry locations and INI file sections
- //
- #define REGKEY_DESKTOP "Control Panel\Desktop"
- #define FULL_REGKEY_DESKTOP "HKR\Control Panel\Desktop"
- #define FULL_REGKEY_PWD_PROVIDER "HKLM\System\CurrentControlSet\Control\PwdProvider\SCRSAVE"
- #define REGVAL_SCREENSAVEACTIVE "ScreenSaveActive"
- #define REGVAL_SCREENSAVELOWPOWERACTIVE "ScreenSaveLowPowerActive"
- #define REGVAL_SCREENSAVELOWPOWERTIMEOUT "ScreenSaveLowPowerTimeout"
- #define REGVAL_SCREENSAVEPOWEROFFACTIVE "ScreenSavePowerOffActive"
- #define REGVAL_SCREENSAVEPOWEROFFTIMEOUT "ScreenSavePowerOffTimeout"
- #define REGVAL_SCREENSAVETIMEOUT "ScreenSaveTimeOut"
- #define REGVAL_SCREENSAVEUSEPASSWORD "ScreenSaveUsePassword"
- #define REGVAL_LOWPOWERACTIVE "LowPowerActive"
- #define REGVAL_LOWPOWERTIMEOUT "LowPowerTimeout"
- #define REGVAL_POWEROFFACTIVE "PowerOffActive"
- #define REGVAL_POWEROFFTIMEOUT "PowerOffTimeout"
- #define REGVAL_SCREENSAVERISSECURE "ScreenSaverIsSecure"
- //
- // State variables
- //
- BOOL g_FoundPassword = FALSE;
- LPCSTR g_User;
- CHAR g_UserNameBuf[MAX_PATH];
- HANDLE g_hHeap;
- BOOL
- WINAPI
- DllMain (
- IN HANDLE DllInstance,
- IN ULONG ReasonForCall,
- IN LPVOID Reserved
- )
- {
- switch (ReasonForCall) {
- case DLL_PROCESS_ATTACH:
- //
- // We don't need DLL_THREAD_ATTACH or DLL_THREAD_DETACH messages
- //
- DisableThreadLibraryCalls (DllInstance);
- //
- // Global init
- //
- g_hHeap = GetProcessHeap();
- if (!MigInf_Initialize()) {
- return FALSE;
- }
- // Open log; FALSE means do not delete existing log
- SetupOpenLog (FALSE);
- break;
- case DLL_PROCESS_DETACH:
- MigInf_CleanUp();
- // Clean up strings
- if (g_WorkingDirectory) {
- HeapFree (g_hHeap, 0, g_WorkingDirectory);
- }
- if (g_SourceDirectories) {
- HeapFree (g_hHeap, 0, g_SourceDirectories);
- }
- if (g_SettingsFile) {
- HeapFree (g_hHeap, 0, g_SettingsFile);
- }
- if (g_MigrateDotInf) {
- HeapFree (g_hHeap, 0, g_MigrateDotInf);
- }
- SetupCloseLog();
- break;
- }
- return TRUE;
- }
- LONG
- CALLBACK
- QueryVersion (
- OUT LPCSTR *ProductID,
- OUT LPUINT DllVersion,
- OUT LPINT *CodePageArray, OPTIONAL
- OUT LPCSTR *ExeNamesBuf, OPTIONAL
- LPVOID Reserved
- )
- {
- //
- // First, we do some preliminary investigation to see if
- // our components are installed.
- //
- if (!GetScrnSaveExe()) {
- //
- // We didn't detect any components, so we return
- // ERROR_NOT_INSTALLED and the DLL will stop being called.
- // Use this method as much as possible, because user enumeration
- // for MigrateUser9x is relatively slow. However, don't spend too
- // much time here because QueryVersion is expected to run quickly.
- //
- return ERROR_NOT_INSTALLED;
- }
- //
- // Screen saver is enabled, so tell Setup who we are. ProductID is used
- // for display, so it must be localized. The ProductID string is
- // converted to UNICODE for use on Windows NT via the MultiByteToWideChar
- // Win32 API. The first element of CodePageArray is used to specify
- // the code page of ProductID, and if no elements are returned in
- // CodePageArray, Setup assumes CP_ACP.
- //
- *ProductID = g_MyProductId;
- //
- // Report our version. Zero is reserved for use by DLLs that
- // ship with Windows NT.
- //
- *DllVersion = 1;
- //
- // Because we have English messages, we return an array that has
- // the English language ID. The sublanguage is neutral because
- // we do not have currency, time, or other geographic-specific
- // information in our messages.
- //
- // Tip: If it makes more sense for your DLL to use locales,
- // return ERROR_NOT_INSTALLED if the DLL detects that an appropriate
- // locale is not installed on the machine.
- //
- *CodePageArray = g_CodePageArray;
- //
- // ExeNamesBuf - we pass a list of file names (the long versions)
- // and let Setup find them for us. Keep this list short because
- // every instance of the file on every hard drive will be reported
- // in migrate.inf.
- //
- // Most applications don't need this behavior, because the registry
- // usually contains full paths to installed components. We need it,
- // though, because there are no registry settings that give us the
- // paths of the screen saver DLLs.
- //
- *ExeNamesBuf = g_ExeNamesBuf;
- return ERROR_SUCCESS;
- }
- LONG
- CALLBACK
- Initialize9x (
- IN LPCSTR WorkingDirectory,
- IN LPCSTR SourceDirectories,
- LPVOID Reserved
- )
- {
- INT Len;
- //
- // Because we returned ERROR_SUCCESS in QueryVersion, we are being
- // called for initialization. Therefore, we know screen savers are
- // enabled on the machine at this point.
- //
- //
- // Make global copies of WorkingDirectory and SourceDirectories --
- // we will not get this information again, and we shouldn't
- // count on Setup keeping the pointer valid for the life of our
- // DLL.
- //
- Len = CountStringBytes (WorkingDirectory);
- g_WorkingDirectory = HeapAlloc (g_hHeap, 0, Len);
- if (!g_WorkingDirectory) {
- return GetLastError();
- }
- CopyMemory (g_WorkingDirectory, WorkingDirectory, Len);
- Len = CountMultiStringBytes (SourceDirectories);
- g_SourceDirectories = HeapAlloc (g_hHeap, 0, Len);
- if (!g_SourceDirectories) {
- return GetLastError();
- }
- CopyMemory (g_SourceDirectories, SourceDirectories, Len);
- //
- // Now create our private 'settings file' path
- //
- GenerateFilePaths();
- //
- // Return success to have MigrateUser9x called
- //
- // Tip: A DLL can save system settings during Initialize9x as
- // well as MigrateSystem9x.
- //
- //
- return ERROR_SUCCESS;
- }
- LONG
- CALLBACK
- MigrateUser9x (
- IN HWND ParentWnd,
- IN LPCSTR UnattendFile,
- IN HKEY UserRegKey,
- IN LPCSTR UserName,
- LPVOID Reserved
- )
- {
- HKEY RegKey;
- LPCSTR ScrnSaveExe;
- DWORD rc = ERROR_SUCCESS;
- LPSTR SectionNameBuf, p;
- DWORD SectionNameSize;
- DWORD Len;
- //
- // This DLL does not require input from the user to upgrade
- // their settings, so ParentWnd is not used. Avoid displaying
- // any user interface when possible.
- //
- // We don't need to use UnattendFile settings because we are not
- // a service (such as a network redirector). Therefore, we do not
- // use the UnattendFile parameter.
- //
- // We don't have any files that need to be generated or expanded on
- // the NT side of Setup, so we do not write to the
- // [NT Disk Space Requirements] section of migrate.inf.
- //
- //
- // We must collect a few registry keys:
- //
- // HKCUControl PanelDesktop
- // ScreenSaveActive
- // ScreenSaveLowPowerActive
- // ScreenSaveLowPowerTimeout
- // ScreenSavePowerOffActive
- // ScreenSavePowerOffTimeout
- // ScreenSaveTimeOut
- // ScreenSaveUsePassword
- //
- // If ScreenSave_Data exists, we tell the user that their
- // password is not supported by writing an incompatiility
- // message.
- //
- //
- // Save the user name in a global so our utils write to the
- // correct section.
- //
- if (UserName) {
- g_User = UserName;
- } else {
- g_User = S_DEFAULT_USER;
- }
- // OpenRegKey is our utility (in utils.c)
- RegKey = OpenRegKey (UserRegKey, REGKEY_DESKTOP);
- if (!RegKey) {
- //
- // User's registry is invalid, so skip the user
- //
- return ERROR_NOT_INSTALLED;
- }
- //
- // Note: NO changes allowed on Win9x side, we can only read our
- // settings and save them in a file.
- //
- if (!CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVEACTIVE) ||
- !CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVELOWPOWERACTIVE) ||
- !CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVELOWPOWERTIMEOUT) ||
- !CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVEPOWEROFFACTIVE) ||
- !CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVEPOWEROFFTIMEOUT) ||
- !CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVETIMEOUT) ||
- !CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVEUSEPASSWORD)
- ) {
- rc = GetLastError();
- }
- if (atoi (GetRegValueString (RegKey, REGVAL_SCREENSAVEUSEPASSWORD))) {
- // Queue change so there is only one message
- g_FoundPassword = TRUE;
- }
- //
- // Save EXE location in our dat file
- //
- ScrnSaveExe = GetScrnSaveExe();
- if (ScrnSaveExe) {
- if (!SaveDatFileKeyAndVal (S_SCRNSAVE_EXE, ScrnSaveExe)) {
- rc = GetLastError();
- }
- }
- //
- // Copy control.ini sections to our dat file
- //
- SectionNameSize = 32768;
- SectionNameBuf = (LPSTR) HeapAlloc (g_hHeap, 0, SectionNameSize);
- if (!SectionNameBuf) {
- return GetLastError();
- }
- GetPrivateProfileString (
- NULL,
- NULL,
- S_DOUBLE_EMPTY,
- SectionNameBuf,
- SectionNameSize,
- S_CONTROL_INI
- );
- Len = _mbslen (S_SCRNSAVE_DOT);
- for (p = SectionNameBuf ; *p ; p = _mbschr (p, 0) + 1) {
- //
- // Determine if section name has "Screen Saver." at the beginning
- //
- if (!_mbsnicmp (p, S_SCRNSAVE_DOT, Len)) {
- //
- // It does, so save it to our private file
- //
- SaveControlIniSection (p, p + Len);
- }
- }
- CloseRegKey (RegKey);
- if (rc != ERROR_SUCCESS) {
- CHAR Msg[512];
- wsprintf (Msg, USER_PROCESSING_ERROR, g_User, rc);
- SetupLogError (Msg, LogSevError);
- } else {
- //
- // Write handled for every setting we are processing. Because this
- // DLL supports only some of the values in the Desktop key, we must
- // be very specific as to which values are actually handled. If
- // your DLL handles all registry values AND subkeys of a registry
- // key, you can specify NULL in the second parameter of
- // MigInf_AddHandledRegistry.
- //
- MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVEACTIVE);
- MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVELOWPOWERACTIVE);
- MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVELOWPOWERTIMEOUT);
- MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVEPOWEROFFACTIVE);
- MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVEPOWEROFFTIMEOUT);
- MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVETIMEOUT);
- MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVEUSEPASSWORD);
- }
- return rc;
- }
- LONG
- CALLBACK
- MigrateSystem9x (
- IN HWND ParentWnd,
- IN LPCSTR UnattendFile,
- LPVOID Reserved
- )
- {
- //
- // We handle the password provider incompatibility
- //
- MigInf_AddHandledRegistry (FULL_REGKEY_PWD_PROVIDER, NULL);
- //
- // Write incompatibility message if necessary (detected in MigrateUser9x)
- //
- if (g_FoundPassword) {
- MigInf_AddMessage (g_MyProductId, PASSWORD_ALERT);
- MigInf_AddMessageRegistry (
- g_MyProductId,
- FULL_REGKEY_DESKTOP,
- REGVAL_SCREENSAVEUSEPASSWORD
- );
- }
- //
- // Write memory version of migrate.inf to disk
- //
- if (!MigInf_WriteInfToDisk()) {
- return GetLastError();
- }
- return ERROR_SUCCESS;
- }
- LONG
- CALLBACK
- InitializeNT (
- IN LPCWSTR WorkingDirectory,
- IN LPCWSTR SourceDirectories,
- LPVOID Reserved
- )
- {
- INT Length;
- LPCWSTR p;
- //
- // Save our working directory and source directory. We
- // convert UNICODE to ANSI because we know we are on a US
- // version of NT. This conversion is not valid for far east
- // languages, because we use CP_ACP (ANSI code page).
- //
- // If your DLL supports far east languages, use UNICODE and
- // call the W version of Win32 functions that take strings.
- //
- //
- // Compute length of source directories
- //
- p = SourceDirectories;
- while (*p) {
- p = wcschr (p, 0) + 1;
- }
- p++;
- Length = (p - SourceDirectories) / sizeof (WCHAR);
- //
- // Convert the directories from UNICODE to DBCS. This DLL is
- // compiled in ANSI.
- //
- g_WorkingDirectory = (LPSTR) HeapAlloc (g_hHeap, 0, MAX_PATH);
- if (!g_WorkingDirectory) {
- return GetLastError();
- }
- WideCharToMultiByte (
- CP_ACP,
- 0,
- WorkingDirectory,
- -1,
- g_WorkingDirectory,
- MAX_PATH,
- NULL,
- NULL
- );
- g_SourceDirectories = (LPSTR) HeapAlloc (g_hHeap, 0, Length * sizeof(WCHAR));
- if (!g_SourceDirectories) {
- return GetLastError();
- }
- WideCharToMultiByte (
- CP_ACP,
- 0,
- SourceDirectories,
- Length,
- g_SourceDirectories,
- Length * sizeof (WCHAR),
- NULL,
- NULL
- );
- //
- // Now generate the derived file names
- //
- GenerateFilePaths();
- //
- // Note: We have no use for g_SourceDirectories for the screen saver
- // upgrade. The g_SourceDirectories string points to the Windows
- // NT media (i.e. e:i386) and optional directories specified on
- // the WINNT32 command line.
- //
- return ERROR_SUCCESS;
- }
- LONG
- CALLBACK
- MigrateUserNT (
- IN HINF UnattendInfHandle,
- IN HKEY UserRegKey,
- IN LPCWSTR UserName,
- LPVOID Reserved
- )
- {
- HKEY DesktopRegKey;
- DWORD rc = ERROR_SUCCESS;
- BOOL b = TRUE;
- //
- // Setup gives us the UnattendInfHandle instead of the file name,
- // so we don't have to open the inf file repeatitively. Since
- // Setup opened the handle, let Setup close it.
- //
- //
- // Convert UserName to ANSI
- //
- if (UserName) {
- WideCharToMultiByte (
- CP_ACP,
- 0,
- UserName,
- -1,
- g_UserNameBuf,
- MAX_PATH,
- NULL,
- NULL
- );
- g_User = g_UserNameBuf;
- } else {
- g_User = S_DEFAULT_USER;
- }
- //
- // Setup copies all of the Win9x registry, EXCEPT for the registry
- // keys that are suppressed in usermig.inf or wkstamig.inf.
- //
- // We need the HKCUControl PanelDesktop key, and because this is
- // an OS key, the settings have been altered. Most applications
- // store their settings in HKCUSoftware, HKLMSoftware or
- // HKCCSoftware, and all three of these keys are copied in their
- // entirety (except the operating system settings in
- // SoftwareMicrosoftWindows).
- //
- // When the non-OS software settings are copied from Win9x to NT, Setup
- // sometimes alters their value. For example, all registry values
- // that point to a file that was moved from SYSTEM to SYSTEM32
- // are modified to point to the right place.
- //
- //
- // Note: we use CreateRegKey here, but actually the key always exists
- // because the NT defaults have been copied into the user's registry
- // already. This approach reduces the possibility of failure.
- //
- DesktopRegKey = CreateRegKey (UserRegKey, REGKEY_DESKTOP);
- if (!DesktopRegKey) {
- CHAR Msg[512];
- rc = GetLastError();
- wsprintf (Msg, S_REGISTRY_ERROR, g_User, rc);
- SetupLogError (Msg, LogSevError);
- return rc;
- }
- // The variable b is used to fall through when we fail unexpectedly
- b = TranslateGeneralSetting (
- DesktopRegKey,
- REGVAL_SCREENSAVEACTIVE,
- NULL
- );
- if (b) {
- b = TranslateGeneralSetting (
- DesktopRegKey,
- REGVAL_SCREENSAVELOWPOWERACTIVE,
- REGVAL_LOWPOWERACTIVE
- );
- }
- if (b) {
- b = TranslateGeneralSetting (
- DesktopRegKey,
- REGVAL_SCREENSAVELOWPOWERTIMEOUT,
- REGVAL_LOWPOWERTIMEOUT
- );
- }
- if (b) {
- b = TranslateGeneralSetting (
- DesktopRegKey,
- REGVAL_SCREENSAVEPOWEROFFACTIVE,
- REGVAL_POWEROFFACTIVE
- );
- }
- if (b) {
- b = TranslateGeneralSetting (
- DesktopRegKey,
- REGVAL_SCREENSAVEPOWEROFFTIMEOUT,
- REGVAL_POWEROFFTIMEOUT
- );
- }
- if (b) {
- b = TranslateGeneralSetting (
- DesktopRegKey,
- REGVAL_SCREENSAVETIMEOUT,
- NULL
- );
- }
- if (b) {
- b = TranslateGeneralSetting (
- DesktopRegKey,
- REGVAL_SCREENSAVEUSEPASSWORD,
- REGVAL_SCREENSAVERISSECURE
- );
- }
- if (b) {
- b = SaveScrName (DesktopRegKey, S_SCRNSAVE_EXE);
- }
- if (b) {
- //
- // For screen savers work differently on Win9x and NT, perform
- // translation.
- //
- TranslateScreenSavers (UserRegKey);
- //
- // The other settings just need to be copied from control.ini
- // to the registry.
- //
- CopyUntranslatedSettings (UserRegKey);
- }
- CloseRegKey (DesktopRegKey);
- //
- // Always return success, because if an error occurred for one user,
- // we don't have a reason not to process the next user. If your DLL
- // runs into a fatal problem, such as a disk space shortage, you
- // should return the error.
- //
- return ERROR_SUCCESS;
- }
- LONG
- CALLBACK
- MigrateSystemNT (
- IN HINF UnattendInfHandle,
- LPVOID Reserved
- )
- {
- CHAR FileName[MAX_PATH];
- HINF MigrateInf;
- INFCONTEXT ic;
- CHAR Msg[512];
- //
- // We now delete the Win9x screen savers that were replaced
- // by Windows NT.
- //
- MigrateInf = SetupOpenInfFile (
- g_MigrateDotInf,
- NULL,
- INF_STYLE_WIN4,
- NULL
- );
- if (MigrateInf != INVALID_HANDLE_VALUE) {
- //
- // Use Setup APIs to scan migration paths section
- //
- if (SetupFindFirstLine (MigrateInf, S_MIGRATION_PATHS, NULL, &ic)) {
- do {
- if (SetupGetStringField (&ic, 0, FileName, MAX_PATH, NULL)) {
- //
- // All 32-bit binaries located in the Win9x system directory
- // were moved to system32. However, the paths reported in
- // [Migration Paths] are the original Win9x paths. We
- // convert c:windowssystemfile to c:windowssystem32file.
- //
- ConvertSystemToSystem32 (FileName);
- //
- // Now delete the file. Ignore errors because user may have
- // lost power, and we may be going through this a second time.
- //
- if (!DeleteFile (FileName)) {
- wsprintf (Msg, DELETEFILE_ERROR, FileName, GetLastError());
- SetupLogError (Msg, LogSevError);
- } else {
- wsprintf (Msg, DELETEFILE_SUCCESS, FileName);
- SetupLogError (Msg, LogSevInformation);
- }
- }
- } while (SetupFindNextLine (&ic, &ic));
- }
- SetupCloseInfFile (MigrateInf);
- }
- return ERROR_SUCCESS;
- }