mirror of
https://github.com/reactos/reactos.git
synced 2025-07-29 05:02:51 +00:00
[RAPPS]
- Changed "/SETUP" key to "/INSTALL" - Added support for multiple apps install by "/INSTALL" rapps /INSTALL 7-Zip AkelPad [...] - Added INF based batch install with the "/SETUP" key Works for the full path for the .inf file TODO: detect if user entered the relative path for the inf and correct it - Moved CmdParser to include/unattended.h and unattended.cpp svn path=/branches/GSoC_2017/rapps/; revision=75555
This commit is contained in:
parent
a59f6f7573
commit
14be048f6f
10 changed files with 238 additions and 172 deletions
|
@ -17,6 +17,7 @@ list(APPEND SOURCE
|
|||
misc.cpp
|
||||
settingsdlg.cpp
|
||||
winmain.cpp
|
||||
unattended.cpp
|
||||
include/rapps.h
|
||||
include/available.h
|
||||
include/gui.h
|
||||
|
@ -28,6 +29,7 @@ list(APPEND SOURCE
|
|||
include/resource.h
|
||||
include/rosui.h
|
||||
include/winmain.h
|
||||
include/unattended.h
|
||||
)
|
||||
|
||||
add_definitions(-DUSE_CERT_PINNING)
|
||||
|
@ -36,7 +38,7 @@ add_rc_deps(rapps.rc ${rapps_rc_deps})
|
|||
add_executable(rapps ${SOURCE} rapps.rc)
|
||||
set_module_type(rapps win32gui UNICODE)
|
||||
target_link_libraries(rapps atlnew uuid wine)
|
||||
add_importlibs(rapps advapi32 comctl32 gdi32 wininet user32 shell32 shlwapi ole32 msvcrt kernel32 ntdll)
|
||||
add_importlibs(rapps advapi32 comctl32 gdi32 wininet user32 shell32 shlwapi ole32 msvcrt kernel32 ntdll setupapi)
|
||||
add_pch(rapps include/rapps.h SOURCE)
|
||||
add_dependencies(rapps rappsmsg)
|
||||
add_message_headers(ANSI rappsmsg.mc)
|
||||
|
|
|
@ -379,6 +379,20 @@ const PAPPLICATION_INFO CAvailableApps::FindInfo(const ATL::CStringW& szAppName)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
ATL::CSimpleArray<PAPPLICATION_INFO> CAvailableApps::FindInfoList(const ATL::CSimpleArray<ATL::CStringW> &arrAppsNames)
|
||||
{
|
||||
ATL::CSimpleArray<PAPPLICATION_INFO> result;
|
||||
for (int i = 0; i < arrAppsNames.GetSize(); ++i)
|
||||
{
|
||||
PAPPLICATION_INFO Info = FindInfo(arrAppsNames[i]);
|
||||
if (Info)
|
||||
{
|
||||
result.Add(Info);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const ATL::CStringW & CAvailableApps::GetFolderPath()
|
||||
{
|
||||
return m_szPath;
|
||||
|
@ -409,109 +423,3 @@ const LPCWSTR CAvailableApps::GetCabPathString()
|
|||
return m_szPath.GetString();
|
||||
}
|
||||
// CAvailableApps
|
||||
|
||||
// CConfigParser
|
||||
ATL::CStringW CConfigParser::m_szLocaleID;
|
||||
ATL::CStringW CConfigParser::m_szCachedINISectionLocale;
|
||||
ATL::CStringW CConfigParser::m_szCachedINISectionLocaleNeutral;
|
||||
|
||||
CConfigParser::CConfigParser(const ATL::CStringW& FileName) : szConfigPath(GetINIFullPath(FileName))
|
||||
{
|
||||
// we don't have cached section strings for the current system language, create them, lazy
|
||||
CacheINILocaleLazy();
|
||||
}
|
||||
|
||||
ATL::CStringW CConfigParser::GetINIFullPath(const ATL::CStringW& FileName)
|
||||
{
|
||||
ATL::CStringW szDir;
|
||||
ATL::CStringW szBuffer;
|
||||
|
||||
GetStorageDirectory(szDir);
|
||||
szBuffer.Format(L"%ls\\rapps\\%ls", szDir, FileName);
|
||||
|
||||
return szBuffer;
|
||||
}
|
||||
|
||||
VOID CConfigParser::CacheINILocaleLazy()
|
||||
{
|
||||
if (m_szLocaleID.IsEmpty())
|
||||
{
|
||||
// TODO: Set default locale if call fails
|
||||
// find out what is the current system lang code (e.g. "0a") and append it to SectionLocale
|
||||
GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_ILANGUAGE,
|
||||
m_szLocaleID.GetBuffer(m_cchLocaleSize), m_cchLocaleSize);
|
||||
|
||||
m_szLocaleID.ReleaseBuffer();
|
||||
m_szCachedINISectionLocale = L"Section." + m_szLocaleID;
|
||||
|
||||
// turn "Section.0c0a" into "Section.0a", keeping just the neutral lang part
|
||||
m_szCachedINISectionLocaleNeutral = m_szCachedINISectionLocale + m_szLocaleID.Right(2);
|
||||
}
|
||||
}
|
||||
|
||||
const ATL::CStringW& CConfigParser::GetLocale()
|
||||
{
|
||||
CacheINILocaleLazy();
|
||||
return m_szLocaleID;
|
||||
}
|
||||
|
||||
INT CConfigParser::GetLocaleSize()
|
||||
{
|
||||
return m_cchLocaleSize;
|
||||
}
|
||||
|
||||
UINT CConfigParser::GetString(const ATL::CStringW& KeyName, ATL::CStringW& ResultString)
|
||||
{
|
||||
DWORD dwResult;
|
||||
|
||||
LPWSTR ResultStringBuffer = ResultString.GetBuffer(MAX_PATH);
|
||||
// 1st - find localized strings (e.g. "Section.0c0a")
|
||||
dwResult = GetPrivateProfileStringW(m_szCachedINISectionLocale.GetString(),
|
||||
KeyName.GetString(),
|
||||
NULL,
|
||||
ResultStringBuffer,
|
||||
MAX_PATH,
|
||||
szConfigPath.GetString());
|
||||
|
||||
if (!dwResult)
|
||||
{
|
||||
// 2nd - if they weren't present check for neutral sub-langs/ generic translations (e.g. "Section.0a")
|
||||
dwResult = GetPrivateProfileStringW(m_szCachedINISectionLocaleNeutral.GetString(),
|
||||
KeyName.GetString(),
|
||||
NULL,
|
||||
ResultStringBuffer,
|
||||
MAX_PATH,
|
||||
szConfigPath.GetString());
|
||||
if (!dwResult)
|
||||
{
|
||||
// 3rd - if they weren't present fallback to standard english strings (just "Section")
|
||||
dwResult = GetPrivateProfileStringW(L"Section",
|
||||
KeyName.GetString(),
|
||||
NULL,
|
||||
ResultStringBuffer,
|
||||
MAX_PATH,
|
||||
szConfigPath.GetString());
|
||||
}
|
||||
}
|
||||
|
||||
ResultString.ReleaseBuffer();
|
||||
return (dwResult != 0 ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
UINT CConfigParser::GetInt(const ATL::CStringW& KeyName)
|
||||
{
|
||||
ATL::CStringW Buffer;
|
||||
|
||||
// grab the text version of our entry
|
||||
if (!GetString(KeyName, Buffer))
|
||||
return FALSE;
|
||||
|
||||
if (Buffer.IsEmpty())
|
||||
return FALSE;
|
||||
|
||||
// convert it to an actual integer
|
||||
int result = StrToIntW(Buffer.GetString());
|
||||
|
||||
return (UINT) (result <= 0) ? 0 : result;
|
||||
}
|
||||
// CConfigParser
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <windef.h>
|
||||
#include <atlstr.h>
|
||||
#include <atlsimpcoll.h>
|
||||
#include <atlcoll.h>
|
||||
#include "misc.h"
|
||||
|
||||
/* EnumType flags for EnumAvailableApplications */
|
||||
enum AvailableCategories
|
||||
|
@ -42,31 +44,6 @@ typedef enum LICENSE_TYPE
|
|||
Min = None
|
||||
} *PLICENSE_TYPE;
|
||||
|
||||
class CConfigParser
|
||||
{
|
||||
// Locale names cache
|
||||
const static INT m_cchLocaleSize = 5;
|
||||
|
||||
static ATL::CStringW m_szLocaleID;
|
||||
static ATL::CStringW m_szCachedINISectionLocale;
|
||||
static ATL::CStringW m_szCachedINISectionLocaleNeutral;
|
||||
|
||||
const LPCWSTR STR_VERSION_CURRENT = L"CURRENT";
|
||||
const ATL::CStringW szConfigPath;
|
||||
|
||||
static ATL::CStringW GetINIFullPath(const ATL::CStringW& FileName);
|
||||
static VOID CacheINILocaleLazy();
|
||||
|
||||
public:
|
||||
static const ATL::CStringW& GetLocale();
|
||||
static INT CConfigParser::GetLocaleSize();
|
||||
|
||||
CConfigParser(const ATL::CStringW& FileName);
|
||||
|
||||
UINT GetString(const ATL::CStringW& KeyName, ATL::CStringW& ResultString);
|
||||
UINT GetInt(const ATL::CStringW& KeyName);
|
||||
};
|
||||
|
||||
typedef struct APPLICATION_INFO
|
||||
{
|
||||
INT Category;
|
||||
|
@ -142,6 +119,7 @@ public:
|
|||
BOOL UpdateAppsDB();
|
||||
BOOL EnumAvailableApplications(INT EnumType, AVAILENUMPROC lpEnumProc);
|
||||
const PAPPLICATION_INFO FindInfo(const ATL::CStringW& szAppName);
|
||||
ATL::CSimpleArray<PAPPLICATION_INFO> FindInfoList(const ATL::CSimpleArray<ATL::CStringW> &arrAppsNames);
|
||||
const ATL::CStringW& GetFolderPath();
|
||||
const ATL::CStringW& GetAppPath();
|
||||
const ATL::CStringW& GetCabPath();
|
||||
|
|
|
@ -25,7 +25,7 @@ public:
|
|||
DWORD_PTR dwRefData);
|
||||
|
||||
static DWORD WINAPI ThreadFunc(LPVOID Context);
|
||||
static BOOL DownloadListOfApplications(const ATL::CSimpleArray<PAPPLICATION_INFO>& AppsList);
|
||||
static BOOL DownloadListOfApplications(const ATL::CSimpleArray<PAPPLICATION_INFO>& AppsList, BOOL modal = FALSE);
|
||||
static BOOL DownloadApplication(PAPPLICATION_INFO pAppInfo, BOOL modal = FALSE);
|
||||
static VOID DownloadApplicationsDB(LPCWSTR lpUrl);
|
||||
static VOID LaunchDownloadDialog(BOOL);
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
#include <windef.h>
|
||||
#include <atlstr.h>
|
||||
|
||||
int GetWindowWidth(HWND hwnd);
|
||||
int GetWindowHeight(HWND hwnd);
|
||||
int GetClientWindowWidth(HWND hwnd);
|
||||
int GetClientWindowHeight(HWND hwnd);
|
||||
INT GetWindowWidth(HWND hwnd);
|
||||
INT GetWindowHeight(HWND hwnd);
|
||||
INT GetClientWindowWidth(HWND hwnd);
|
||||
INT GetClientWindowHeight(HWND hwnd);
|
||||
|
||||
VOID CopyTextToClipboard(LPCWSTR lpszText);
|
||||
VOID SetWelcomeText(VOID);
|
||||
|
@ -19,3 +19,27 @@ VOID InitLogs(VOID);
|
|||
VOID FreeLogs(VOID);
|
||||
BOOL WriteLogMessage(WORD wType, DWORD dwEventID, LPCWSTR lpMsg);
|
||||
BOOL GetInstalledVersion(ATL::CStringW *pszVersion, const ATL::CStringW &szRegName);
|
||||
|
||||
class CConfigParser
|
||||
{
|
||||
// Locale names cache
|
||||
const static INT m_cchLocaleSize = 5;
|
||||
|
||||
static ATL::CStringW m_szLocaleID;
|
||||
static ATL::CStringW m_szCachedINISectionLocale;
|
||||
static ATL::CStringW m_szCachedINISectionLocaleNeutral;
|
||||
|
||||
const ATL::CStringW szConfigPath;
|
||||
|
||||
static ATL::CStringW GetINIFullPath(const ATL::CStringW& FileName);
|
||||
static VOID CacheINILocaleLazy();
|
||||
|
||||
public:
|
||||
static const ATL::CStringW& GetLocale();
|
||||
static INT CConfigParser::GetLocaleSize();
|
||||
|
||||
CConfigParser(const ATL::CStringW& FileName);
|
||||
|
||||
UINT GetString(const ATL::CStringW& KeyName, ATL::CStringW& ResultString);
|
||||
UINT GetInt(const ATL::CStringW& KeyName);
|
||||
};
|
8
reactos/base/applications/rapps/include/unattended.h
Normal file
8
reactos/base/applications/rapps/include/unattended.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#include "windef.h"
|
||||
|
||||
#define CMD_KEY_INSTALL L"/INSTALL"
|
||||
#define CMD_KEY_SETUP L"/SETUP"
|
||||
|
||||
// return TRUE if the SETUP key was valid
|
||||
BOOL CmdParser(LPWSTR lpCmdLine);
|
|
@ -793,7 +793,7 @@ end:
|
|||
return 0;
|
||||
}
|
||||
|
||||
BOOL CDownloadManager::DownloadListOfApplications(const ATL::CSimpleArray<PAPPLICATION_INFO>& AppsList)
|
||||
BOOL CDownloadManager::DownloadListOfApplications(const ATL::CSimpleArray<PAPPLICATION_INFO>& AppsList, BOOL modal)
|
||||
{
|
||||
if (AppsList.GetSize() == 0)
|
||||
{
|
||||
|
@ -804,7 +804,7 @@ BOOL CDownloadManager::DownloadListOfApplications(const ATL::CSimpleArray<PAPPLI
|
|||
AppsToInstallList = AppsList;
|
||||
|
||||
// Create a dialog and issue a download process
|
||||
LaunchDownloadDialog(FALSE);
|
||||
LaunchDownloadDialog(modal);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -397,3 +397,109 @@ BOOL GetInstalledVersion(ATL::CStringW *pszVersion, const ATL::CStringW &szRegNa
|
|||
|| GetInstalledVersion_WowUser(pszVersion, szRegName, TRUE, KEY_WOW64_64KEY)
|
||||
|| GetInstalledVersion_WowUser(pszVersion, szRegName, FALSE, KEY_WOW64_64KEY)));
|
||||
}
|
||||
|
||||
// CConfigParser
|
||||
ATL::CStringW CConfigParser::m_szLocaleID;
|
||||
ATL::CStringW CConfigParser::m_szCachedINISectionLocale;
|
||||
ATL::CStringW CConfigParser::m_szCachedINISectionLocaleNeutral;
|
||||
|
||||
CConfigParser::CConfigParser(const ATL::CStringW& FileName) : szConfigPath(GetINIFullPath(FileName))
|
||||
{
|
||||
// we don't have cached section strings for the current system language, create them, lazy
|
||||
CacheINILocaleLazy();
|
||||
}
|
||||
|
||||
ATL::CStringW CConfigParser::GetINIFullPath(const ATL::CStringW& FileName)
|
||||
{
|
||||
ATL::CStringW szDir;
|
||||
ATL::CStringW szBuffer;
|
||||
|
||||
GetStorageDirectory(szDir);
|
||||
szBuffer.Format(L"%ls\\rapps\\%ls", szDir, FileName);
|
||||
|
||||
return szBuffer;
|
||||
}
|
||||
|
||||
VOID CConfigParser::CacheINILocaleLazy()
|
||||
{
|
||||
if (m_szLocaleID.IsEmpty())
|
||||
{
|
||||
// TODO: Set default locale if call fails
|
||||
// find out what is the current system lang code (e.g. "0a") and append it to SectionLocale
|
||||
GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_ILANGUAGE,
|
||||
m_szLocaleID.GetBuffer(m_cchLocaleSize), m_cchLocaleSize);
|
||||
|
||||
m_szLocaleID.ReleaseBuffer();
|
||||
m_szCachedINISectionLocale = L"Section." + m_szLocaleID;
|
||||
|
||||
// turn "Section.0c0a" into "Section.0a", keeping just the neutral lang part
|
||||
m_szCachedINISectionLocaleNeutral = m_szCachedINISectionLocale + m_szLocaleID.Right(2);
|
||||
}
|
||||
}
|
||||
|
||||
const ATL::CStringW& CConfigParser::GetLocale()
|
||||
{
|
||||
CacheINILocaleLazy();
|
||||
return m_szLocaleID;
|
||||
}
|
||||
|
||||
INT CConfigParser::GetLocaleSize()
|
||||
{
|
||||
return m_cchLocaleSize;
|
||||
}
|
||||
|
||||
UINT CConfigParser::GetString(const ATL::CStringW& KeyName, ATL::CStringW& ResultString)
|
||||
{
|
||||
DWORD dwResult;
|
||||
|
||||
LPWSTR ResultStringBuffer = ResultString.GetBuffer(MAX_PATH);
|
||||
// 1st - find localized strings (e.g. "Section.0c0a")
|
||||
dwResult = GetPrivateProfileStringW(m_szCachedINISectionLocale.GetString(),
|
||||
KeyName.GetString(),
|
||||
NULL,
|
||||
ResultStringBuffer,
|
||||
MAX_PATH,
|
||||
szConfigPath.GetString());
|
||||
|
||||
if (!dwResult)
|
||||
{
|
||||
// 2nd - if they weren't present check for neutral sub-langs/ generic translations (e.g. "Section.0a")
|
||||
dwResult = GetPrivateProfileStringW(m_szCachedINISectionLocaleNeutral.GetString(),
|
||||
KeyName.GetString(),
|
||||
NULL,
|
||||
ResultStringBuffer,
|
||||
MAX_PATH,
|
||||
szConfigPath.GetString());
|
||||
if (!dwResult)
|
||||
{
|
||||
// 3rd - if they weren't present fallback to standard english strings (just "Section")
|
||||
dwResult = GetPrivateProfileStringW(L"Section",
|
||||
KeyName.GetString(),
|
||||
NULL,
|
||||
ResultStringBuffer,
|
||||
MAX_PATH,
|
||||
szConfigPath.GetString());
|
||||
}
|
||||
}
|
||||
|
||||
ResultString.ReleaseBuffer();
|
||||
return (dwResult != 0 ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
UINT CConfigParser::GetInt(const ATL::CStringW& KeyName)
|
||||
{
|
||||
ATL::CStringW Buffer;
|
||||
|
||||
// grab the text version of our entry
|
||||
if (!GetString(KeyName, Buffer))
|
||||
return FALSE;
|
||||
|
||||
if (Buffer.IsEmpty())
|
||||
return FALSE;
|
||||
|
||||
// convert it to an actual integer
|
||||
int result = StrToIntW(Buffer.GetString());
|
||||
|
||||
return (UINT) (result <= 0) ? 0 : result;
|
||||
}
|
||||
// CConfigParser
|
||||
|
|
70
reactos/base/applications/rapps/unattended.cpp
Normal file
70
reactos/base/applications/rapps/unattended.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
#include "unattended.h"
|
||||
#include "defines.h"
|
||||
#include "available.h"
|
||||
#include "dialogs.h"
|
||||
|
||||
#include "setupapi.h"
|
||||
|
||||
BOOL CmdParser(LPWSTR lpCmdLine)
|
||||
{
|
||||
INT argc;
|
||||
LPWSTR* argv = CommandLineToArgvW(lpCmdLine, &argc);
|
||||
ATL::CString szName;
|
||||
|
||||
if (!argv || argc < 2)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Setup key - single app expected
|
||||
// TODO: add multiple apps
|
||||
// TODO: use DB filenames as names because they're shorter
|
||||
|
||||
// app setup
|
||||
ATL::CSimpleArray<ATL::CStringW> arrNames;
|
||||
if (!StrCmpW(argv[0], CMD_KEY_INSTALL))
|
||||
{
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
arrNames.Add(argv[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!StrCmpW(argv[0], CMD_KEY_SETUP))
|
||||
{
|
||||
//TODO: inf file loading
|
||||
HINF InfHandle = SetupOpenInfFileW(argv[1], NULL, INF_STYLE_WIN4, NULL);
|
||||
if (InfHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
INFCONTEXT Context;
|
||||
if (!SetupFindFirstLineW(InfHandle, L"RAPPS", L"Install", &Context))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WCHAR szName[MAX_PATH];
|
||||
do
|
||||
{
|
||||
if (SetupGetStringFieldW(&Context, 1, szName, MAX_PATH, NULL))
|
||||
{
|
||||
arrNames.Add(szName);
|
||||
}
|
||||
}
|
||||
while (SetupFindNextLine(&Context, &Context));
|
||||
}
|
||||
|
||||
CAvailableApps apps;
|
||||
apps.EnumAvailableApplications(ENUM_ALL_AVAILABLE, NULL);
|
||||
ATL::CSimpleArray<PAPPLICATION_INFO> arrAppInfo = apps.FindInfoList(arrNames);
|
||||
if (arrAppInfo.GetSize() > 0)
|
||||
{
|
||||
CDownloadManager::DownloadListOfApplications(arrAppInfo, TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
|
@ -8,12 +8,10 @@
|
|||
* Alexander Shaposhnikov (chaez.san@gmail.com)
|
||||
*/
|
||||
#include "defines.h"
|
||||
|
||||
#include "rapps.h"
|
||||
#include "unattended.h"
|
||||
|
||||
#include <atlbase.h>
|
||||
#include <atlcom.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
HWND hMainWnd;
|
||||
HINSTANCE hInst;
|
||||
|
@ -132,39 +130,11 @@ VOID SaveSettings(HWND hwnd)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#define CMD_KEY_SETUP L"/SETUP"
|
||||
|
||||
// return TRUE if the SETUP key was valid
|
||||
BOOL CmdParser(LPWSTR lpCmdLine)
|
||||
{
|
||||
INT argc;
|
||||
LPWSTR* argv = CommandLineToArgvW(lpCmdLine, &argc);
|
||||
CAvailableApps apps;
|
||||
PAPPLICATION_INFO appInfo;
|
||||
ATL::CString szName;
|
||||
|
||||
if (!argv || argc < 2 || StrCmpW(argv[0], CMD_KEY_SETUP))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
apps.EnumAvailableApplications(ENUM_ALL_AVAILABLE, NULL);
|
||||
appInfo = apps.FindInfo(argv[1]);
|
||||
if (appInfo)
|
||||
{
|
||||
CDownloadManager::DownloadApplication(appInfo, TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
|
||||
{
|
||||
LPCWSTR szWindowClass = L"ROSAPPMGR";
|
||||
HANDLE hMutex = NULL;
|
||||
HACCEL KeyBrd = NULL;
|
||||
HANDLE hMutex;
|
||||
HACCEL KeyBrd;
|
||||
MSG Msg;
|
||||
|
||||
InitializeAtlModule(hInstance, TRUE);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue