chore: initial commit (extracted from Launchers monorepo)
Plugin: ns7zip v2.0.0 Architectures: x86-ansi, x86-unicode, amd64-unicode License: LGPL-2.1-or-later
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
// Windows/COM.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
/*
|
||||
|
||||
#include "COM.h"
|
||||
#include "../Common/StringConvert.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NCOM {
|
||||
|
||||
// CoInitialize (NULL); must be called!
|
||||
|
||||
UString GUIDToStringW(REFGUID guid)
|
||||
{
|
||||
UString s;
|
||||
const unsigned kSize = 48;
|
||||
StringFromGUID2(guid, s.GetBuf(kSize), kSize);
|
||||
s.ReleaseBuf_CalcLen(kSize);
|
||||
return s;
|
||||
}
|
||||
|
||||
AString GUIDToStringA(REFGUID guid)
|
||||
{
|
||||
return UnicodeStringToMultiByte(GUIDToStringW(guid));
|
||||
}
|
||||
|
||||
HRESULT StringToGUIDW(const wchar_t *string, GUID &classID)
|
||||
{
|
||||
return CLSIDFromString((wchar_t *)string, &classID);
|
||||
}
|
||||
|
||||
HRESULT StringToGUIDA(const char *string, GUID &classID)
|
||||
{
|
||||
return StringToGUIDW(MultiByteToUnicodeString(string), classID);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,86 @@
|
||||
// Windows/COM.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_COM_H
|
||||
#define ZIP7_INC_WINDOWS_COM_H
|
||||
|
||||
// #include "../Common/MyString.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NCOM {
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
class CComInitializer
|
||||
{
|
||||
public:
|
||||
CComInitializer()
|
||||
{
|
||||
#ifdef UNDER_CE
|
||||
CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
#else
|
||||
// it's single thread. Do we need multithread?
|
||||
CoInitialize(NULL);
|
||||
#endif
|
||||
}
|
||||
~CComInitializer() { CoUninitialize(); }
|
||||
};
|
||||
|
||||
/*
|
||||
class CStgMedium2
|
||||
{
|
||||
STGMEDIUM _object;
|
||||
bool _mustBeReleased;
|
||||
public:
|
||||
CStgMedium2(): _mustBeReleased(false) {}
|
||||
~CStgMedium2() { Free(); }
|
||||
void Free()
|
||||
{
|
||||
if (_mustBeReleased)
|
||||
ReleaseStgMedium(&_object);
|
||||
_mustBeReleased = false;
|
||||
}
|
||||
const STGMEDIUM* operator->() const { return &_object;}
|
||||
STGMEDIUM* operator->() { return &_object;}
|
||||
STGMEDIUM* operator&() { return &_object; }
|
||||
};
|
||||
*/
|
||||
|
||||
struct CStgMedium: public STGMEDIUM
|
||||
{
|
||||
CStgMedium()
|
||||
{
|
||||
tymed = TYMED_NULL; // 0
|
||||
hGlobal = NULL;
|
||||
pUnkForRelease = NULL;
|
||||
}
|
||||
~CStgMedium()
|
||||
{
|
||||
ReleaseStgMedium(this);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
//////////////////////////////////
|
||||
// GUID <--> String Conversions
|
||||
UString GUIDToStringW(REFGUID guid);
|
||||
AString GUIDToStringA(REFGUID guid);
|
||||
#ifdef UNICODE
|
||||
#define GUIDToString GUIDToStringW
|
||||
#else
|
||||
#define GUIDToString GUIDToStringA
|
||||
#endif
|
||||
|
||||
HRESULT StringToGUIDW(const wchar_t *string, GUID &classID);
|
||||
HRESULT StringToGUIDA(const char *string, GUID &classID);
|
||||
#ifdef UNICODE
|
||||
#define StringToGUID StringToGUIDW
|
||||
#else
|
||||
#define StringToGUID StringToGUIDA
|
||||
#endif
|
||||
*/
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,130 @@
|
||||
// Windows/Clipboard.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#ifdef UNDER_CE
|
||||
#include <winuserm.h>
|
||||
#endif
|
||||
|
||||
#include "../Common/StringConvert.h"
|
||||
|
||||
#include "Clipboard.h"
|
||||
#include "Defs.h"
|
||||
#include "MemoryGlobal.h"
|
||||
#include "Shell.h"
|
||||
|
||||
namespace NWindows {
|
||||
|
||||
bool CClipboard::Open(HWND wndNewOwner) throw()
|
||||
{
|
||||
m_Open = BOOLToBool(::OpenClipboard(wndNewOwner));
|
||||
return m_Open;
|
||||
}
|
||||
|
||||
bool CClipboard::Close() throw()
|
||||
{
|
||||
if (!m_Open)
|
||||
return true;
|
||||
m_Open = !BOOLToBool(CloseClipboard());
|
||||
return !m_Open;
|
||||
}
|
||||
|
||||
bool ClipboardIsFormatAvailableHDROP()
|
||||
{
|
||||
return BOOLToBool(IsClipboardFormatAvailable(CF_HDROP));
|
||||
}
|
||||
|
||||
/*
|
||||
bool ClipboardGetTextString(AString &s)
|
||||
{
|
||||
s.Empty();
|
||||
if (!IsClipboardFormatAvailable(CF_TEXT))
|
||||
return false;
|
||||
CClipboard clipboard;
|
||||
|
||||
if (!clipboard.Open(NULL))
|
||||
return false;
|
||||
|
||||
HGLOBAL h = ::GetClipboardData(CF_TEXT);
|
||||
if (h != NULL)
|
||||
{
|
||||
NMemory::CGlobalLock globalLock(h);
|
||||
const char *p = (const char *)globalLock.GetPointer();
|
||||
if (p != NULL)
|
||||
{
|
||||
s = p;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
bool ClipboardGetFileNames(UStringVector &names)
|
||||
{
|
||||
names.Clear();
|
||||
if (!IsClipboardFormatAvailable(CF_HDROP))
|
||||
return false;
|
||||
CClipboard clipboard;
|
||||
|
||||
if (!clipboard.Open(NULL))
|
||||
return false;
|
||||
|
||||
HGLOBAL h = ::GetClipboardData(CF_HDROP);
|
||||
if (h != NULL)
|
||||
{
|
||||
NMemory::CGlobalLock globalLock(h);
|
||||
void *p = (void *)globalLock.GetPointer();
|
||||
if (p != NULL)
|
||||
{
|
||||
NShell::CDrop drop(false);
|
||||
drop.Attach((HDROP)p);
|
||||
drop.QueryFileNames(names);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
static bool ClipboardSetData(UINT uFormat, const void *data, size_t size) throw()
|
||||
{
|
||||
NMemory::CGlobal global;
|
||||
if (!global.Alloc(GMEM_DDESHARE | GMEM_MOVEABLE, size))
|
||||
return false;
|
||||
{
|
||||
NMemory::CGlobalLock globalLock(global);
|
||||
LPVOID p = globalLock.GetPointer();
|
||||
if (!p)
|
||||
return false;
|
||||
memcpy(p, data, size);
|
||||
}
|
||||
if (::SetClipboardData(uFormat, global) == NULL)
|
||||
return false;
|
||||
global.Detach();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClipboardSetText(HWND owner, const UString &s)
|
||||
{
|
||||
CClipboard clipboard;
|
||||
if (!clipboard.Open(owner))
|
||||
return false;
|
||||
if (!::EmptyClipboard())
|
||||
return false;
|
||||
|
||||
bool res;
|
||||
res = ClipboardSetData(CF_UNICODETEXT, (const wchar_t *)s, (s.Len() + 1) * sizeof(wchar_t));
|
||||
#ifndef _UNICODE
|
||||
AString a (UnicodeStringToMultiByte(s, CP_ACP));
|
||||
if (ClipboardSetData(CF_TEXT, (const char *)a, (a.Len() + 1) * sizeof(char)))
|
||||
res = true;
|
||||
a = UnicodeStringToMultiByte(s, CP_OEMCP);
|
||||
if (ClipboardSetData(CF_OEMTEXT, (const char *)a, (a.Len() + 1) * sizeof(char)))
|
||||
res = true;
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Windows/Clipboard.h
|
||||
|
||||
#ifndef ZIP7_INC_CLIPBOARD_H
|
||||
#define ZIP7_INC_CLIPBOARD_H
|
||||
|
||||
#include "../Common/MyString.h"
|
||||
|
||||
namespace NWindows {
|
||||
|
||||
class CClipboard
|
||||
{
|
||||
bool m_Open;
|
||||
public:
|
||||
CClipboard(): m_Open(false) {}
|
||||
~CClipboard() { Close(); }
|
||||
bool Open(HWND wndNewOwner) throw();
|
||||
bool Close() throw();
|
||||
};
|
||||
|
||||
bool ClipboardIsFormatAvailableHDROP();
|
||||
|
||||
// bool ClipboardGetFileNames(UStringVector &names);
|
||||
// bool ClipboardGetTextString(AString &s);
|
||||
bool ClipboardSetText(HWND owner, const UString &s);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,269 @@
|
||||
// Windows/CommonDialog.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/MyBuffer.h"
|
||||
|
||||
#ifdef UNDER_CE
|
||||
#include <commdlg.h>
|
||||
#endif
|
||||
|
||||
#ifndef _UNICODE
|
||||
#include "../Common/StringConvert.h"
|
||||
#endif
|
||||
|
||||
#include "CommonDialog.h"
|
||||
#include "Defs.h"
|
||||
// #include "FileDir.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
|
||||
namespace NWindows {
|
||||
|
||||
/*
|
||||
GetSaveFileName()
|
||||
GetOpenFileName()
|
||||
OPENFILENAME
|
||||
|
||||
(lpstrInitialDir) : the initial directory.
|
||||
DOCs: the algorithm for selecting the initial directory varies on different platforms:
|
||||
{
|
||||
Win2000/XP/Vista:
|
||||
1. If lpstrFile contains a path, that path is the initial directory.
|
||||
2. Otherwise, lpstrInitialDir specifies the initial directory.
|
||||
|
||||
Win7:
|
||||
If lpstrInitialDir has the same value as was passed the first time
|
||||
the application used an Open or Save As dialog box, the path
|
||||
most recently selected by the user is used as the initial directory.
|
||||
}
|
||||
|
||||
Win10:
|
||||
in:
|
||||
function supports (lpstrInitialDir) path with super prefix "\\\\?\\"
|
||||
function supports (lpstrInitialDir) path with long path
|
||||
function doesn't support absolute (lpstrFile) path with super prefix "\\\\?\\"
|
||||
function doesn't support absolute (lpstrFile) path with long path
|
||||
out: the path with super prefix "\\\\?\\" will be returned, if selected path is long
|
||||
|
||||
WinXP-64 and Win10: if no filters, the system shows all files.
|
||||
but DOCs say: If all three members are zero or NULL,
|
||||
the system does not use any filters and does not
|
||||
show any files in the file list control of the dialog box.
|
||||
|
||||
in Win7+: GetOpenFileName() and GetSaveFileName()
|
||||
do not support pstrCustomFilter feature anymore
|
||||
*/
|
||||
|
||||
#ifdef UNDER_CE
|
||||
#define MY_OFN_PROJECT 0x00400000
|
||||
#define MY_OFN_SHOW_ALL 0x01000000
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
structures
|
||||
OPENFILENAMEW
|
||||
OPENFILENAMEA
|
||||
contain additional members:
|
||||
#if (_WIN32_WINNT >= 0x0500)
|
||||
void *pvReserved;
|
||||
DWORD dwReserved;
|
||||
DWORD FlagsEx;
|
||||
#endif
|
||||
|
||||
If we compile the source code with (_WIN32_WINNT >= 0x0500), some functions
|
||||
will not work at NT 4.0, if we use sizeof(OPENFILENAME).
|
||||
We try to use reduced structure OPENFILENAME_NT4.
|
||||
*/
|
||||
|
||||
// #if defined(_WIN64) || (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500)
|
||||
#if defined(__GNUC__) && (__GNUC__ <= 9) || defined(Z7_OLD_WIN_SDK)
|
||||
#ifndef _UNICODE
|
||||
#define my_compatib_OPENFILENAMEA OPENFILENAMEA
|
||||
#endif
|
||||
#define my_compatib_OPENFILENAMEW OPENFILENAMEW
|
||||
|
||||
// MinGW doesn't support some required macros. So we define them here:
|
||||
#ifndef CDSIZEOF_STRUCT
|
||||
#define CDSIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member))
|
||||
#endif
|
||||
#ifndef _UNICODE
|
||||
#ifndef OPENFILENAME_SIZE_VERSION_400A
|
||||
#define OPENFILENAME_SIZE_VERSION_400A CDSIZEOF_STRUCT(OPENFILENAMEA,lpTemplateName)
|
||||
#endif
|
||||
#endif
|
||||
#ifndef OPENFILENAME_SIZE_VERSION_400W
|
||||
#define OPENFILENAME_SIZE_VERSION_400W CDSIZEOF_STRUCT(OPENFILENAMEW,lpTemplateName)
|
||||
#endif
|
||||
|
||||
#ifndef _UNICODE
|
||||
#define my_compatib_OPENFILENAMEA_size OPENFILENAME_SIZE_VERSION_400A
|
||||
#endif
|
||||
#define my_compatib_OPENFILENAMEW_size OPENFILENAME_SIZE_VERSION_400W
|
||||
#else
|
||||
#ifndef _UNICODE
|
||||
#define my_compatib_OPENFILENAMEA OPENFILENAME_NT4A
|
||||
#define my_compatib_OPENFILENAMEA_size sizeof(my_compatib_OPENFILENAMEA)
|
||||
#endif
|
||||
#define my_compatib_OPENFILENAMEW OPENFILENAME_NT4W
|
||||
#define my_compatib_OPENFILENAMEW_size sizeof(my_compatib_OPENFILENAMEW)
|
||||
#endif
|
||||
/*
|
||||
#elif defined(UNDER_CE) || defined(_WIN64) || (_WIN32_WINNT < 0x0500)
|
||||
// || !defined(WINVER)
|
||||
#ifndef _UNICODE
|
||||
#define my_compatib_OPENFILENAMEA OPENFILENAMEA
|
||||
#define my_compatib_OPENFILENAMEA_size sizeof(OPENFILENAMEA)
|
||||
#endif
|
||||
#define my_compatib_OPENFILENAMEW OPENFILENAMEW
|
||||
#define my_compatib_OPENFILENAMEW_size sizeof(OPENFILENAMEW)
|
||||
#else
|
||||
|
||||
#endif
|
||||
*/
|
||||
|
||||
#ifndef _UNICODE
|
||||
#define CONV_U_To_A(dest, src, temp) AString temp; if (src) { temp = GetSystemString(src); dest = temp; }
|
||||
#endif
|
||||
|
||||
bool CCommonDialogInfo::CommonDlg_BrowseForFile(LPCWSTR lpstrInitialDir, const UStringVector &filters)
|
||||
{
|
||||
/* GetSaveFileName() and GetOpenFileName() could change current dir,
|
||||
if OFN_NOCHANGEDIR is not used.
|
||||
We can restore current dir manually, if it's required.
|
||||
22.02: we use OFN_NOCHANGEDIR. So we don't need to restore current dir manually. */
|
||||
// NFile::NDir::CCurrentDirRestorer curDirRestorer;
|
||||
|
||||
#ifndef _UNICODE
|
||||
if (!g_IsNT)
|
||||
{
|
||||
AString tempPath;
|
||||
AStringVector f;
|
||||
unsigned i;
|
||||
for (i = 0; i < filters.Size(); i++)
|
||||
f.Add(GetSystemString(filters[i]));
|
||||
unsigned size = f.Size() + 1;
|
||||
for (i = 0; i < f.Size(); i++)
|
||||
size += f[i].Len();
|
||||
CObjArray<char> filterBuf(size);
|
||||
// memset(filterBuf, 0, size * sizeof(char));
|
||||
{
|
||||
char *dest = filterBuf;
|
||||
for (i = 0; i < f.Size(); i++)
|
||||
{
|
||||
const AString &s = f[i];
|
||||
MyStringCopy(dest, s);
|
||||
dest += s.Len() + 1;
|
||||
}
|
||||
*dest = 0;
|
||||
}
|
||||
my_compatib_OPENFILENAMEA p;
|
||||
memset(&p, 0, sizeof(p));
|
||||
p.lStructSize = my_compatib_OPENFILENAMEA_size;
|
||||
p.hwndOwner = hwndOwner;
|
||||
if (size > 1)
|
||||
{
|
||||
p.lpstrFilter = filterBuf;
|
||||
p.nFilterIndex = (DWORD)(FilterIndex + 1);
|
||||
}
|
||||
|
||||
CONV_U_To_A(p.lpstrInitialDir, lpstrInitialDir, initialDir_a)
|
||||
CONV_U_To_A(p.lpstrTitle, lpstrTitle, title_a)
|
||||
|
||||
const AString filePath_a = GetSystemString(FilePath);
|
||||
const unsigned bufSize = MAX_PATH * 8
|
||||
+ filePath_a.Len()
|
||||
+ initialDir_a.Len();
|
||||
p.nMaxFile = bufSize;
|
||||
p.lpstrFile = tempPath.GetBuf(bufSize);
|
||||
MyStringCopy(p.lpstrFile, filePath_a);
|
||||
p.Flags =
|
||||
OFN_EXPLORER
|
||||
| OFN_HIDEREADONLY
|
||||
| OFN_NOCHANGEDIR;
|
||||
const BOOL b = SaveMode ?
|
||||
::GetSaveFileNameA((LPOPENFILENAMEA)(void *)&p) :
|
||||
::GetOpenFileNameA((LPOPENFILENAMEA)(void *)&p);
|
||||
if (!b)
|
||||
return false;
|
||||
{
|
||||
tempPath.ReleaseBuf_CalcLen(bufSize);
|
||||
FilePath = GetUnicodeString(tempPath);
|
||||
FilterIndex = (int)p.nFilterIndex - 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
UString tempPath;
|
||||
unsigned size = filters.Size() + 1;
|
||||
unsigned i;
|
||||
for (i = 0; i < filters.Size(); i++)
|
||||
size += filters[i].Len();
|
||||
CObjArray<wchar_t> filterBuf(size);
|
||||
// memset(filterBuf, 0, size * sizeof(wchar_t));
|
||||
{
|
||||
wchar_t *dest = filterBuf;
|
||||
for (i = 0; i < filters.Size(); i++)
|
||||
{
|
||||
const UString &s = filters[i];
|
||||
MyStringCopy(dest, s);
|
||||
dest += s.Len() + 1;
|
||||
}
|
||||
*dest = 0;
|
||||
// if ((unsigned)(dest + 1 - filterBuf) != size) return false;
|
||||
}
|
||||
my_compatib_OPENFILENAMEW p;
|
||||
memset(&p, 0, sizeof(p));
|
||||
p.lStructSize = my_compatib_OPENFILENAMEW_size;
|
||||
p.hwndOwner = hwndOwner;
|
||||
if (size > 1)
|
||||
{
|
||||
p.lpstrFilter = filterBuf;
|
||||
p.nFilterIndex = (DWORD)(FilterIndex + 1);
|
||||
}
|
||||
unsigned bufSize = MAX_PATH * 8 + FilePath.Len();
|
||||
if (lpstrInitialDir)
|
||||
{
|
||||
p.lpstrInitialDir = lpstrInitialDir;
|
||||
bufSize += MyStringLen(lpstrInitialDir);
|
||||
}
|
||||
p.nMaxFile = bufSize;
|
||||
p.lpstrFile = tempPath.GetBuf(bufSize);
|
||||
MyStringCopy(p.lpstrFile, FilePath);
|
||||
p.lpstrTitle = lpstrTitle;
|
||||
p.Flags =
|
||||
OFN_EXPLORER
|
||||
| OFN_HIDEREADONLY
|
||||
| OFN_NOCHANGEDIR
|
||||
// | OFN_FORCESHOWHIDDEN // Win10 shows hidden items even without this flag
|
||||
// | OFN_PATHMUSTEXIST
|
||||
#ifdef UNDER_CE
|
||||
| (OpenFolderMode ? (MY_OFN_PROJECT | MY_OFN_SHOW_ALL) : 0)
|
||||
#endif
|
||||
;
|
||||
const BOOL b = SaveMode ?
|
||||
::GetSaveFileNameW((LPOPENFILENAMEW)(void *)&p) :
|
||||
::GetOpenFileNameW((LPOPENFILENAMEW)(void *)&p);
|
||||
/* DOCs: lpstrFile :
|
||||
if the buffer is too small, then:
|
||||
- the function returns FALSE
|
||||
- the CommDlgExtendedError() returns FNERR_BUFFERTOOSMALL
|
||||
- the first two bytes of the lpstrFile buffer contain the
|
||||
required size, in bytes or characters. */
|
||||
if (!b)
|
||||
return false;
|
||||
{
|
||||
tempPath.ReleaseBuf_CalcLen(bufSize);
|
||||
FilePath = tempPath;
|
||||
FilterIndex = (int)p.nFilterIndex - 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// Windows/CommonDialog.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_COMMON_DIALOG_H
|
||||
#define ZIP7_INC_WINDOWS_COMMON_DIALOG_H
|
||||
|
||||
#include "../Common/MyString.h"
|
||||
|
||||
namespace NWindows {
|
||||
|
||||
struct CCommonDialogInfo
|
||||
{
|
||||
/* (FilterIndex == -1) means no selected filter.
|
||||
and (-1) also is reserved for unsupported custom filter.
|
||||
if (FilterIndex >= 0), then FilterIndex is index of filter */
|
||||
int FilterIndex; // [in / out]
|
||||
bool SaveMode;
|
||||
#ifdef UNDER_CE
|
||||
bool OpenFolderMode;
|
||||
#endif
|
||||
HWND hwndOwner;
|
||||
// LPCWSTR lpstrInitialDir;
|
||||
LPCWSTR lpstrTitle;
|
||||
UString FilePath; // [in / out]
|
||||
|
||||
CCommonDialogInfo()
|
||||
{
|
||||
FilterIndex = -1;
|
||||
SaveMode = false;
|
||||
#ifdef UNDER_CE
|
||||
OpenFolderMode = false;
|
||||
#endif
|
||||
hwndOwner = NULL;
|
||||
// lpstrInitialDir = NULL;
|
||||
lpstrTitle = NULL;
|
||||
}
|
||||
|
||||
/* (filters) : 2 sequential vector strings (Description, Masks) represent each filter */
|
||||
bool CommonDlg_BrowseForFile(LPCWSTR lpstrInitialDir, const UStringVector &filters);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
// Windows/Console.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Console.h"
|
||||
|
||||
namespace NWindows{
|
||||
namespace NConsole{
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,52 @@
|
||||
// Windows/Console.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_CONSOLE_H
|
||||
#define ZIP7_INC_WINDOWS_CONSOLE_H
|
||||
|
||||
#include "Defs.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NConsole {
|
||||
|
||||
class CBase
|
||||
{
|
||||
protected:
|
||||
HANDLE m_Object;
|
||||
public:
|
||||
void Attach(HANDLE handle) { m_Object = handle; }
|
||||
bool GetMode(DWORD &mode)
|
||||
{ return BOOLToBool(::GetConsoleMode(m_Object, &mode)); }
|
||||
bool SetMode(DWORD mode)
|
||||
{ return BOOLToBool(::SetConsoleMode(m_Object, mode)); }
|
||||
};
|
||||
|
||||
class CIn: public CBase
|
||||
{
|
||||
public:
|
||||
bool PeekEvents(PINPUT_RECORD events, DWORD numEvents, DWORD &numEventsRead)
|
||||
{ return BOOLToBool(::PeekConsoleInput(m_Object, events, numEvents, &numEventsRead)); }
|
||||
bool PeekEvent(INPUT_RECORD &event, DWORD &numEventsRead)
|
||||
{ return PeekEvents(&event, 1, numEventsRead); }
|
||||
bool ReadEvents(PINPUT_RECORD events, DWORD numEvents, DWORD &numEventsRead)
|
||||
{ return BOOLToBool(::ReadConsoleInput(m_Object, events, numEvents, &numEventsRead)); }
|
||||
bool ReadEvent(INPUT_RECORD &event, DWORD &numEventsRead)
|
||||
{ return ReadEvents(&event, 1, numEventsRead); }
|
||||
bool GetNumberOfEvents(DWORD &numEvents)
|
||||
{ return BOOLToBool(::GetNumberOfConsoleInputEvents(m_Object, &numEvents)); }
|
||||
|
||||
bool WriteEvents(const INPUT_RECORD *events, DWORD numEvents, DWORD &numEventsWritten)
|
||||
{ return BOOLToBool(::WriteConsoleInput(m_Object, events, numEvents, &numEventsWritten)); }
|
||||
bool WriteEvent(const INPUT_RECORD &event, DWORD &numEventsWritten)
|
||||
{ return WriteEvents(&event, 1, numEventsWritten); }
|
||||
|
||||
bool Read(LPVOID buffer, DWORD numChars, DWORD &numCharsRead)
|
||||
{ return BOOLToBool(::ReadConsole(m_Object, buffer, numChars, &numCharsRead, NULL)); }
|
||||
|
||||
bool Flush()
|
||||
{ return BOOLToBool(::FlushConsoleInputBuffer(m_Object)); }
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
// Windows/Control/ComboBox.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
#include "../../Common/StringConvert.h"
|
||||
#endif
|
||||
|
||||
#include "ComboBox.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
|
||||
namespace NWindows {
|
||||
namespace NControl {
|
||||
|
||||
LRESULT CComboBox::GetLBText(int index, CSysString &s)
|
||||
{
|
||||
s.Empty();
|
||||
LRESULT len = GetLBTextLen(index); // length, excluding the terminating null character
|
||||
if (len == CB_ERR)
|
||||
return len;
|
||||
LRESULT len2 = GetLBText(index, s.GetBuf((unsigned)len));
|
||||
if (len2 == CB_ERR)
|
||||
return len;
|
||||
if (len > len2)
|
||||
len = len2;
|
||||
s.ReleaseBuf_CalcLen((unsigned)len);
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
LRESULT CComboBox::AddString(LPCWSTR s)
|
||||
{
|
||||
if (g_IsNT)
|
||||
return SendMsgW(CB_ADDSTRING, 0, (LPARAM)s);
|
||||
return AddString(GetSystemString(s));
|
||||
}
|
||||
|
||||
LRESULT CComboBox::GetLBText(int index, UString &s)
|
||||
{
|
||||
s.Empty();
|
||||
if (g_IsNT)
|
||||
{
|
||||
LRESULT len = SendMsgW(CB_GETLBTEXTLEN, MY_int_TO_WPARAM(index), 0);
|
||||
if (len == CB_ERR)
|
||||
return len;
|
||||
LRESULT len2 = SendMsgW(CB_GETLBTEXT, MY_int_TO_WPARAM(index), (LPARAM)s.GetBuf((unsigned)len));
|
||||
if (len2 == CB_ERR)
|
||||
return len;
|
||||
if (len > len2)
|
||||
len = len2;
|
||||
s.ReleaseBuf_CalcLen((unsigned)len);
|
||||
return len;
|
||||
}
|
||||
AString sa;
|
||||
const LRESULT len = GetLBText(index, sa);
|
||||
if (len == CB_ERR)
|
||||
return len;
|
||||
s = GetUnicodeString(sa);
|
||||
return (LRESULT)s.Len();
|
||||
}
|
||||
#endif
|
||||
|
||||
LRESULT CComboBox::AddString_SetItemData(LPCWSTR s, LPARAM lParam)
|
||||
{
|
||||
const LRESULT index = AddString(s);
|
||||
// NOTE: SetItemData((int)-1, lParam) works as unexpected.
|
||||
if (index >= 0) // optional check, because (index < 0) is not expected for normal inputs
|
||||
SetItemData((int)index, lParam);
|
||||
return index;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,79 @@
|
||||
// Windows/Control/ComboBox.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_CONTROL_COMBOBOX_H
|
||||
#define ZIP7_INC_WINDOWS_CONTROL_COMBOBOX_H
|
||||
|
||||
#include "../../Common/MyWindows.h"
|
||||
|
||||
#include <CommCtrl.h>
|
||||
|
||||
#include "../Window.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NControl {
|
||||
|
||||
class CComboBox: public CWindow
|
||||
{
|
||||
public:
|
||||
void ResetContent() { SendMsg(CB_RESETCONTENT, 0, 0); }
|
||||
LRESULT AddString(LPCTSTR s) { return SendMsg(CB_ADDSTRING, 0, (LPARAM)s); }
|
||||
#ifndef _UNICODE
|
||||
LRESULT AddString(LPCWSTR s);
|
||||
#endif
|
||||
|
||||
LRESULT AddString_SetItemData(LPCWSTR s, LPARAM lParam);
|
||||
|
||||
/* If this parameter is -1, any current selection in the list is removed and the edit control is cleared.*/
|
||||
LRESULT SetCurSel(int index) { return SendMsg(CB_SETCURSEL, MY_int_TO_WPARAM(index), 0); }
|
||||
LRESULT SetCurSel(unsigned index) { return SendMsg(CB_SETCURSEL, index, 0); }
|
||||
|
||||
/* If no item is selected, it returns CB_ERR (-1) */
|
||||
int GetCurSel() { return (int)SendMsg(CB_GETCURSEL, 0, 0); }
|
||||
|
||||
/* If an error occurs, it is CB_ERR (-1) */
|
||||
int GetCount() { return (int)SendMsg(CB_GETCOUNT, 0, 0); }
|
||||
|
||||
LRESULT GetLBTextLen(int index) { return SendMsg(CB_GETLBTEXTLEN, MY_int_TO_WPARAM(index), 0); }
|
||||
LRESULT GetLBText(int index, LPTSTR s) { return SendMsg(CB_GETLBTEXT, MY_int_TO_WPARAM(index), (LPARAM)s); }
|
||||
LRESULT GetLBText(int index, CSysString &s);
|
||||
#ifndef _UNICODE
|
||||
LRESULT GetLBText(int index, UString &s);
|
||||
#endif
|
||||
|
||||
LRESULT SetItemData(int index, LPARAM lParam) { return SendMsg(CB_SETITEMDATA, MY_int_TO_WPARAM(index), lParam); }
|
||||
LRESULT GetItemData(int index) { return SendMsg(CB_GETITEMDATA, MY_int_TO_WPARAM(index), 0); }
|
||||
LRESULT GetItemData(unsigned index) { return SendMsg(CB_GETITEMDATA, index, 0); }
|
||||
|
||||
LRESULT GetItemData_of_CurSel() { return GetItemData(GetCurSel()); }
|
||||
|
||||
void ShowDropDown(bool show = true) { SendMsg(CB_SHOWDROPDOWN, show ? TRUE : FALSE, 0); }
|
||||
};
|
||||
|
||||
#ifndef UNDER_CE
|
||||
|
||||
class CComboBoxEx: public CComboBox
|
||||
{
|
||||
public:
|
||||
bool SetUnicodeFormat(bool fUnicode) { return LRESULTToBool(SendMsg(CBEM_SETUNICODEFORMAT, BOOLToBool(fUnicode), 0)); }
|
||||
|
||||
/* Returns:
|
||||
an INT value that represents the number of items remaining in the control.
|
||||
If (index) is invalid, the message returns CB_ERR. */
|
||||
LRESULT DeleteItem(int index) { return SendMsg(CBEM_DELETEITEM, MY_int_TO_WPARAM(index), 0); }
|
||||
|
||||
LRESULT InsertItem(COMBOBOXEXITEM *item) { return SendMsg(CBEM_INSERTITEM, 0, (LPARAM)item); }
|
||||
#ifndef _UNICODE
|
||||
LRESULT InsertItem(COMBOBOXEXITEMW *item) { return SendMsg(CBEM_INSERTITEMW, 0, (LPARAM)item); }
|
||||
#endif
|
||||
|
||||
LRESULT SetItem(COMBOBOXEXITEM *item) { return SendMsg(CBEM_SETITEM, 0, (LPARAM)item); }
|
||||
DWORD SetExtendedStyle(DWORD exMask, DWORD exStyle) { return (DWORD)SendMsg(CBEM_SETEXTENDEDSTYLE, exMask, (LPARAM)exStyle); }
|
||||
HWND GetEditControl() { return (HWND)SendMsg(CBEM_GETEDITCONTROL, 0, 0); }
|
||||
HIMAGELIST SetImageList(HIMAGELIST imageList) { return (HIMAGELIST)SendMsg(CBEM_SETIMAGELIST, 0, (LPARAM)imageList); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,52 @@
|
||||
// Windows/Control/CommandBar.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_CONTROL_COMMANDBAR_H
|
||||
#define ZIP7_INC_WINDOWS_CONTROL_COMMANDBAR_H
|
||||
|
||||
#ifdef UNDER_CE
|
||||
|
||||
#include "../../Common/MyWindows.h"
|
||||
|
||||
#include <commctrl.h>
|
||||
|
||||
#include "../Window.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NControl {
|
||||
|
||||
class CCommandBar: public NWindows::CWindow
|
||||
{
|
||||
public:
|
||||
bool Create(HINSTANCE hInst, HWND hwndParent, int idCmdBar)
|
||||
{
|
||||
_window = ::CommandBar_Create(hInst, hwndParent, idCmdBar);
|
||||
return (_window != NULL);
|
||||
}
|
||||
|
||||
// Macros
|
||||
// void Destroy() { CommandBar_Destroy(_window); }
|
||||
// bool AddButtons(UINT numButtons, LPTBBUTTON buttons) { return BOOLToBool(SendMsg(TB_ADDBUTTONS, (WPARAM)numButtons, (LPARAM)buttons)); }
|
||||
// bool InsertButton(unsigned iButton, LPTBBUTTON button) { return BOOLToBool(SendMsg(TB_INSERTBUTTON, (WPARAM)iButton, (LPARAM)button)); }
|
||||
// BOOL AddToolTips(UINT numToolTips, LPTSTR toolTips) { return BOOLToBool(SendMsg(TB_SETTOOLTIPS, (WPARAM)numToolTips, (LPARAM)toolTips)); }
|
||||
void AutoSize() { SendMsg(TB_AUTOSIZE, 0, 0); }
|
||||
|
||||
// bool AddAdornments(DWORD dwFlags) { return BOOLToBool(::CommandBar_AddAdornments(_window, dwFlags, 0)); }
|
||||
// int AddBitmap(HINSTANCE hInst, int idBitmap, int iNumImages, int iImageWidth, int iImageHeight) { return ::CommandBar_AddBitmap(_window, hInst, idBitmap, iNumImages, iImageWidth, iImageHeight); }
|
||||
bool DrawMenuBar(WORD iButton) { return BOOLToBool(::CommandBar_DrawMenuBar(_window, iButton)); }
|
||||
HMENU GetMenu(WORD iButton) { return ::CommandBar_GetMenu(_window, iButton); }
|
||||
int Height() { return CommandBar_Height(_window); }
|
||||
HWND InsertComboBox(HINSTANCE hInst, int iWidth, UINT dwStyle, WORD idComboBox, WORD iButton) { return ::CommandBar_InsertComboBox(_window, hInst, iWidth, dwStyle, idComboBox, iButton); }
|
||||
bool InsertMenubar(HINSTANCE hInst, WORD idMenu, WORD iButton) { return BOOLToBool(::CommandBar_InsertMenubar(_window, hInst, idMenu, iButton)); }
|
||||
bool InsertMenubarEx(HINSTANCE hInst, LPTSTR pszMenu, WORD iButton) { return BOOLToBool(::CommandBar_InsertMenubarEx(_window, hInst, pszMenu, iButton)); }
|
||||
bool Show(bool cmdShow) { return BOOLToBool(::CommandBar_Show(_window, BoolToBOOL(cmdShow))); }
|
||||
|
||||
|
||||
// CE 4.0
|
||||
void AlignAdornments() { CommandBar_AlignAdornments(_window); }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,446 @@
|
||||
// Windows/Control/Dialog.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
// #include "../../Windows/DLL.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
#include "../../Common/StringConvert.h"
|
||||
#endif
|
||||
|
||||
#include "Dialog.h"
|
||||
|
||||
extern HINSTANCE g_hInstance;
|
||||
#ifndef _UNICODE
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
|
||||
namespace NWindows {
|
||||
namespace NControl {
|
||||
|
||||
static
|
||||
#ifdef Z7_OLD_WIN_SDK
|
||||
BOOL
|
||||
#else
|
||||
INT_PTR
|
||||
#endif
|
||||
APIENTRY
|
||||
DialogProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
CWindow tempDialog(dialogHWND);
|
||||
if (message == WM_INITDIALOG)
|
||||
tempDialog.SetUserDataLongPtr(lParam);
|
||||
CDialog *dialog = (CDialog *)(tempDialog.GetUserDataLongPtr());
|
||||
if (dialog == NULL)
|
||||
return FALSE;
|
||||
if (message == WM_INITDIALOG)
|
||||
dialog->Attach(dialogHWND);
|
||||
|
||||
/* MSDN: The dialog box procedure should return
|
||||
TRUE - if it processed the message
|
||||
FALSE - if it did not process the message
|
||||
If the dialog box procedure returns FALSE,
|
||||
the dialog manager performs the default dialog operation in response to the message.
|
||||
*/
|
||||
|
||||
try { return BoolToBOOL(dialog->OnMessage(message, wParam, lParam)); }
|
||||
catch(...) { return TRUE; }
|
||||
}
|
||||
|
||||
bool CDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_INITDIALOG: return OnInit();
|
||||
case WM_COMMAND: return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam);
|
||||
case WM_NOTIFY: return OnNotify((UINT)wParam, (LPNMHDR) lParam);
|
||||
case WM_TIMER: return OnTimer(wParam, lParam);
|
||||
case WM_SIZE: return OnSize(wParam, LOWORD(lParam), HIWORD(lParam));
|
||||
case WM_DESTROY: return OnDestroy();
|
||||
case WM_HELP: OnHelp(); return true;
|
||||
/*
|
||||
OnHelp(
|
||||
#ifdef UNDER_CE
|
||||
(void *)
|
||||
#else
|
||||
(LPHELPINFO)
|
||||
#endif
|
||||
lParam);
|
||||
return true;
|
||||
*/
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bool CDialog::OnCommand2(WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam);
|
||||
}
|
||||
*/
|
||||
|
||||
bool CDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam)
|
||||
{
|
||||
if (code == BN_CLICKED)
|
||||
return OnButtonClicked(itemID, (HWND)lParam);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CDialog::OnButtonClicked(unsigned buttonID, HWND /* buttonHWND */)
|
||||
{
|
||||
switch (buttonID)
|
||||
{
|
||||
case IDOK: OnOK(); break;
|
||||
case IDCANCEL: OnCancel(); break;
|
||||
case IDCLOSE: OnClose(); break;
|
||||
case IDCONTINUE: OnContinue(); break;
|
||||
case IDHELP: OnHelp(); break;
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef UNDER_CE
|
||||
/* in win2000/win98 : monitor functions are supported.
|
||||
We need dynamic linking, if we want nt4/win95 support in program.
|
||||
Even if we compile the code with low (WINVER) value, we still
|
||||
want to use monitor functions. So we declare missing functions here */
|
||||
// #if (WINVER < 0x0500)
|
||||
#ifndef MONITOR_DEFAULTTOPRIMARY
|
||||
extern "C" {
|
||||
DECLARE_HANDLE(HMONITOR);
|
||||
#define MONITOR_DEFAULTTOPRIMARY 0x00000001
|
||||
typedef struct tagMONITORINFO
|
||||
{
|
||||
DWORD cbSize;
|
||||
RECT rcMonitor;
|
||||
RECT rcWork;
|
||||
DWORD dwFlags;
|
||||
} MONITORINFO, *LPMONITORINFO;
|
||||
WINUSERAPI HMONITOR WINAPI MonitorFromWindow(HWND hwnd, DWORD dwFlags);
|
||||
WINUSERAPI BOOL WINAPI GetMonitorInfoA(HMONITOR hMonitor, LPMONITORINFO lpmi);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static bool GetWorkAreaRect(RECT *rect, HWND hwnd)
|
||||
{
|
||||
if (hwnd)
|
||||
{
|
||||
#ifndef UNDER_CE
|
||||
/* MonitorFromWindow() is supported in Win2000+
|
||||
MonitorFromWindow() : retrieves a handle to the display monitor that has the
|
||||
largest area of intersection with the bounding rectangle of a specified window.
|
||||
dwFlags: Determines the function's return value if the window does not intersect any display monitor.
|
||||
MONITOR_DEFAULTTONEAREST : Returns display that is nearest to the window.
|
||||
MONITOR_DEFAULTTONULL : Returns NULL.
|
||||
MONITOR_DEFAULTTOPRIMARY : Returns the primary display monitor.
|
||||
*/
|
||||
const HMONITOR hmon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
|
||||
if (hmon)
|
||||
{
|
||||
MONITORINFO mi;
|
||||
memset(&mi, 0, sizeof(mi));
|
||||
mi.cbSize = sizeof(mi);
|
||||
if (GetMonitorInfoA(hmon, &mi))
|
||||
{
|
||||
*rect = mi.rcWork;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Retrieves the size of the work area on the primary display monitor.
|
||||
The work area is the portion of the screen not obscured
|
||||
by the system taskbar or by application desktop toolbars.
|
||||
Any DPI virtualization mode of the caller has no effect on this output. */
|
||||
|
||||
return BOOLToBool(::SystemParametersInfo(SPI_GETWORKAREA, 0, rect, 0));
|
||||
}
|
||||
|
||||
|
||||
bool IsDialogSizeOK(int xSize, int ySize, HWND hwnd)
|
||||
{
|
||||
// it returns for system font. Real font uses another values
|
||||
const LONG v = GetDialogBaseUnits();
|
||||
const int x = LOWORD(v);
|
||||
const int y = HIWORD(v);
|
||||
|
||||
RECT rect;
|
||||
GetWorkAreaRect(&rect, hwnd);
|
||||
const int wx = RECT_SIZE_X(rect);
|
||||
const int wy = RECT_SIZE_Y(rect);
|
||||
return
|
||||
xSize / 4 * x <= wx &&
|
||||
ySize / 8 * y <= wy;
|
||||
}
|
||||
|
||||
bool CDialog::GetMargins(int margin, int &x, int &y)
|
||||
{
|
||||
x = margin;
|
||||
y = margin;
|
||||
RECT rect;
|
||||
rect.left = 0;
|
||||
rect.top = 0;
|
||||
rect.right = margin;
|
||||
rect.bottom = margin;
|
||||
if (!MapRect(&rect))
|
||||
return false;
|
||||
x = rect.right - rect.left;
|
||||
y = rect.bottom - rect.top;
|
||||
return true;
|
||||
}
|
||||
|
||||
int CDialog::Units_To_Pixels_X(int units)
|
||||
{
|
||||
RECT rect;
|
||||
rect.left = 0;
|
||||
rect.top = 0;
|
||||
rect.right = units;
|
||||
rect.bottom = units;
|
||||
if (!MapRect(&rect))
|
||||
return units * 3 / 2;
|
||||
return rect.right - rect.left;
|
||||
}
|
||||
|
||||
bool CDialog::GetItemSizes(unsigned id, int &x, int &y)
|
||||
{
|
||||
RECT rect;
|
||||
if (!::GetWindowRect(GetItem(id), &rect))
|
||||
return false;
|
||||
x = RECT_SIZE_X(rect);
|
||||
y = RECT_SIZE_Y(rect);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDialog::GetClientRectOfItem(unsigned id, RECT &rect)
|
||||
{
|
||||
::GetWindowRect(GetItem(id), &rect);
|
||||
ScreenToClient(&rect);
|
||||
}
|
||||
|
||||
bool CDialog::MoveItem(unsigned id, int x, int y, int width, int height, bool repaint)
|
||||
{
|
||||
return BOOLToBool(::MoveWindow(GetItem(id), x, y, width, height, BoolToBOOL(repaint)));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
typedef BOOL (WINAPI * Func_DwmGetWindowAttribute)(
|
||||
HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute);
|
||||
|
||||
static bool GetWindowsRect_DWM(HWND hwnd, RECT *rect)
|
||||
{
|
||||
// dll load and free is too slow : 300 calls in second.
|
||||
NDLL::CLibrary dll;
|
||||
if (!dll.Load(FTEXT("dwmapi.dll")))
|
||||
return false;
|
||||
Func_DwmGetWindowAttribute f = (Func_DwmGetWindowAttribute)dll.GetProc("DwmGetWindowAttribute" );
|
||||
if (f)
|
||||
{
|
||||
#define MY__DWMWA_EXTENDED_FRAME_BOUNDS 9
|
||||
// 30000 per second
|
||||
RECT r;
|
||||
if (f(hwnd, MY__DWMWA_EXTENDED_FRAME_BOUNDS, &r, sizeof(RECT)) == S_OK)
|
||||
{
|
||||
*rect = r;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
static bool IsRect_Small_Inside_Big(const RECT &sm, const RECT &big)
|
||||
{
|
||||
return sm.left >= big.left
|
||||
&& sm.right <= big.right
|
||||
&& sm.top >= big.top
|
||||
&& sm.bottom <= big.bottom;
|
||||
}
|
||||
|
||||
|
||||
static bool AreRectsOverlapped(const RECT &r1, const RECT &r2)
|
||||
{
|
||||
return r1.left < r2.right
|
||||
&& r1.right > r2.left
|
||||
&& r1.top < r2.bottom
|
||||
&& r1.bottom > r2.top;
|
||||
}
|
||||
|
||||
|
||||
static bool AreRectsEqual(const RECT &r1, const RECT &r2)
|
||||
{
|
||||
return r1.left == r2.left
|
||||
&& r1.right == r2.right
|
||||
&& r1.top == r2.top
|
||||
&& r1.bottom == r2.bottom;
|
||||
}
|
||||
|
||||
|
||||
void CDialog::NormalizeSize(bool fullNormalize)
|
||||
{
|
||||
RECT workRect;
|
||||
if (!GetWorkAreaRect(&workRect, *this))
|
||||
return;
|
||||
RECT rect;
|
||||
if (!GetWindowRect(&rect))
|
||||
return;
|
||||
int xs = RECT_SIZE_X(rect);
|
||||
int ys = RECT_SIZE_Y(rect);
|
||||
|
||||
// we don't want to change size using workRect, if window is outside of WorkArea
|
||||
if (!AreRectsOverlapped(rect, workRect))
|
||||
return;
|
||||
|
||||
/* here rect and workRect are overlapped, but it can be false
|
||||
overlapping of small shadow when window in another display. */
|
||||
|
||||
const int xsW = RECT_SIZE_X(workRect);
|
||||
const int ysW = RECT_SIZE_Y(workRect);
|
||||
if (xs <= xsW && ys <= ysW)
|
||||
return; // size of window is OK
|
||||
if (fullNormalize)
|
||||
{
|
||||
Show(SW_SHOWMAXIMIZED);
|
||||
return;
|
||||
}
|
||||
int x = workRect.left;
|
||||
int y = workRect.top;
|
||||
if (xs < xsW) x += (xsW - xs) / 2; else xs = xsW;
|
||||
if (ys < ysW) y += (ysW - ys) / 2; else ys = ysW;
|
||||
Move(x, y, xs, ys, true);
|
||||
}
|
||||
|
||||
|
||||
void CDialog::NormalizePosition()
|
||||
{
|
||||
RECT workRect;
|
||||
if (!GetWorkAreaRect(&workRect, *this))
|
||||
return;
|
||||
|
||||
RECT rect2 = workRect;
|
||||
bool useWorkArea = true;
|
||||
const HWND parentHWND = GetParent();
|
||||
|
||||
if (parentHWND)
|
||||
{
|
||||
RECT workRectParent;
|
||||
if (!GetWorkAreaRect(&workRectParent, parentHWND))
|
||||
return;
|
||||
|
||||
// if windows are in different monitors, we use only workArea of current window
|
||||
|
||||
if (AreRectsEqual(workRectParent, workRect))
|
||||
{
|
||||
// RECT rect3; if (GetWindowsRect_DWM(parentHWND, &rect3)) {}
|
||||
CWindow wnd(parentHWND);
|
||||
if (wnd.GetWindowRect(&rect2))
|
||||
{
|
||||
// it's same monitor. So we try to use parentHWND rect.
|
||||
/* we don't want to change position, if parent window is not inside work area.
|
||||
In Win10 : parent window rect is 8 pixels larger for each corner than window size for shadow.
|
||||
In maximize mode : window is outside of workRect.
|
||||
if parent window is inside workRect, we will use parent window instead of workRect */
|
||||
if (IsRect_Small_Inside_Big(rect2, workRect))
|
||||
useWorkArea = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RECT rect;
|
||||
if (!GetWindowRect(&rect))
|
||||
return;
|
||||
|
||||
if (useWorkArea)
|
||||
{
|
||||
// we don't want to move window, if it's already inside.
|
||||
if (IsRect_Small_Inside_Big(rect, workRect))
|
||||
return;
|
||||
// we don't want to move window, if it's outside of workArea
|
||||
if (!AreRectsOverlapped(rect, workRect))
|
||||
return;
|
||||
rect2 = workRect;
|
||||
}
|
||||
|
||||
{
|
||||
const int xs = RECT_SIZE_X(rect);
|
||||
const int ys = RECT_SIZE_Y(rect);
|
||||
const int xs2 = RECT_SIZE_X(rect2);
|
||||
const int ys2 = RECT_SIZE_Y(rect2);
|
||||
// we don't want to change position if parent is smaller.
|
||||
if (xs <= xs2 && ys <= ys2)
|
||||
{
|
||||
const int x = rect2.left + (xs2 - xs) / 2;
|
||||
const int y = rect2.top + (ys2 - ys) / 2;
|
||||
|
||||
if (x != rect.left || y != rect.top)
|
||||
Move(x, y, xs, ys, true);
|
||||
// SetWindowPos(*this, HWND_TOP, x, y, 0, 0, SWP_NOSIZE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CModelessDialog::Create(LPCTSTR templateName, HWND parentWindow)
|
||||
{
|
||||
const HWND aHWND = CreateDialogParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
|
||||
if (!aHWND)
|
||||
return false;
|
||||
Attach(aHWND);
|
||||
return true;
|
||||
}
|
||||
|
||||
INT_PTR CModalDialog::Create(LPCTSTR templateName, HWND parentWindow)
|
||||
{
|
||||
return DialogBoxParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
|
||||
bool CModelessDialog::Create(LPCWSTR templateName, HWND parentWindow)
|
||||
{
|
||||
HWND aHWND;
|
||||
if (g_IsNT)
|
||||
aHWND = CreateDialogParamW(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
|
||||
else
|
||||
{
|
||||
AString name;
|
||||
LPCSTR templateNameA;
|
||||
if (IS_INTRESOURCE(templateName))
|
||||
templateNameA = (LPCSTR)templateName;
|
||||
else
|
||||
{
|
||||
name = GetSystemString(templateName);
|
||||
templateNameA = name;
|
||||
}
|
||||
aHWND = CreateDialogParamA(g_hInstance, templateNameA, parentWindow, DialogProcedure, (LPARAM)this);
|
||||
}
|
||||
if (aHWND == 0)
|
||||
return false;
|
||||
Attach(aHWND);
|
||||
return true;
|
||||
}
|
||||
|
||||
INT_PTR CModalDialog::Create(LPCWSTR templateName, HWND parentWindow)
|
||||
{
|
||||
if (g_IsNT)
|
||||
return DialogBoxParamW(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
|
||||
AString name;
|
||||
LPCSTR templateNameA;
|
||||
if (IS_INTRESOURCE(templateName))
|
||||
templateNameA = (LPCSTR)templateName;
|
||||
else
|
||||
{
|
||||
name = GetSystemString(templateName);
|
||||
templateNameA = name;
|
||||
}
|
||||
return DialogBoxParamA(g_hInstance, templateNameA, parentWindow, DialogProcedure, (LPARAM)this);
|
||||
}
|
||||
#endif
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,213 @@
|
||||
// Windows/Control/Dialog.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_CONTROL_DIALOG_H
|
||||
#define ZIP7_INC_WINDOWS_CONTROL_DIALOG_H
|
||||
|
||||
#include "../Window.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NControl {
|
||||
|
||||
#ifndef IDCONTINUE
|
||||
#define IDCONTINUE 11
|
||||
#endif
|
||||
|
||||
class CDialog: public CWindow
|
||||
{
|
||||
// Z7_CLASS_NO_COPY(CDialog)
|
||||
public:
|
||||
CDialog(HWND wnd = NULL): CWindow(wnd) {}
|
||||
virtual ~CDialog() {}
|
||||
|
||||
HWND GetItem(unsigned itemID) const
|
||||
{ return GetDlgItem(_window, (int)itemID); }
|
||||
|
||||
bool EnableItem(unsigned itemID, bool enable) const
|
||||
{ return BOOLToBool(::EnableWindow(GetItem(itemID), BoolToBOOL(enable))); }
|
||||
|
||||
bool ShowItem(unsigned itemID, int cmdShow) const
|
||||
{ return BOOLToBool(::ShowWindow(GetItem(itemID), cmdShow)); }
|
||||
|
||||
bool ShowItem_Bool(unsigned itemID, bool show) const
|
||||
{ return ShowItem(itemID, show ? SW_SHOW: SW_HIDE); }
|
||||
|
||||
bool HideItem(unsigned itemID) const { return ShowItem(itemID, SW_HIDE); }
|
||||
|
||||
bool SetItemText(unsigned itemID, LPCTSTR s)
|
||||
{ return BOOLToBool(SetDlgItemText(_window, (int)itemID, s)); }
|
||||
|
||||
bool SetItemTextA(unsigned itemID, LPCSTR s)
|
||||
{ return BOOLToBool(SetDlgItemTextA(_window, (int)itemID, s)); }
|
||||
|
||||
bool SetItemText_Empty(unsigned itemID)
|
||||
{ return SetItemText(itemID, TEXT("")); }
|
||||
|
||||
#ifndef _UNICODE
|
||||
bool SetItemText(unsigned itemID, LPCWSTR s)
|
||||
{
|
||||
CWindow window(GetItem(itemID));
|
||||
return window.SetText(s);
|
||||
}
|
||||
#endif
|
||||
|
||||
UINT GetItemText(unsigned itemID, LPTSTR string, unsigned maxCount)
|
||||
{ return GetDlgItemText(_window, (int)itemID, string, (int)maxCount); }
|
||||
#ifndef _UNICODE
|
||||
/*
|
||||
bool GetItemText(unsigned itemID, LPWSTR string, int maxCount)
|
||||
{
|
||||
CWindow window(GetItem(unsigned));
|
||||
return window.GetText(string, maxCount);
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
bool GetItemText(unsigned itemID, UString &s)
|
||||
{
|
||||
CWindow window(GetItem(itemID));
|
||||
return window.GetText(s);
|
||||
}
|
||||
|
||||
/*
|
||||
bool SetItemInt(unsigned itemID, UINT value, bool isSigned)
|
||||
{ return BOOLToBool(SetDlgItemInt(_window, (int)itemID, value, BoolToBOOL(isSigned))); }
|
||||
*/
|
||||
bool SetItemUInt(unsigned itemID, UINT value)
|
||||
{ return BOOLToBool(SetDlgItemInt(_window, (int)itemID, value, FALSE)); }
|
||||
/*
|
||||
bool GetItemInt(unsigned itemID, bool isSigned, UINT &value)
|
||||
{
|
||||
BOOL result;
|
||||
value = GetDlgItemInt(_window, (int)itemID, &result, BoolToBOOL(isSigned));
|
||||
return BOOLToBool(result);
|
||||
}
|
||||
*/
|
||||
bool GetItemUInt(unsigned itemID, UINT &value)
|
||||
{
|
||||
BOOL result;
|
||||
value = GetDlgItemInt(_window, (int)itemID, &result, FALSE);
|
||||
return BOOLToBool(result);
|
||||
}
|
||||
|
||||
HWND GetNextGroupItem(HWND control, bool previous)
|
||||
{ return GetNextDlgGroupItem(_window, control, BoolToBOOL(previous)); }
|
||||
HWND GetNextTabItem(HWND control, bool previous)
|
||||
{ return GetNextDlgTabItem(_window, control, BoolToBOOL(previous)); }
|
||||
|
||||
LRESULT SendMsg_NextDlgCtl(WPARAM wParam, LPARAM lParam)
|
||||
{ return SendMsg(WM_NEXTDLGCTL, wParam, lParam); }
|
||||
LRESULT SendMsg_NextDlgCtl_HWND(HWND hwnd) { return SendMsg_NextDlgCtl((WPARAM)hwnd, TRUE); }
|
||||
LRESULT SendMsg_NextDlgCtl_CtlId(unsigned id) { return SendMsg_NextDlgCtl_HWND(GetItem(id)); }
|
||||
LRESULT SendMsg_NextDlgCtl_Next() { return SendMsg_NextDlgCtl(0, FALSE); }
|
||||
LRESULT SendMsg_NextDlgCtl_Prev() { return SendMsg_NextDlgCtl(1, FALSE); }
|
||||
|
||||
bool MapRect(LPRECT rect)
|
||||
{ return BOOLToBool(MapDialogRect(_window, rect)); }
|
||||
|
||||
bool IsMessage(LPMSG message)
|
||||
{ return BOOLToBool(IsDialogMessage(_window, message)); }
|
||||
|
||||
LRESULT SendItemMessage(unsigned itemID, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{ return SendDlgItemMessage(_window, (int)itemID, message, wParam, lParam); }
|
||||
|
||||
bool CheckButton(unsigned buttonID, UINT checkState)
|
||||
{ return BOOLToBool(CheckDlgButton(_window, (int)buttonID, checkState)); }
|
||||
bool CheckButton(unsigned buttonID, bool checkState)
|
||||
{ return CheckButton(buttonID, UINT(checkState ? BST_CHECKED : BST_UNCHECKED)); }
|
||||
|
||||
UINT IsButtonChecked_BST(unsigned buttonID) const
|
||||
{ return IsDlgButtonChecked(_window, (int)buttonID); }
|
||||
bool IsButtonCheckedBool(unsigned buttonID) const
|
||||
{ return (IsButtonChecked_BST(buttonID) == BST_CHECKED); }
|
||||
|
||||
bool CheckRadioButton(unsigned firstButtonID, unsigned lastButtonID, unsigned checkButtonID)
|
||||
{ return BOOLToBool(::CheckRadioButton(_window,
|
||||
(int)firstButtonID, (int)lastButtonID, (int)checkButtonID)); }
|
||||
|
||||
virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
virtual bool OnInit() { return true; }
|
||||
// virtual bool OnCommand2(WPARAM wParam, LPARAM lParam);
|
||||
virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam);
|
||||
virtual bool OnSize(WPARAM /* wParam */, int /* xSize */, int /* ySize */) { return false; }
|
||||
virtual bool OnDestroy() { return false; }
|
||||
|
||||
/*
|
||||
#ifdef UNDER_CE
|
||||
virtual void OnHelp(void *) { OnHelp(); }
|
||||
#else
|
||||
virtual void OnHelp(LPHELPINFO) { OnHelp(); }
|
||||
#endif
|
||||
*/
|
||||
virtual void OnHelp() {}
|
||||
|
||||
virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND);
|
||||
virtual void OnOK() {}
|
||||
virtual void OnContinue() {}
|
||||
virtual void OnCancel() {}
|
||||
virtual void OnClose() {}
|
||||
virtual bool OnNotify(UINT /* controlID */, LPNMHDR /* lParam */) { return false; }
|
||||
virtual bool OnTimer(WPARAM /* timerID */, LPARAM /* callback */) { return false; }
|
||||
|
||||
LONG_PTR SetMsgResult(LONG_PTR newLongPtr )
|
||||
{ return SetLongPtr(DWLP_MSGRESULT, newLongPtr); }
|
||||
LONG_PTR GetMsgResult() const
|
||||
{ return GetLongPtr(DWLP_MSGRESULT); }
|
||||
|
||||
bool GetMargins(int margin, int &x, int &y);
|
||||
int Units_To_Pixels_X(int units);
|
||||
bool GetItemSizes(unsigned id, int &x, int &y);
|
||||
void GetClientRectOfItem(unsigned id, RECT &rect);
|
||||
bool MoveItem(unsigned id, int x, int y, int width, int height, bool repaint = true);
|
||||
bool MoveItem_RECT(unsigned id, const RECT &r, bool repaint = true)
|
||||
{ return MoveItem(id, r.left, r.top, RECT_SIZE_X(r), RECT_SIZE_Y(r), repaint); }
|
||||
|
||||
void NormalizeSize(bool fullNormalize = false);
|
||||
void NormalizePosition();
|
||||
};
|
||||
|
||||
class CModelessDialog: public CDialog
|
||||
{
|
||||
public:
|
||||
bool Create(LPCTSTR templateName, HWND parentWindow);
|
||||
bool Create(UINT resID, HWND parentWindow) { return Create(MAKEINTRESOURCEW(resID), parentWindow); }
|
||||
#ifndef _UNICODE
|
||||
bool Create(LPCWSTR templateName, HWND parentWindow);
|
||||
#endif
|
||||
virtual void OnOK() Z7_override { Destroy(); }
|
||||
virtual void OnContinue() Z7_override { Destroy(); }
|
||||
virtual void OnCancel() Z7_override { Destroy(); }
|
||||
virtual void OnClose() Z7_override { Destroy(); }
|
||||
};
|
||||
|
||||
class CModalDialog: public CDialog
|
||||
{
|
||||
public:
|
||||
INT_PTR Create(LPCTSTR templateName, HWND parentWindow);
|
||||
INT_PTR Create(UINT resID, HWND parentWindow) { return Create(MAKEINTRESOURCEW(resID), parentWindow); }
|
||||
#ifndef _UNICODE
|
||||
INT_PTR Create(LPCWSTR templateName, HWND parentWindow);
|
||||
#endif
|
||||
|
||||
bool End(INT_PTR result) { return BOOLToBool(::EndDialog(_window, result)); }
|
||||
virtual void OnOK() Z7_override { End(IDOK); }
|
||||
virtual void OnContinue() Z7_override { End(IDCONTINUE); }
|
||||
virtual void OnCancel() Z7_override { End(IDCANCEL); }
|
||||
virtual void OnClose() Z7_override { End(IDCLOSE); }
|
||||
};
|
||||
|
||||
class CDialogChildControl: public NWindows::CWindow
|
||||
{
|
||||
// unsigned m_ID;
|
||||
public:
|
||||
void Init(const NWindows::NControl::CDialog &parentDialog, unsigned id)
|
||||
{
|
||||
// m_ID = id;
|
||||
Attach(parentDialog.GetItem(id));
|
||||
}
|
||||
};
|
||||
|
||||
bool IsDialogSizeOK(int xSize, int ySize, HWND hwnd = NULL);
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
// Windows/Control/Edit.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_CONTROL_EDIT_H
|
||||
#define ZIP7_INC_WINDOWS_CONTROL_EDIT_H
|
||||
|
||||
#include "../Window.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NControl {
|
||||
|
||||
class CEdit: public CWindow
|
||||
{
|
||||
public:
|
||||
void SetPasswordChar(WPARAM c) { SendMsg(EM_SETPASSWORDCHAR, c); }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
// Windows/Control/ImageList.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "ImageList.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NControl {
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,87 @@
|
||||
// Windows/Control/ImageList.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_CONTROL_IMAGE_LIST_H
|
||||
#define ZIP7_INC_WINDOWS_CONTROL_IMAGE_LIST_H
|
||||
|
||||
#include <CommCtrl.h>
|
||||
|
||||
#include "../Defs.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NControl {
|
||||
|
||||
class CImageList
|
||||
{
|
||||
HIMAGELIST m_Object;
|
||||
public:
|
||||
operator HIMAGELIST() const {return m_Object; }
|
||||
CImageList(): m_Object(NULL) {}
|
||||
bool Attach(HIMAGELIST imageList)
|
||||
{
|
||||
if (imageList == NULL)
|
||||
return false;
|
||||
m_Object = imageList;
|
||||
return true;
|
||||
}
|
||||
|
||||
HIMAGELIST Detach()
|
||||
{
|
||||
HIMAGELIST imageList = m_Object;
|
||||
m_Object = NULL;
|
||||
return imageList;
|
||||
}
|
||||
|
||||
bool Create(int width, int height, UINT flags, int initialNumber, int grow)
|
||||
{
|
||||
HIMAGELIST a = ImageList_Create(width, height, flags,
|
||||
initialNumber, grow);
|
||||
if (a == NULL)
|
||||
return false;
|
||||
return Attach(a);
|
||||
}
|
||||
|
||||
bool Destroy() // DeleteImageList() in MFC
|
||||
{
|
||||
if (m_Object == NULL)
|
||||
return false;
|
||||
return BOOLToBool(ImageList_Destroy(Detach()));
|
||||
}
|
||||
|
||||
~CImageList()
|
||||
{ Destroy(); }
|
||||
|
||||
int GetImageCount() const
|
||||
{ return ImageList_GetImageCount(m_Object); }
|
||||
|
||||
bool GetImageInfo(int index, IMAGEINFO* imageInfo) const
|
||||
{ return BOOLToBool(ImageList_GetImageInfo(m_Object, index, imageInfo)); }
|
||||
|
||||
int Add(HBITMAP hbmImage, HBITMAP hbmMask = NULL)
|
||||
{ return ImageList_Add(m_Object, hbmImage, hbmMask); }
|
||||
int AddMasked(HBITMAP hbmImage, COLORREF mask)
|
||||
{ return ImageList_AddMasked(m_Object, hbmImage, mask); }
|
||||
int AddIcon(HICON icon)
|
||||
{ return ImageList_AddIcon(m_Object, icon); }
|
||||
int Replace(int index, HICON icon)
|
||||
{ return ImageList_ReplaceIcon(m_Object, index, icon); }
|
||||
|
||||
// If index is -1, the function removes all images.
|
||||
bool Remove(int index)
|
||||
{ return BOOLToBool(ImageList_Remove(m_Object, index)); }
|
||||
bool RemoveAll()
|
||||
{ return BOOLToBool(ImageList_RemoveAll(m_Object)); }
|
||||
|
||||
HICON ExtractIcon(int index)
|
||||
{ return ImageList_ExtractIcon(NULL, m_Object, index); }
|
||||
HICON GetIcon(int index, UINT flags)
|
||||
{ return ImageList_GetIcon(m_Object, index, flags); }
|
||||
|
||||
bool GetIconSize(int &width, int &height) const
|
||||
{ return BOOLToBool(ImageList_GetIconSize(m_Object, &width, &height)); }
|
||||
bool SetIconSize(int width, int height)
|
||||
{ return BOOLToBool(ImageList_SetIconSize(m_Object, width, height)); }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,162 @@
|
||||
// Windows/Control/ListView.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "ListView.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
|
||||
namespace NWindows {
|
||||
namespace NControl {
|
||||
|
||||
bool CListView::CreateEx(DWORD exStyle, DWORD style,
|
||||
int x, int y, int width, int height,
|
||||
HWND parentWindow, HMENU idOrHMenu,
|
||||
HINSTANCE instance, LPVOID createParam)
|
||||
{
|
||||
return CWindow::CreateEx(exStyle, WC_LISTVIEW, TEXT(""), style, x, y, width,
|
||||
height, parentWindow, idOrHMenu, instance, createParam);
|
||||
}
|
||||
|
||||
/* note: LVITEM and LVCOLUMN structures contain optional fields
|
||||
depending from preprocessor macros:
|
||||
#if (_WIN32_IE >= 0x0300)
|
||||
#if (_WIN32_WINNT >= 0x0501)
|
||||
#if (_WIN32_WINNT >= 0x0600)
|
||||
*/
|
||||
|
||||
bool CListView::GetItemParam(unsigned index, LPARAM ¶m) const
|
||||
{
|
||||
LVITEM item;
|
||||
item.iItem = (int)index;
|
||||
item.iSubItem = 0;
|
||||
item.mask = LVIF_PARAM;
|
||||
const bool res = GetItem(&item);
|
||||
param = item.lParam;
|
||||
return res;
|
||||
}
|
||||
|
||||
int CListView::InsertColumn(unsigned columnIndex, LPCTSTR text, int width)
|
||||
{
|
||||
LVCOLUMN ci;
|
||||
ci.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
|
||||
ci.pszText = (LPTSTR)(void *)text;
|
||||
ci.iSubItem = (int)columnIndex;
|
||||
ci.cx = width;
|
||||
return InsertColumn(columnIndex, &ci);
|
||||
}
|
||||
|
||||
int CListView::InsertItem(unsigned index, LPCTSTR text)
|
||||
{
|
||||
LVITEM item;
|
||||
item.mask = LVIF_TEXT | LVIF_PARAM;
|
||||
item.iItem = (int)index;
|
||||
item.lParam = (LPARAM)index;
|
||||
item.pszText = (LPTSTR)(void *)text;
|
||||
item.iSubItem = 0;
|
||||
return InsertItem(&item);
|
||||
}
|
||||
|
||||
int CListView::SetSubItem(unsigned index, unsigned subIndex, LPCTSTR text)
|
||||
{
|
||||
LVITEM item;
|
||||
item.mask = LVIF_TEXT;
|
||||
item.iItem = (int)index;
|
||||
item.pszText = (LPTSTR)(void *)text;
|
||||
item.iSubItem = (int)subIndex;
|
||||
return SetItem(&item);
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
|
||||
int CListView::InsertColumn(unsigned columnIndex, LPCWSTR text, int width)
|
||||
{
|
||||
LVCOLUMNW ci;
|
||||
ci.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
|
||||
ci.pszText = (LPWSTR)(void *)text;
|
||||
ci.iSubItem = (int)columnIndex;
|
||||
ci.cx = width;
|
||||
return InsertColumn(columnIndex, &ci);
|
||||
}
|
||||
|
||||
int CListView::InsertItem(unsigned index, LPCWSTR text)
|
||||
{
|
||||
LVITEMW item;
|
||||
item.mask = LVIF_TEXT | LVIF_PARAM;
|
||||
item.iItem = (int)index;
|
||||
item.lParam = (LPARAM)index;
|
||||
item.pszText = (LPWSTR)(void *)text;
|
||||
item.iSubItem = 0;
|
||||
return InsertItem(&item);
|
||||
}
|
||||
|
||||
int CListView::SetSubItem(unsigned index, unsigned subIndex, LPCWSTR text)
|
||||
{
|
||||
LVITEMW item;
|
||||
item.mask = LVIF_TEXT;
|
||||
item.iItem = (int)index;
|
||||
item.pszText = (LPWSTR)(void *)text;
|
||||
item.iSubItem = (int)subIndex;
|
||||
return SetItem(&item);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static LRESULT APIENTRY ListViewSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
CWindow window(hwnd);
|
||||
CListView2 *w = (CListView2 *)(window.GetUserDataLongPtr());
|
||||
if (w == NULL)
|
||||
return 0;
|
||||
return w->OnMessage(message, wParam, lParam);
|
||||
}
|
||||
|
||||
LRESULT CListView2::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
#ifndef _UNICODE
|
||||
if (g_IsNT)
|
||||
return CallWindowProcW(_origWindowProc, *this, message, wParam, lParam);
|
||||
else
|
||||
#endif
|
||||
return CallWindowProc(_origWindowProc, *this, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void CListView2::SetWindowProc()
|
||||
{
|
||||
SetUserDataLongPtr((LONG_PTR)this);
|
||||
#ifndef _UNICODE
|
||||
if (g_IsNT)
|
||||
_origWindowProc = (WNDPROC)SetLongPtrW(GWLP_WNDPROC, (LONG_PTR)ListViewSubclassProc);
|
||||
else
|
||||
#endif
|
||||
_origWindowProc = (WNDPROC)SetLongPtr(GWLP_WNDPROC, (LONG_PTR)ListViewSubclassProc);
|
||||
}
|
||||
|
||||
/*
|
||||
LRESULT CListView3::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
LRESULT res = CListView2::OnMessage(message, wParam, lParam);
|
||||
if (message == WM_GETDLGCODE)
|
||||
{
|
||||
// when user presses RETURN, windows sends default (first) button command to parent dialog.
|
||||
// we disable this:
|
||||
MSG *msg = (MSG *)lParam;
|
||||
WPARAM key = wParam;
|
||||
bool change = false;
|
||||
if (msg)
|
||||
{
|
||||
if (msg->message == WM_KEYDOWN && msg->wParam == VK_RETURN)
|
||||
change = true;
|
||||
}
|
||||
else if (wParam == VK_RETURN)
|
||||
change = true;
|
||||
if (change)
|
||||
res |= DLGC_WANTALLKEYS;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,156 @@
|
||||
// Windows/Control/ListView.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_CONTROL_LISTVIEW_H
|
||||
#define ZIP7_INC_WINDOWS_CONTROL_LISTVIEW_H
|
||||
|
||||
#include "../../Common/MyWindows.h"
|
||||
|
||||
#include <CommCtrl.h>
|
||||
|
||||
#include "../Window.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NControl {
|
||||
|
||||
class CListView: public NWindows::CWindow
|
||||
{
|
||||
public:
|
||||
bool CreateEx(DWORD exStyle, DWORD style,
|
||||
int x, int y, int width, int height,
|
||||
HWND parentWindow, HMENU idOrHMenu,
|
||||
HINSTANCE instance, LPVOID createParam);
|
||||
|
||||
void SetUnicodeFormat()
|
||||
{
|
||||
#ifndef UNDER_CE
|
||||
ListView_SetUnicodeFormat(_window, TRUE);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool DeleteAllItems() { return BOOLToBool(ListView_DeleteAllItems(_window)); }
|
||||
bool DeleteColumn(unsigned columnIndex) { return BOOLToBool(ListView_DeleteColumn(_window, columnIndex)); }
|
||||
|
||||
int InsertColumn(unsigned columnIndex, const LVCOLUMN *columnInfo) { return ListView_InsertColumn(_window, columnIndex, columnInfo); }
|
||||
int InsertColumn(unsigned columnIndex, LPCTSTR text, int width);
|
||||
bool SetColumnOrderArray(unsigned count, const int *columns)
|
||||
{ return BOOLToBool(ListView_SetColumnOrderArray(_window, count, (int *)(void *)columns)); }
|
||||
|
||||
/*
|
||||
int GetNumColumns()
|
||||
{
|
||||
HWND header = ListView_GetHeader(_window);
|
||||
if (!header)
|
||||
return -1;
|
||||
return Header_GetItemCount(header);
|
||||
}
|
||||
*/
|
||||
|
||||
int InsertItem(const LVITEM* item) { return ListView_InsertItem(_window, item); }
|
||||
int InsertItem(unsigned index, LPCTSTR text);
|
||||
bool SetItem(const LVITEM* item) { return BOOLToBool(ListView_SetItem(_window, item)); }
|
||||
int SetSubItem(unsigned index, unsigned subIndex, LPCTSTR text);
|
||||
|
||||
#ifndef _UNICODE
|
||||
|
||||
int InsertColumn(unsigned columnIndex, const LVCOLUMNW *columnInfo) { return (int)SendMsg(LVM_INSERTCOLUMNW, (WPARAM)columnIndex, (LPARAM)columnInfo); }
|
||||
int InsertColumn(unsigned columnIndex, LPCWSTR text, int width);
|
||||
int InsertItem(const LV_ITEMW* item) { return (int)SendMsg(LVM_INSERTITEMW, 0, (LPARAM)item); }
|
||||
int InsertItem(unsigned index, LPCWSTR text);
|
||||
bool SetItem(const LV_ITEMW* item) { return BOOLToBool((BOOL)SendMsg(LVM_SETITEMW, 0, (LPARAM)item)); }
|
||||
int SetSubItem(unsigned index, unsigned subIndex, LPCWSTR text);
|
||||
|
||||
#endif
|
||||
|
||||
bool DeleteItem(unsigned itemIndex) { return BOOLToBool(ListView_DeleteItem(_window, itemIndex)); }
|
||||
|
||||
UINT GetSelectedCount() const { return ListView_GetSelectedCount(_window); }
|
||||
int GetItemCount() const { return ListView_GetItemCount(_window); }
|
||||
|
||||
INT GetSelectionMark() const { return ListView_GetSelectionMark(_window); }
|
||||
|
||||
void SetItemCount(unsigned numItems) { ListView_SetItemCount(_window, numItems); }
|
||||
void SetItemCountEx(unsigned numItems, DWORD flags) { ListView_SetItemCountEx(_window, numItems, flags); }
|
||||
|
||||
/* startIndex : The index of the item with which to begin the search,
|
||||
or -1 to find the first item that matches the specified flags.
|
||||
The specified item itself is excluded from the search. */
|
||||
int GetNextItem(int startIndex, UINT flags) const { return ListView_GetNextItem(_window, startIndex, flags); }
|
||||
int GetNextSelectedItem(int startIndex) const { return GetNextItem(startIndex, LVNI_SELECTED); }
|
||||
int GetFocusedItem() const { return GetNextItem(-1, LVNI_FOCUSED); }
|
||||
|
||||
bool GetItem(LVITEM* item) const { return BOOLToBool(ListView_GetItem(_window, item)); }
|
||||
bool GetItemParam(unsigned itemIndex, LPARAM ¶m) const;
|
||||
/*
|
||||
void GetItemText(unsigned itemIndex, unsigned subItemIndex, LPTSTR text, unsigned textSizeMax) const
|
||||
{ ListView_GetItemText(_window, itemIndex, subItemIndex, text, textSizeMax) }
|
||||
*/
|
||||
bool SortItems(PFNLVCOMPARE compareFunction, LPARAM dataParam)
|
||||
{ return BOOLToBool(ListView_SortItems(_window, compareFunction, dataParam)); }
|
||||
|
||||
// If (index == -1), then the state change is applied to all items.
|
||||
void SetItemState(int index, UINT state, UINT mask) { ListView_SetItemState(_window, index, state, mask) }
|
||||
void SetItemState_Selected(int index, bool select) { SetItemState(index, select ? LVIS_SELECTED : 0, LVIS_SELECTED); }
|
||||
void SetItemState_Selected(int index) { SetItemState(index, LVIS_SELECTED, LVIS_SELECTED); }
|
||||
void SelectAll() { SetItemState_Selected(-1); }
|
||||
void SetItemState_FocusedSelected(int index) { SetItemState(index, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); }
|
||||
UINT GetItemState(int index, UINT mask) const { return ListView_GetItemState(_window, index, mask); }
|
||||
bool IsItemSelected(int index) const { return GetItemState(index, LVIS_SELECTED) == LVIS_SELECTED; }
|
||||
|
||||
bool GetColumn(unsigned columnIndex, LVCOLUMN* columnInfo) const
|
||||
{ return BOOLToBool(ListView_GetColumn(_window, columnIndex, columnInfo)); }
|
||||
|
||||
HIMAGELIST SetImageList(HIMAGELIST imageList, int imageListType)
|
||||
{ return ListView_SetImageList(_window, imageList, imageListType); }
|
||||
|
||||
// version 4.70: NT5 | (NT4 + ie3) | w98 | (w95 + ie3)
|
||||
DWORD GetExtendedListViewStyle() { return ListView_GetExtendedListViewStyle(_window); }
|
||||
void SetExtendedListViewStyle(DWORD exStyle) { ListView_SetExtendedListViewStyle(_window, exStyle); }
|
||||
void SetExtendedListViewStyle(DWORD exMask, DWORD exStyle) { ListView_SetExtendedListViewStyleEx(_window, exMask, exStyle); }
|
||||
|
||||
void SetCheckState(UINT index, bool checkState) { ListView_SetCheckState(_window, index, BoolToBOOL(checkState)) }
|
||||
bool GetCheckState(UINT index) { return BOOLToBool(ListView_GetCheckState(_window, index)); }
|
||||
|
||||
bool EnsureVisible(int index, bool partialOK) { return BOOLToBool(ListView_EnsureVisible(_window, index, BoolToBOOL(partialOK))); }
|
||||
|
||||
bool GetItemRect(int index, RECT *rect, int code) { return BOOLToBool(ListView_GetItemRect(_window, index, rect, code)); }
|
||||
|
||||
HWND GetEditControl() { return ListView_GetEditControl(_window) ; }
|
||||
HWND EditLabel(int itemIndex) { return ListView_EditLabel(_window, itemIndex) ; }
|
||||
|
||||
bool RedrawItems(int firstIndex, int lastIndex) { return BOOLToBool(ListView_RedrawItems(_window, firstIndex, lastIndex)); }
|
||||
bool RedrawAllItems()
|
||||
{
|
||||
if (GetItemCount() > 0)
|
||||
return RedrawItems(0, GetItemCount() - 1);
|
||||
return true;
|
||||
}
|
||||
bool RedrawItem(int index) { return RedrawItems(index, index); }
|
||||
|
||||
int HitTest(LPLVHITTESTINFO info) { return ListView_HitTest(_window, info); }
|
||||
COLORREF GetBkColor() { return ListView_GetBkColor(_window); }
|
||||
bool SetColumnWidth(int iCol, int cx) { return BOOLToBool(ListView_SetColumnWidth(_window, iCol, cx)); }
|
||||
bool SetColumnWidthAuto(int iCol) { return SetColumnWidth(iCol, LVSCW_AUTOSIZE); }
|
||||
};
|
||||
|
||||
class CListView2: public CListView
|
||||
{
|
||||
WNDPROC _origWindowProc;
|
||||
// ~CListView2() ZIP7_eq_delete;
|
||||
public:
|
||||
virtual ~CListView2() {}
|
||||
CListView2() {}
|
||||
void SetWindowProc();
|
||||
virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
};
|
||||
|
||||
/*
|
||||
class CListView3: public CListView2
|
||||
{
|
||||
public:
|
||||
virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
};
|
||||
*/
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
// Windows/Control/ProgressBar.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_CONTROL_PROGRESSBAR_H
|
||||
#define ZIP7_INC_WINDOWS_CONTROL_PROGRESSBAR_H
|
||||
|
||||
#include "../../Common/MyWindows.h"
|
||||
|
||||
#include <CommCtrl.h>
|
||||
|
||||
#include "../Window.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NControl {
|
||||
|
||||
class CProgressBar: public CWindow
|
||||
{
|
||||
public:
|
||||
LRESULT SetPos(int pos) { return SendMsg(PBM_SETPOS, (unsigned)pos, 0); }
|
||||
// LRESULT DeltaPos(int increment) { return SendMsg(PBM_DELTAPOS, increment, 0); }
|
||||
// UINT GetPos() { return (UINT)SendMsg(PBM_GETPOS, 0, 0); }
|
||||
// LRESULT SetRange(unsigned short minValue, unsigned short maxValue) { return SendMsg(PBM_SETRANGE, 0, MAKELPARAM(minValue, maxValue)); }
|
||||
DWORD SetRange32(int minValue, int maxValue) { return (DWORD)SendMsg(PBM_SETRANGE32, (unsigned)minValue, (LPARAM)(unsigned)maxValue); }
|
||||
// int SetStep(int step) { return (int)SendMsg(PBM_SETSTEP, step, 0); }
|
||||
// LRESULT StepIt() { return SendMsg(PBM_STEPIT, 0, 0); }
|
||||
// INT GetRange(bool minValue, PPBRANGE range) { return (INT)SendMsg(PBM_GETRANGE, BoolToBOOL(minValue), (LPARAM)range); }
|
||||
|
||||
#ifndef UNDER_CE
|
||||
COLORREF SetBarColor(COLORREF color) { return (COLORREF)SendMsg(PBM_SETBARCOLOR, 0, (LPARAM)color); }
|
||||
COLORREF SetBackgroundColor(COLORREF color) { return (COLORREF)SendMsg(PBM_SETBKCOLOR, 0, (LPARAM)color); }
|
||||
#endif
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,165 @@
|
||||
// Windows/Control/PropertyPage.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
#include "../../Common/StringConvert.h"
|
||||
#endif
|
||||
|
||||
#include "PropertyPage.h"
|
||||
|
||||
extern HINSTANCE g_hInstance;
|
||||
#ifndef _UNICODE
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
|
||||
namespace NWindows {
|
||||
namespace NControl {
|
||||
|
||||
static
|
||||
#ifdef Z7_OLD_WIN_SDK
|
||||
BOOL
|
||||
#else
|
||||
INT_PTR
|
||||
#endif
|
||||
APIENTRY MyProperyPageProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
CWindow tempDialog(dialogHWND);
|
||||
if (message == WM_INITDIALOG)
|
||||
tempDialog.SetUserDataLongPtr(((PROPSHEETPAGE *)lParam)->lParam);
|
||||
CDialog *dialog = (CDialog *)(tempDialog.GetUserDataLongPtr());
|
||||
if (dialog == NULL)
|
||||
return FALSE;
|
||||
if (message == WM_INITDIALOG)
|
||||
dialog->Attach(dialogHWND);
|
||||
try { return BoolToBOOL(dialog->OnMessage(message, wParam, lParam)); }
|
||||
catch(...) { return TRUE; }
|
||||
}
|
||||
|
||||
bool CPropertyPage::OnNotify(UINT /* controlID */, LPNMHDR lParam)
|
||||
{
|
||||
switch (lParam->code)
|
||||
{
|
||||
case PSN_APPLY: SetMsgResult(OnApply2(LPPSHNOTIFY(lParam))); break;
|
||||
case PSN_KILLACTIVE: SetMsgResult(BoolToBOOL(OnKillActive2(LPPSHNOTIFY(lParam)))); break;
|
||||
case PSN_SETACTIVE: SetMsgResult(OnSetActive2(LPPSHNOTIFY(lParam))); break;
|
||||
case PSN_RESET: OnReset2(LPPSHNOTIFY(lParam)); break;
|
||||
case PSN_HELP: OnNotifyHelp2(LPPSHNOTIFY(lParam)); break;
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
PROPSHEETPAGE fields depend from
|
||||
#if (_WIN32_WINNT >= 0x0600)
|
||||
#elif (_WIN32_WINNT >= 0x0501)
|
||||
#elif (_WIN32_IE >= 0x0400)
|
||||
PROPSHEETHEADER fields depend from
|
||||
#if (_WIN32_IE >= 0x0400)
|
||||
*/
|
||||
#if defined(PROPSHEETPAGEA_V1_SIZE) && !defined(Z7_OLD_WIN_SDK)
|
||||
#ifndef _UNICODE
|
||||
#define my_compatib_PROPSHEETPAGEA PROPSHEETPAGEA_V1
|
||||
#endif
|
||||
#define my_compatib_PROPSHEETPAGEW PROPSHEETPAGEW_V1
|
||||
#else
|
||||
// for old mingw:
|
||||
#ifndef _UNICODE
|
||||
#define my_compatib_PROPSHEETPAGEA PROPSHEETPAGEA
|
||||
#endif
|
||||
#define my_compatib_PROPSHEETPAGEW PROPSHEETPAGEW
|
||||
#endif
|
||||
|
||||
INT_PTR MyPropertySheet(const CObjectVector<CPageInfo> &pagesInfo, HWND hwndParent, const UString &title)
|
||||
{
|
||||
unsigned i;
|
||||
#ifndef _UNICODE
|
||||
AStringVector titles;
|
||||
for (i = 0; i < pagesInfo.Size(); i++)
|
||||
titles.Add(GetSystemString(pagesInfo[i].Title));
|
||||
CRecordVector<my_compatib_PROPSHEETPAGEA> pagesA;
|
||||
#endif
|
||||
CRecordVector<my_compatib_PROPSHEETPAGEW> pagesW;
|
||||
|
||||
for (i = 0; i < pagesInfo.Size(); i++)
|
||||
{
|
||||
const CPageInfo &pageInfo = pagesInfo[i];
|
||||
#ifndef _UNICODE
|
||||
{
|
||||
my_compatib_PROPSHEETPAGEA page;
|
||||
memset(&page, 0, sizeof(page));
|
||||
page.dwSize = sizeof(page);
|
||||
page.dwFlags = PSP_HASHELP;
|
||||
page.hInstance = g_hInstance;
|
||||
page.pszTemplate = MAKEINTRESOURCEA(pageInfo.ID);
|
||||
// page.pszIcon = NULL;
|
||||
page.pfnDlgProc = NWindows::NControl::MyProperyPageProcedure;
|
||||
|
||||
if (!titles[i].IsEmpty())
|
||||
{
|
||||
page.pszTitle = titles[i];
|
||||
page.dwFlags |= PSP_USETITLE;
|
||||
}
|
||||
// else page.pszTitle = NULL;
|
||||
page.lParam = (LPARAM)pageInfo.Page;
|
||||
// page.pfnCallback = NULL;
|
||||
pagesA.Add(page);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
my_compatib_PROPSHEETPAGEW page;
|
||||
memset(&page, 0, sizeof(page));
|
||||
page.dwSize = sizeof(page);
|
||||
page.dwFlags = PSP_HASHELP;
|
||||
page.hInstance = g_hInstance;
|
||||
page.pszTemplate = MAKEINTRESOURCEW(pageInfo.ID);
|
||||
// page.pszIcon = NULL;
|
||||
page.pfnDlgProc = NWindows::NControl::MyProperyPageProcedure;
|
||||
|
||||
if (!pageInfo.Title.IsEmpty())
|
||||
{
|
||||
page.pszTitle = pageInfo.Title;
|
||||
page.dwFlags |= PSP_USETITLE;
|
||||
}
|
||||
// else page.pszTitle = NULL;
|
||||
page.lParam = (LPARAM)pageInfo.Page;
|
||||
// page.pfnCallback = NULL;
|
||||
pagesW.Add(page);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
if (!g_IsNT)
|
||||
{
|
||||
PROPSHEETHEADERA sheet;
|
||||
sheet.dwSize = sizeof(sheet);
|
||||
sheet.dwFlags = PSH_PROPSHEETPAGE;
|
||||
sheet.hwndParent = hwndParent;
|
||||
sheet.hInstance = g_hInstance;
|
||||
AString titleA (GetSystemString(title));
|
||||
sheet.pszCaption = titleA;
|
||||
sheet.nPages = pagesA.Size();
|
||||
sheet.nStartPage = 0;
|
||||
sheet.ppsp = (LPCPROPSHEETPAGEA)(const void *)pagesA.ConstData();
|
||||
sheet.pfnCallback = NULL;
|
||||
return ::PropertySheetA(&sheet);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
PROPSHEETHEADERW sheet;
|
||||
sheet.dwSize = sizeof(sheet);
|
||||
sheet.dwFlags = PSH_PROPSHEETPAGE;
|
||||
sheet.hwndParent = hwndParent;
|
||||
sheet.hInstance = g_hInstance;
|
||||
sheet.pszCaption = title;
|
||||
sheet.nPages = pagesW.Size();
|
||||
sheet.nStartPage = 0;
|
||||
sheet.ppsp = (LPCPROPSHEETPAGEW)(const void *)pagesW.ConstData();
|
||||
sheet.pfnCallback = NULL;
|
||||
return ::PropertySheetW(&sheet);
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,50 @@
|
||||
// Windows/Control/PropertyPage.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_CONTROL_PROPERTYPAGE_H
|
||||
#define ZIP7_INC_WINDOWS_CONTROL_PROPERTYPAGE_H
|
||||
|
||||
#include "../../Common/MyWindows.h"
|
||||
|
||||
#include <prsht.h>
|
||||
|
||||
#include "Dialog.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NControl {
|
||||
|
||||
INT_PTR APIENTRY ProperyPageProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
class CPropertyPage: public CDialog
|
||||
{
|
||||
public:
|
||||
CPropertyPage(HWND window = NULL): CDialog(window) {}
|
||||
|
||||
void Changed() { PropSheet_Changed(GetParent(), (HWND)*this); }
|
||||
void UnChanged() { PropSheet_UnChanged(GetParent(), (HWND)*this); }
|
||||
|
||||
virtual bool OnNotify(UINT controlID, LPNMHDR lParam) Z7_override;
|
||||
|
||||
virtual bool OnKillActive() { return false; } // false = OK
|
||||
virtual bool OnKillActive2(const PSHNOTIFY *) { return OnKillActive(); }
|
||||
virtual LONG OnSetActive() { return false; } // false = OK
|
||||
virtual LONG OnSetActive2(const PSHNOTIFY *) { return OnSetActive(); }
|
||||
virtual LONG OnApply() { return PSNRET_NOERROR; }
|
||||
virtual LONG OnApply2(const PSHNOTIFY *) { return OnApply(); }
|
||||
virtual void OnNotifyHelp() {}
|
||||
virtual void OnNotifyHelp2(const PSHNOTIFY *) { OnNotifyHelp(); }
|
||||
virtual void OnReset() {}
|
||||
virtual void OnReset2(const PSHNOTIFY *) { OnReset(); }
|
||||
};
|
||||
|
||||
struct CPageInfo
|
||||
{
|
||||
CPropertyPage *Page;
|
||||
UString Title;
|
||||
UINT ID;
|
||||
};
|
||||
|
||||
INT_PTR MyPropertySheet(const CObjectVector<CPageInfo> &pagesInfo, HWND hwndParent, const UString &title);
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
// Windows/Control/ReBar.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_CONTROL_REBAR_H
|
||||
#define ZIP7_INC_WINDOWS_CONTROL_REBAR_H
|
||||
|
||||
#include "../Window.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NControl {
|
||||
|
||||
class CReBar: public NWindows::CWindow
|
||||
{
|
||||
public:
|
||||
bool SetBarInfo(LPREBARINFO barInfo)
|
||||
{ return LRESULTToBool(SendMsg(RB_SETBARINFO, 0, (LPARAM)barInfo)); }
|
||||
bool InsertBand(int index, LPREBARBANDINFO bandInfo)
|
||||
{ return LRESULTToBool(SendMsg(RB_INSERTBAND, MY_int_TO_WPARAM(index), (LPARAM)bandInfo)); }
|
||||
bool SetBandInfo(unsigned index, LPREBARBANDINFO bandInfo)
|
||||
{ return LRESULTToBool(SendMsg(RB_SETBANDINFO, index, (LPARAM)bandInfo)); }
|
||||
void MaximizeBand(unsigned index, bool ideal)
|
||||
{ SendMsg(RB_MAXIMIZEBAND, index, BoolToBOOL(ideal)); }
|
||||
bool SizeToRect(LPRECT rect)
|
||||
{ return LRESULTToBool(SendMsg(RB_SIZETORECT, 0, (LPARAM)rect)); }
|
||||
UINT GetHeight()
|
||||
{ return (UINT)SendMsg(RB_GETBARHEIGHT); }
|
||||
UINT GetBandCount()
|
||||
{ return (UINT)SendMsg(RB_GETBANDCOUNT); }
|
||||
bool DeleteBand(UINT index)
|
||||
{ return LRESULTToBool(SendMsg(RB_DELETEBAND, index)); }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
// Windows/Control/Static.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_CONTROL_STATIC_H
|
||||
#define ZIP7_INC_WINDOWS_CONTROL_STATIC_H
|
||||
|
||||
#include "../Window.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NControl {
|
||||
|
||||
class CStatic: public CWindow
|
||||
{
|
||||
public:
|
||||
HANDLE SetImage(WPARAM imageType, HANDLE handle) { return (HANDLE)SendMsg(STM_SETIMAGE, imageType, (LPARAM)handle); }
|
||||
HANDLE GetImage(WPARAM imageType) { return (HANDLE)SendMsg(STM_GETIMAGE, imageType, 0); }
|
||||
|
||||
#ifdef UNDER_CE
|
||||
HICON SetIcon(HICON icon) { return (HICON)SetImage(IMAGE_ICON, icon); }
|
||||
HICON GetIcon() { return (HICON)GetImage(IMAGE_ICON); }
|
||||
#else
|
||||
HICON SetIcon(HICON icon) { return (HICON)SendMsg(STM_SETICON, (WPARAM)icon, 0); }
|
||||
HICON GetIcon() { return (HICON)SendMsg(STM_GETICON, 0, 0); }
|
||||
#endif
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
// Windows/Control/StatusBar.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_CONTROL_STATUSBAR_H
|
||||
#define ZIP7_INC_WINDOWS_CONTROL_STATUSBAR_H
|
||||
|
||||
#include "../Window.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NControl {
|
||||
|
||||
class CStatusBar: public NWindows::CWindow
|
||||
{
|
||||
public:
|
||||
bool Create(LONG style, LPCTSTR text, HWND hwndParent, UINT id)
|
||||
{ return (_window = ::CreateStatusWindow(style, text, hwndParent, id)) != NULL; }
|
||||
bool SetText(LPCTSTR text)
|
||||
{ return CWindow::SetText(text); }
|
||||
bool SetText(unsigned index, LPCTSTR text, UINT type)
|
||||
{ return LRESULTToBool(SendMsg(SB_SETTEXT, index | type, (LPARAM)text)); }
|
||||
bool SetText(unsigned index, LPCTSTR text)
|
||||
{ return SetText(index, text, 0); }
|
||||
|
||||
#ifndef _UNICODE
|
||||
bool Create(LONG style, LPCWSTR text, HWND hwndParent, UINT id)
|
||||
{ return (_window = ::CreateStatusWindowW(style, text, hwndParent, id)) != NULL; }
|
||||
bool SetText(LPCWSTR text)
|
||||
{ return CWindow::SetText(text); }
|
||||
bool SetText(unsigned index, LPCWSTR text, UINT type)
|
||||
{ return LRESULTToBool(SendMsg(SB_SETTEXTW, index | type, (LPARAM)text)); }
|
||||
bool SetText(unsigned index, LPCWSTR text)
|
||||
{ return SetText(index, text, 0); }
|
||||
#endif
|
||||
|
||||
bool SetParts(unsigned numParts, const int *edgePostions)
|
||||
{ return LRESULTToBool(SendMsg(SB_SETPARTS, numParts, (LPARAM)edgePostions)); }
|
||||
void Simple(bool simple)
|
||||
{ SendMsg(SB_SIMPLE, (WPARAM)BoolToBOOL(simple), 0); }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
// StdAfx.h
|
||||
|
||||
#ifndef ZIP7_INC_STDAFX_H
|
||||
#define ZIP7_INC_STDAFX_H
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1800
|
||||
#pragma warning(disable : 4464) // relative include path contains '..'
|
||||
#endif
|
||||
#include "../../Common/Common.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
// Windows/Control/ToolBar.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_CONTROL_TOOLBAR_H
|
||||
#define ZIP7_INC_WINDOWS_CONTROL_TOOLBAR_H
|
||||
|
||||
#include "../Window.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NControl {
|
||||
|
||||
class CToolBar: public NWindows::CWindow
|
||||
{
|
||||
public:
|
||||
void AutoSize() { SendMsg(TB_AUTOSIZE, 0, 0); }
|
||||
DWORD GetButtonSize() { return (DWORD)SendMsg(TB_GETBUTTONSIZE, 0, 0); }
|
||||
|
||||
bool GetMaxSize(LPSIZE size)
|
||||
#ifdef UNDER_CE
|
||||
{
|
||||
// maybe it must be fixed for more than 1 buttons
|
||||
const DWORD val = GetButtonSize();
|
||||
size->cx = LOWORD(val);
|
||||
size->cy = HIWORD(val);
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
{
|
||||
return LRESULTToBool(SendMsg(TB_GETMAXSIZE, 0, (LPARAM)size));
|
||||
}
|
||||
#endif
|
||||
|
||||
bool EnableButton(UINT buttonID, bool enable) { return LRESULTToBool(SendMsg(TB_ENABLEBUTTON, buttonID, MAKELONG(BoolToBOOL(enable), 0))); }
|
||||
void ButtonStructSize() { SendMsg(TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON)); }
|
||||
HIMAGELIST SetImageList(UINT listIndex, HIMAGELIST imageList) { return HIMAGELIST(SendMsg(TB_SETIMAGELIST, listIndex, (LPARAM)imageList)); }
|
||||
bool AddButton(UINT numButtons, LPTBBUTTON buttons) { return LRESULTToBool(SendMsg(TB_ADDBUTTONS, numButtons, (LPARAM)buttons)); }
|
||||
#ifndef _UNICODE
|
||||
bool AddButtonW(UINT numButtons, LPTBBUTTON buttons) { return LRESULTToBool(SendMsg(TB_ADDBUTTONSW, numButtons, (LPARAM)buttons)); }
|
||||
#endif
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
// Windows/Control/Trackbar.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_CONTROL_TRACKBAR_H
|
||||
#define ZIP7_INC_WINDOWS_CONTROL_TRACKBAR_H
|
||||
|
||||
#include "../Window.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NControl {
|
||||
|
||||
class CTrackbar: public CWindow
|
||||
{
|
||||
public:
|
||||
void SetRange(int minimum, int maximum, bool redraw = true)
|
||||
{ SendMsg(TBM_SETRANGE, BoolToBOOL(redraw), MAKELONG(minimum, maximum)); }
|
||||
void SetPos(int pos, bool redraw = true)
|
||||
{ SendMsg(TBM_SETPOS, BoolToBOOL(redraw), pos); }
|
||||
void SetTicFreq(int freq)
|
||||
{ SendMsg(TBM_SETTICFREQ, freq); }
|
||||
|
||||
int GetPos()
|
||||
{ return (int)SendMsg(TBM_GETPOS); }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,202 @@
|
||||
// Windows/Control/Window2.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
#include "../../Common/StringConvert.h"
|
||||
#endif
|
||||
|
||||
#include "Window2.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
|
||||
namespace NWindows {
|
||||
|
||||
#ifndef _UNICODE
|
||||
ATOM MyRegisterClass(CONST WNDCLASSW *wndClass);
|
||||
#endif
|
||||
|
||||
namespace NControl {
|
||||
|
||||
#ifdef UNDER_CE
|
||||
#define MY_START_WM_CREATE WM_CREATE
|
||||
#else
|
||||
#define MY_START_WM_CREATE WM_NCCREATE
|
||||
#endif
|
||||
|
||||
static LRESULT CALLBACK WindowProcedure(HWND aHWND, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
CWindow tempWindow(aHWND);
|
||||
if (message == MY_START_WM_CREATE)
|
||||
tempWindow.SetUserDataLongPtr((LONG_PTR)(((LPCREATESTRUCT)lParam)->lpCreateParams));
|
||||
CWindow2 *window = (CWindow2 *)(tempWindow.GetUserDataLongPtr());
|
||||
if (window && message == MY_START_WM_CREATE)
|
||||
window->Attach(aHWND);
|
||||
if (!window)
|
||||
{
|
||||
#ifndef _UNICODE
|
||||
if (g_IsNT)
|
||||
return DefWindowProcW(aHWND, message, wParam, lParam);
|
||||
else
|
||||
#endif
|
||||
return DefWindowProc(aHWND, message, wParam, lParam);
|
||||
}
|
||||
return window->OnMessage(message, wParam, lParam);
|
||||
}
|
||||
|
||||
bool CWindow2::CreateEx(DWORD exStyle, LPCTSTR className, LPCTSTR windowName,
|
||||
DWORD style, int x, int y, int width, int height,
|
||||
HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance)
|
||||
{
|
||||
WNDCLASS wc;
|
||||
if (!::GetClassInfo(instance, className, &wc))
|
||||
{
|
||||
// wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wc.style = 0;
|
||||
wc.lpfnWndProc = WindowProcedure;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = instance;
|
||||
wc.hIcon = NULL;
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||
wc.lpszMenuName = NULL;
|
||||
wc.lpszClassName = className;
|
||||
if (::RegisterClass(&wc) == 0)
|
||||
return false;
|
||||
}
|
||||
return CWindow::CreateEx(exStyle, className, windowName, style,
|
||||
x, y, width, height, parentWindow, idOrHMenu, instance, this);
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
|
||||
bool CWindow2::CreateEx(DWORD exStyle, LPCWSTR className, LPCWSTR windowName,
|
||||
DWORD style, int x, int y, int width, int height,
|
||||
HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance)
|
||||
{
|
||||
bool needRegister;
|
||||
if (g_IsNT)
|
||||
{
|
||||
WNDCLASSW wc;
|
||||
needRegister = ::GetClassInfoW(instance, className, &wc) == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
WNDCLASSA windowClassA;
|
||||
AString classNameA;
|
||||
LPCSTR classNameP;
|
||||
if (IS_INTRESOURCE(className))
|
||||
classNameP = (LPCSTR)className;
|
||||
else
|
||||
{
|
||||
classNameA = GetSystemString(className);
|
||||
classNameP = classNameA;
|
||||
}
|
||||
needRegister = ::GetClassInfoA(instance, classNameP, &windowClassA) == 0;
|
||||
}
|
||||
if (needRegister)
|
||||
{
|
||||
WNDCLASSW wc;
|
||||
// wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wc.style = 0;
|
||||
wc.lpfnWndProc = WindowProcedure;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = instance;
|
||||
wc.hIcon = NULL;
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||
wc.lpszMenuName = NULL;
|
||||
wc.lpszClassName = className;
|
||||
if (MyRegisterClass(&wc) == 0)
|
||||
return false;
|
||||
}
|
||||
return CWindow::CreateEx(exStyle, className, windowName, style,
|
||||
x, y, width, height, parentWindow, idOrHMenu, instance, this);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
LRESULT CWindow2::DefProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
#ifndef _UNICODE
|
||||
if (g_IsNT)
|
||||
return DefWindowProcW(_window, message, wParam, lParam);
|
||||
else
|
||||
#endif
|
||||
return DefWindowProc(_window, message, wParam, lParam);
|
||||
}
|
||||
|
||||
LRESULT CWindow2::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
LRESULT result;
|
||||
switch (message)
|
||||
{
|
||||
case WM_CREATE:
|
||||
if (!OnCreate((CREATESTRUCT *)lParam))
|
||||
return -1;
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
if (OnCommand(HIWORD(wParam), LOWORD(wParam), lParam, result))
|
||||
return result;
|
||||
break;
|
||||
case WM_NOTIFY:
|
||||
if (OnNotify((UINT)wParam, (LPNMHDR) lParam, result))
|
||||
return result;
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
OnDestroy();
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
OnClose();
|
||||
return 0;
|
||||
case WM_SIZE:
|
||||
if (OnSize(wParam, LOWORD(lParam), HIWORD(lParam)))
|
||||
return 0;
|
||||
}
|
||||
return DefProc(message, wParam, lParam);
|
||||
}
|
||||
|
||||
/*
|
||||
bool CWindow2::OnCommand2(WPARAM wParam, LPARAM lParam, LRESULT &result)
|
||||
{
|
||||
return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam, result);
|
||||
}
|
||||
*/
|
||||
|
||||
bool CWindow2::OnCommand(unsigned /* code */, unsigned /* itemID */, LPARAM /* lParam */, LRESULT & /* result */)
|
||||
{
|
||||
return false;
|
||||
// return DefProc(message, wParam, lParam);
|
||||
/*
|
||||
if (code == BN_CLICKED)
|
||||
return OnButtonClicked(itemID, (HWND)lParam);
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
bool CDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
|
||||
{
|
||||
switch (buttonID)
|
||||
{
|
||||
case IDOK:
|
||||
OnOK();
|
||||
break;
|
||||
case IDCANCEL:
|
||||
OnCancel();
|
||||
break;
|
||||
case IDHELP:
|
||||
OnHelp();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Windows/Control/Window2.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_CONTROL_WINDOW2_H
|
||||
#define ZIP7_INC_WINDOWS_CONTROL_WINDOW2_H
|
||||
|
||||
#include "../Window.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NControl {
|
||||
|
||||
class CWindow2: public CWindow
|
||||
{
|
||||
// Z7_CLASS_NO_COPY(CWindow2)
|
||||
|
||||
LRESULT DefProc(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
public:
|
||||
CWindow2(HWND newWindow = NULL): CWindow(newWindow) {}
|
||||
virtual ~CWindow2() {}
|
||||
|
||||
bool CreateEx(DWORD exStyle, LPCTSTR className, LPCTSTR windowName,
|
||||
DWORD style, int x, int y, int width, int height,
|
||||
HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance);
|
||||
|
||||
#ifndef _UNICODE
|
||||
bool CreateEx(DWORD exStyle, LPCWSTR className, LPCWSTR windowName,
|
||||
DWORD style, int x, int y, int width, int height,
|
||||
HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance);
|
||||
#endif
|
||||
|
||||
virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
virtual bool OnCreate(CREATESTRUCT * /* createStruct */) { return true; }
|
||||
// virtual LRESULT OnCommand(WPARAM wParam, LPARAM lParam);
|
||||
// bool OnCommand2(WPARAM wParam, LPARAM lParam, LRESULT &result);
|
||||
virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam, LRESULT &result);
|
||||
virtual bool OnSize(WPARAM /* wParam */, int /* xSize */, int /* ySize */) { return false; }
|
||||
virtual bool OnNotify(UINT /* controlID */, LPNMHDR /* lParam */, LRESULT & /* result */) { return false; }
|
||||
virtual void OnDestroy() { PostQuitMessage(0); }
|
||||
virtual void OnClose() { Destroy(); }
|
||||
/*
|
||||
virtual LRESULT OnHelp(LPHELPINFO helpInfo) { OnHelp(); }
|
||||
virtual LRESULT OnHelp() {};
|
||||
virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND);
|
||||
virtual void OnOK() {};
|
||||
virtual void OnCancel() {};
|
||||
*/
|
||||
|
||||
LONG_PTR SetMsgResult(LONG_PTR newLongPtr) { return SetLongPtr(DWLP_MSGRESULT, newLongPtr); }
|
||||
LONG_PTR GetMsgResult() const { return GetLongPtr(DWLP_MSGRESULT); }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,178 @@
|
||||
// Windows/DLL.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "DLL.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifndef _UNICODE
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
|
||||
extern HINSTANCE g_hInstance;
|
||||
|
||||
namespace NWindows {
|
||||
namespace NDLL {
|
||||
|
||||
bool CLibrary::Free() throw()
|
||||
{
|
||||
if (_module == NULL)
|
||||
return true;
|
||||
if (!::FreeLibrary(_module))
|
||||
return false;
|
||||
_module = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLibrary::LoadEx(CFSTR path, DWORD flags) throw()
|
||||
{
|
||||
if (!Free())
|
||||
return false;
|
||||
#ifndef _UNICODE
|
||||
if (!g_IsNT)
|
||||
{
|
||||
_module = ::LoadLibraryEx(fs2fas(path), NULL, flags);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
_module = ::LoadLibraryExW(fs2us(path), NULL, flags);
|
||||
}
|
||||
return (_module != NULL);
|
||||
}
|
||||
|
||||
bool CLibrary::Load(CFSTR path) throw()
|
||||
{
|
||||
if (!Free())
|
||||
return false;
|
||||
#ifndef _UNICODE
|
||||
if (!g_IsNT)
|
||||
{
|
||||
_module = ::LoadLibrary(fs2fas(path));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
_module = ::LoadLibraryW(fs2us(path));
|
||||
}
|
||||
return (_module != NULL);
|
||||
}
|
||||
|
||||
bool MyGetModuleFileName(FString &path)
|
||||
{
|
||||
const HMODULE hModule = g_hInstance;
|
||||
path.Empty();
|
||||
#ifndef _UNICODE
|
||||
if (!g_IsNT)
|
||||
{
|
||||
TCHAR s[MAX_PATH + 2];
|
||||
s[0] = 0;
|
||||
const DWORD size = ::GetModuleFileName(hModule, s, MAX_PATH + 1);
|
||||
if (size <= MAX_PATH && size != 0)
|
||||
{
|
||||
path = fas2fs(s);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
WCHAR s[MAX_PATH + 2];
|
||||
s[0] = 0;
|
||||
const DWORD size = ::GetModuleFileNameW(hModule, s, MAX_PATH + 1);
|
||||
if (size <= MAX_PATH && size != 0)
|
||||
{
|
||||
path = us2fs(s);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef Z7_SFX
|
||||
|
||||
FString GetModuleDirPrefix()
|
||||
{
|
||||
FString s;
|
||||
if (MyGetModuleFileName(s))
|
||||
{
|
||||
const int pos = s.ReverseFind_PathSepar();
|
||||
if (pos >= 0)
|
||||
s.DeleteFrom((unsigned)(pos + 1));
|
||||
}
|
||||
if (s.IsEmpty())
|
||||
s = "." STRING_PATH_SEPARATOR;
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}}
|
||||
|
||||
#else // _WIN32
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// FARPROC
|
||||
void *GetProcAddress(HMODULE module, LPCSTR procName)
|
||||
{
|
||||
void *ptr = NULL;
|
||||
if (module)
|
||||
ptr = dlsym(module, procName);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
namespace NWindows {
|
||||
namespace NDLL {
|
||||
|
||||
bool CLibrary::Free() throw()
|
||||
{
|
||||
if (!_module)
|
||||
return true;
|
||||
const int ret = dlclose(_module);
|
||||
if (ret != 0)
|
||||
return false;
|
||||
_module = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLibrary::Load(CFSTR path) throw()
|
||||
{
|
||||
if (!Free())
|
||||
return false;
|
||||
|
||||
int options = 0;
|
||||
|
||||
#ifdef RTLD_LOCAL
|
||||
options |= RTLD_LOCAL;
|
||||
#endif
|
||||
|
||||
#ifdef RTLD_NOW
|
||||
options |= RTLD_NOW;
|
||||
#endif
|
||||
|
||||
#ifdef RTLD_GROUP
|
||||
#if ! (defined(hpux) || defined(__hpux))
|
||||
options |= RTLD_GROUP; // mainly for solaris but not for HPUX
|
||||
#endif
|
||||
#endif
|
||||
|
||||
_module = dlopen(path, options);
|
||||
return (_module != NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
// FARPROC
|
||||
void * CLibrary::GetProc(LPCSTR procName) const
|
||||
{
|
||||
// return My_GetProcAddress(_module, procName);
|
||||
return local_GetProcAddress(_module, procName);
|
||||
// return NULL;
|
||||
}
|
||||
*/
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,103 @@
|
||||
// Windows/DLL.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_DLL_H
|
||||
#define ZIP7_INC_WINDOWS_DLL_H
|
||||
|
||||
#include "../Common/MyString.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
typedef void * HMODULE;
|
||||
// typedef int (*FARPROC)();
|
||||
// typedef void *FARPROC;
|
||||
void *GetProcAddress(HMODULE module, LPCSTR procName);
|
||||
#endif
|
||||
|
||||
namespace NWindows {
|
||||
namespace NDLL {
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/*
|
||||
#ifdef UNDER_CE
|
||||
#define My_GetProcAddress(module, procName) (void *)::GetProcAddressA(module, procName)
|
||||
#else
|
||||
#define My_GetProcAddress(module, procName) (void *)::GetProcAddress(module, procName)
|
||||
#endif
|
||||
*/
|
||||
|
||||
/* Win32: Don't call CLibrary::Free() and FreeLibrary() from another
|
||||
FreeLibrary() code: detaching code in DLL entry-point or in
|
||||
destructors of global objects in DLL module. */
|
||||
|
||||
class CLibrary
|
||||
{
|
||||
HMODULE _module;
|
||||
|
||||
// Z7_CLASS_NO_COPY(CLibrary);
|
||||
// copy constructor is required here
|
||||
public:
|
||||
CLibrary(): _module(NULL) {}
|
||||
~CLibrary() { Free(); }
|
||||
|
||||
CLibrary(const CLibrary &c): _module(NULL)
|
||||
{
|
||||
if (c._module)
|
||||
{
|
||||
// we need non const to reference from original item
|
||||
// c._module = NULL;
|
||||
throw 20230102;
|
||||
}
|
||||
}
|
||||
|
||||
HMODULE Get_HMODULE() const { return _module; }
|
||||
// operator HMODULE() const { return _module; }
|
||||
// HMODULE* operator&() { return &_module; }
|
||||
bool IsLoaded() const { return (_module != NULL); }
|
||||
|
||||
void Attach(HMODULE m)
|
||||
{
|
||||
Free();
|
||||
_module = m;
|
||||
}
|
||||
HMODULE Detach()
|
||||
{
|
||||
const HMODULE m = _module;
|
||||
_module = NULL;
|
||||
return m;
|
||||
}
|
||||
|
||||
bool Free() throw();
|
||||
bool LoadEx(CFSTR path, DWORD flags = LOAD_LIBRARY_AS_DATAFILE) throw();
|
||||
bool Load(CFSTR path) throw();
|
||||
// FARPROC
|
||||
// void *GetProc(LPCSTR procName) const { return My_GetProcAddress(_module, procName); }
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class CLibrary
|
||||
{
|
||||
HMODULE _module;
|
||||
|
||||
// Z7_CLASS_NO_COPY(CLibrary);
|
||||
public:
|
||||
CLibrary(): _module(NULL) {}
|
||||
~CLibrary() { Free(); }
|
||||
|
||||
HMODULE Get_HMODULE() const { return _module; }
|
||||
|
||||
bool Free() throw();
|
||||
bool Load(CFSTR path) throw();
|
||||
// FARPROC
|
||||
// void *GetProc(LPCSTR procName) const; // { return My_GetProcAddress(_module, procName); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
bool MyGetModuleFileName(FString &path);
|
||||
|
||||
FString GetModuleDirPrefix();
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
// Windows/Defs.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_DEFS_H
|
||||
#define ZIP7_INC_WINDOWS_DEFS_H
|
||||
|
||||
#include "../Common/MyWindows.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
inline BOOL BoolToBOOL(bool v) { return (v ? TRUE: FALSE); }
|
||||
#endif
|
||||
|
||||
inline bool BOOLToBool(BOOL v) { return (v != FALSE); }
|
||||
|
||||
inline VARIANT_BOOL BoolToVARIANT_BOOL(bool v) { return (v ? VARIANT_TRUE: VARIANT_FALSE); }
|
||||
inline bool VARIANT_BOOLToBool(VARIANT_BOOL v) { return (v != VARIANT_FALSE); }
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,133 @@
|
||||
// Windows/ErrorMsg.h
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#if !defined(_UNICODE) || !defined(_WIN32)
|
||||
#include "../Common/StringConvert.h"
|
||||
#endif
|
||||
|
||||
#include "ErrorMsg.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#if !defined(_UNICODE)
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace NWindows {
|
||||
namespace NError {
|
||||
|
||||
static bool MyFormatMessage(DWORD errorCode, UString &message)
|
||||
{
|
||||
#ifndef Z7_SFX
|
||||
if ((HRESULT)errorCode == MY_HRES_ERROR_INTERNAL_ERROR)
|
||||
{
|
||||
message = "Internal Error: The failure in hardware (RAM or CPU), OS or program";
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
LPVOID msgBuf;
|
||||
#ifndef _UNICODE
|
||||
if (!g_IsNT)
|
||||
{
|
||||
if (::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, errorCode, 0, (LPTSTR) &msgBuf, 0, NULL) == 0)
|
||||
return false;
|
||||
message = GetUnicodeString((LPCTSTR)msgBuf);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, errorCode, 0, (LPWSTR) &msgBuf, 0, NULL) == 0)
|
||||
return false;
|
||||
message = (LPCWSTR)msgBuf;
|
||||
}
|
||||
::LocalFree(msgBuf);
|
||||
return true;
|
||||
|
||||
#else // _WIN32
|
||||
|
||||
AString m;
|
||||
|
||||
const char *s = NULL;
|
||||
|
||||
switch ((Int32)errorCode)
|
||||
{
|
||||
// case ERROR_NO_MORE_FILES : s = "No more files"; break;
|
||||
// case ERROR_DIRECTORY : s = "Error Directory"; break;
|
||||
case E_NOTIMPL : s = "E_NOTIMPL : Not implemented"; break;
|
||||
case E_NOINTERFACE : s = "E_NOINTERFACE : No such interface supported"; break;
|
||||
case E_ABORT : s = "E_ABORT : Operation aborted"; break;
|
||||
case E_FAIL : s = "E_FAIL : Unspecified error"; break;
|
||||
|
||||
case STG_E_INVALIDFUNCTION : s = "STG_E_INVALIDFUNCTION"; break;
|
||||
case CLASS_E_CLASSNOTAVAILABLE : s = "CLASS_E_CLASSNOTAVAILABLE"; break;
|
||||
|
||||
case E_OUTOFMEMORY : s = "E_OUTOFMEMORY : Can't allocate required memory"; break;
|
||||
case E_INVALIDARG : s = "E_INVALIDARG : One or more arguments are invalid"; break;
|
||||
|
||||
// case MY_E_ERROR_NEGATIVE_SEEK : s = "MY_E_ERROR_NEGATIVE_SEEK"; break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* strerror() for unknown errors still shows message "Unknown error -12345678")
|
||||
So we must transfer error codes before strerror() */
|
||||
if (!s)
|
||||
{
|
||||
if ((errorCode & 0xFFFF0000) == (UInt32)((MY_FACILITY_WRes << 16) | 0x80000000))
|
||||
errorCode &= 0xFFFF;
|
||||
else if ((errorCode & ((UInt32)1 << 31)))
|
||||
return false; // we will show hex error later for that case
|
||||
|
||||
s = strerror((int)errorCode);
|
||||
|
||||
// if (!s)
|
||||
{
|
||||
m += "errno=";
|
||||
m.Add_UInt32(errorCode);
|
||||
if (s)
|
||||
m += " : ";
|
||||
}
|
||||
}
|
||||
|
||||
if (s)
|
||||
m += s;
|
||||
|
||||
MultiByteToUnicodeString2(message, m);
|
||||
return true;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
UString MyFormatMessage(DWORD errorCode)
|
||||
{
|
||||
UString m;
|
||||
if (!MyFormatMessage(errorCode, m) || m.IsEmpty())
|
||||
{
|
||||
char s[16];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
unsigned t = errorCode & 0xF;
|
||||
errorCode >>= 4;
|
||||
s[7 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
|
||||
}
|
||||
s[8] = 0;
|
||||
m += "Error #";
|
||||
m += s;
|
||||
}
|
||||
else if (m.Len() >= 2
|
||||
&& m[m.Len() - 1] == 0x0A
|
||||
&& m[m.Len() - 2] == 0x0D)
|
||||
m.DeleteFrom(m.Len() - 2);
|
||||
return m;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Windows/ErrorMsg.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_ERROR_MSG_H
|
||||
#define ZIP7_INC_WINDOWS_ERROR_MSG_H
|
||||
|
||||
#include "../Common/MyString.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NError {
|
||||
|
||||
UString MyFormatMessage(DWORD errorCode);
|
||||
inline UString MyFormatMessage(HRESULT errorCode) { return MyFormatMessage((DWORD)errorCode); }
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,172 @@
|
||||
// Windows/FileDir.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_FILE_DIR_H
|
||||
#define ZIP7_INC_WINDOWS_FILE_DIR_H
|
||||
|
||||
#include "../Common/MyString.h"
|
||||
|
||||
#include "FileIO.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NFile {
|
||||
namespace NDir {
|
||||
|
||||
bool GetWindowsDir(FString &path);
|
||||
bool GetSystemDir(FString &path);
|
||||
|
||||
/*
|
||||
WIN32 API : SetFileTime() doesn't allow to set zero timestamps in file
|
||||
but linux : allows unix time = 0 in filesystem
|
||||
*/
|
||||
/*
|
||||
SetDirTime() can be used to set time for file or for dir.
|
||||
If path is symbolic link, SetDirTime() will follow symbolic link,
|
||||
and it will set timestamps of symbolic link's target file or dir.
|
||||
*/
|
||||
bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime);
|
||||
|
||||
/*
|
||||
SetLinkFileTime() doesn't follow symbolic link,
|
||||
and it sets timestamps for symbolic link file itself.
|
||||
If (path) is not symbolic link, it still can work (at least in some new OS versions).
|
||||
*/
|
||||
bool SetLinkFileTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime);
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
bool SetFileAttrib(CFSTR path, DWORD attrib);
|
||||
|
||||
/*
|
||||
Some programs store posix attributes in high 16 bits of windows attributes field.
|
||||
Also some programs use additional flag markers: 0x8000 or 0x4000.
|
||||
SetFileAttrib_PosixHighDetect() tries to detect posix field, and it extracts only attribute
|
||||
bits that are related to current system only.
|
||||
*/
|
||||
#else
|
||||
|
||||
int my_chown(CFSTR path, uid_t owner, gid_t group);
|
||||
|
||||
#endif
|
||||
|
||||
bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib);
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
#define PROGRESS_CONTINUE 0
|
||||
#define PROGRESS_CANCEL 1
|
||||
// #define PROGRESS_STOP 2
|
||||
// #define PROGRESS_QUIET 3
|
||||
#endif
|
||||
Z7_PURE_INTERFACES_BEGIN
|
||||
DECLARE_INTERFACE(ICopyFileProgress)
|
||||
{
|
||||
// in: total, current: include all/processed alt streams.
|
||||
// it returns PROGRESS_CONTINUE or PROGRESS_CANCEL.
|
||||
virtual DWORD CopyFileProgress(UInt64 total, UInt64 current) = 0;
|
||||
};
|
||||
Z7_PURE_INTERFACES_END
|
||||
|
||||
bool MyMoveFile(CFSTR existFileName, CFSTR newFileName);
|
||||
// (progress == NULL) is allowed
|
||||
bool MyMoveFile_with_Progress(CFSTR oldFile, CFSTR newFile,
|
||||
ICopyFileProgress *progress);
|
||||
|
||||
|
||||
#ifndef UNDER_CE
|
||||
bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName);
|
||||
#endif
|
||||
|
||||
bool RemoveDir(CFSTR path);
|
||||
bool CreateDir(CFSTR path);
|
||||
|
||||
/* CreateComplexDir returns true, if directory can contain files after the call (two cases):
|
||||
1) the directory already exists (network shares and drive paths are supported)
|
||||
2) the directory was created
|
||||
path can be WITH or WITHOUT trailing path separator. */
|
||||
|
||||
bool CreateComplexDir(CFSTR path);
|
||||
|
||||
bool DeleteFileAlways(CFSTR name);
|
||||
bool RemoveDirWithSubItems(const FString &path);
|
||||
#ifdef _WIN32
|
||||
bool RemoveDirAlways_if_Empty(const FString &path);
|
||||
#else
|
||||
#define RemoveDirAlways_if_Empty RemoveDir
|
||||
#endif
|
||||
|
||||
bool MyGetFullPathName(CFSTR path, FString &resFullPath);
|
||||
bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName);
|
||||
bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix);
|
||||
|
||||
#ifndef UNDER_CE
|
||||
|
||||
bool SetCurrentDir(CFSTR path);
|
||||
bool GetCurrentDir(FString &resultPath);
|
||||
|
||||
#endif
|
||||
|
||||
bool MyGetTempPath(FString &resultPath);
|
||||
|
||||
bool CreateTempFile2(CFSTR prefix, bool addRandom, AString &postfix, NIO::COutFile *outFile);
|
||||
|
||||
class CTempFile MY_UNCOPYABLE
|
||||
{
|
||||
bool _mustBeDeleted;
|
||||
FString _path;
|
||||
void DisableDeleting() { _mustBeDeleted = false; }
|
||||
public:
|
||||
CTempFile(): _mustBeDeleted(false) {}
|
||||
~CTempFile() { Remove(); }
|
||||
const FString &GetPath() const { return _path; }
|
||||
bool Create(CFSTR pathPrefix, NIO::COutFile *outFile); // pathPrefix is not folder prefix
|
||||
bool CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile);
|
||||
bool Remove();
|
||||
// bool MoveTo(CFSTR name, bool deleteDestBefore);
|
||||
bool MoveTo(CFSTR name, bool deleteDestBefore,
|
||||
ICopyFileProgress *progress);
|
||||
};
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
class CTempDir MY_UNCOPYABLE
|
||||
{
|
||||
bool _mustBeDeleted;
|
||||
FString _path;
|
||||
public:
|
||||
CTempDir(): _mustBeDeleted(false) {}
|
||||
~CTempDir() { Remove(); }
|
||||
const FString &GetPath() const { return _path; }
|
||||
void DisableDeleting() { _mustBeDeleted = false; }
|
||||
bool Create(CFSTR namePrefix) ;
|
||||
bool Remove();
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(UNDER_CE)
|
||||
class CCurrentDirRestorer MY_UNCOPYABLE
|
||||
{
|
||||
FString _path;
|
||||
public:
|
||||
bool NeedRestore;
|
||||
|
||||
CCurrentDirRestorer(): NeedRestore(true)
|
||||
{
|
||||
GetCurrentDir(_path);
|
||||
}
|
||||
~CCurrentDirRestorer()
|
||||
{
|
||||
if (!NeedRestore)
|
||||
return;
|
||||
FString s;
|
||||
if (GetCurrentDir(s))
|
||||
if (s != _path)
|
||||
SetCurrentDir(_path);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,347 @@
|
||||
// Windows/FileFind.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_FILE_FIND_H
|
||||
#define ZIP7_INC_WINDOWS_FILE_FIND_H
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
#include "../Common/MyLinux.h"
|
||||
#include "../Common/MyString.h"
|
||||
#include "../Common/MyWindows.h"
|
||||
|
||||
#include "Defs.h"
|
||||
|
||||
#include "FileIO.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NFile {
|
||||
namespace NFind {
|
||||
|
||||
// bool DoesFileExist(CFSTR name, bool followLink);
|
||||
bool DoesFileExist_Raw(CFSTR name);
|
||||
bool DoesFileExist_FollowLink(CFSTR name);
|
||||
bool DoesDirExist(CFSTR name, bool followLink);
|
||||
|
||||
inline bool DoesDirExist(CFSTR name)
|
||||
{ return DoesDirExist(name, false); }
|
||||
inline bool DoesDirExist_FollowLink(CFSTR name)
|
||||
{ return DoesDirExist(name, true); }
|
||||
|
||||
// it's always _Raw
|
||||
bool DoesFileOrDirExist(CFSTR name);
|
||||
|
||||
DWORD GetFileAttrib(CFSTR path);
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
namespace NAttributes
|
||||
{
|
||||
inline bool IsReadOnly(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_READONLY) != 0; }
|
||||
inline bool IsHidden(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_HIDDEN) != 0; }
|
||||
inline bool IsSystem(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_SYSTEM) != 0; }
|
||||
inline bool IsDir(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; }
|
||||
inline bool IsArchived(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ARCHIVE) != 0; }
|
||||
inline bool IsCompressed(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_COMPRESSED) != 0; }
|
||||
inline bool IsEncrypted(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ENCRYPTED) != 0; }
|
||||
|
||||
inline UInt32 Get_PosixMode_From_WinAttrib(DWORD attrib)
|
||||
{
|
||||
UInt32 v = IsDir(attrib) ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG;
|
||||
/* 21.06: as WSL we allow write permissions (0222) for directories even for (FILE_ATTRIBUTE_READONLY).
|
||||
So extracting at Linux will be allowed to write files inside (0777) directories. */
|
||||
v |= ((IsReadOnly(attrib) && !IsDir(attrib)) ? 0555 : 0777);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode);
|
||||
|
||||
#endif
|
||||
|
||||
class CFileInfoBase
|
||||
{
|
||||
#ifdef _WIN32
|
||||
bool MatchesMask(UINT32 mask) const { return ((Attrib & mask) != 0); }
|
||||
#endif
|
||||
public:
|
||||
UInt64 Size;
|
||||
CFiTime CTime;
|
||||
CFiTime ATime;
|
||||
CFiTime MTime;
|
||||
#ifdef _WIN32
|
||||
DWORD Attrib;
|
||||
bool IsAltStream;
|
||||
bool IsDevice;
|
||||
|
||||
/*
|
||||
#ifdef UNDER_CE
|
||||
DWORD ObjectID;
|
||||
#else
|
||||
UINT32 ReparseTag;
|
||||
#endif
|
||||
*/
|
||||
#else
|
||||
dev_t dev; /* ID of device containing file */
|
||||
ino_t ino;
|
||||
mode_t mode;
|
||||
nlink_t nlink;
|
||||
uid_t uid; /* user ID of owner */
|
||||
gid_t gid; /* group ID of owner */
|
||||
dev_t rdev; /* device ID (defined, if S_ISCHR(mode) || S_ISBLK(mode)) */
|
||||
// bool Use_lstat;
|
||||
#endif
|
||||
|
||||
CFileInfoBase() { ClearBase(); }
|
||||
void ClearBase() throw();
|
||||
bool SetAs_StdInFile();
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
bool Fill_From_ByHandleFileInfo(CFSTR path);
|
||||
void SetAsDir() { Attrib = FILE_ATTRIBUTE_DIRECTORY; } // |= (FILE_ATTRIBUTE_UNIX_EXTENSION + (S_IFDIR << 16));
|
||||
|
||||
bool IsArchived() const { return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); }
|
||||
bool IsCompressed() const { return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); }
|
||||
bool IsDir() const { return MatchesMask(FILE_ATTRIBUTE_DIRECTORY); }
|
||||
bool IsEncrypted() const { return MatchesMask(FILE_ATTRIBUTE_ENCRYPTED); }
|
||||
bool IsHidden() const { return MatchesMask(FILE_ATTRIBUTE_HIDDEN); }
|
||||
bool IsNormal() const { return MatchesMask(FILE_ATTRIBUTE_NORMAL); }
|
||||
bool IsOffline() const { return MatchesMask(FILE_ATTRIBUTE_OFFLINE); }
|
||||
bool IsReadOnly() const { return MatchesMask(FILE_ATTRIBUTE_READONLY); }
|
||||
bool HasReparsePoint() const { return MatchesMask(FILE_ATTRIBUTE_REPARSE_POINT); }
|
||||
bool IsSparse() const { return MatchesMask(FILE_ATTRIBUTE_SPARSE_FILE); }
|
||||
bool IsSystem() const { return MatchesMask(FILE_ATTRIBUTE_SYSTEM); }
|
||||
bool IsTemporary() const { return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); }
|
||||
|
||||
UInt32 GetWinAttrib() const { return Attrib; }
|
||||
UInt32 GetPosixAttrib() const
|
||||
{
|
||||
return NAttributes::Get_PosixMode_From_WinAttrib(Attrib);
|
||||
}
|
||||
bool Has_Attrib_ReparsePoint() const { return (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0; }
|
||||
|
||||
#else
|
||||
|
||||
UInt32 GetPosixAttrib() const { return mode; }
|
||||
UInt32 GetWinAttrib() const { return Get_WinAttribPosix_From_PosixMode(mode); }
|
||||
|
||||
bool IsDir() const { return S_ISDIR(mode); }
|
||||
void SetAsDir() { mode = S_IFDIR | 0777; }
|
||||
void SetFrom_stat(const struct stat &st);
|
||||
|
||||
bool IsReadOnly() const
|
||||
{
|
||||
// does linux support writing to ReadOnly files?
|
||||
if ((mode & 0222) == 0) // S_IWUSR in p7zip
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsPosixLink() const { return S_ISLNK(mode); }
|
||||
|
||||
#endif
|
||||
|
||||
bool IsOsSymLink() const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return HasReparsePoint();
|
||||
#else
|
||||
return IsPosixLink();
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
struct CFileInfo: public CFileInfoBase
|
||||
{
|
||||
FString Name;
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
// FString ShortName;
|
||||
#endif
|
||||
|
||||
bool IsDots() const throw();
|
||||
bool Find(CFSTR path, bool followLink = false);
|
||||
bool Find_FollowLink(CFSTR path) { return Find(path, true); }
|
||||
|
||||
#ifdef _WIN32
|
||||
// bool Fill_From_ByHandleFileInfo(CFSTR path);
|
||||
// bool FollowReparse(CFSTR path, bool isDir);
|
||||
#else
|
||||
bool Find_DontFill_Name(CFSTR path, bool followLink = false);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
class CFindFileBase MY_UNCOPYABLE
|
||||
{
|
||||
protected:
|
||||
HANDLE _handle;
|
||||
public:
|
||||
bool IsHandleAllocated() const { return _handle != INVALID_HANDLE_VALUE; }
|
||||
CFindFileBase(): _handle(INVALID_HANDLE_VALUE) {}
|
||||
~CFindFileBase() { Close(); }
|
||||
bool Close() throw();
|
||||
};
|
||||
|
||||
class CFindFile: public CFindFileBase
|
||||
{
|
||||
public:
|
||||
bool FindFirst(CFSTR wildcard, CFileInfo &fileInfo);
|
||||
bool FindNext(CFileInfo &fileInfo);
|
||||
};
|
||||
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
|
||||
struct CStreamInfo
|
||||
{
|
||||
UString Name;
|
||||
UInt64 Size;
|
||||
|
||||
UString GetReducedName() const; // returns ":Name"
|
||||
// UString GetReducedName2() const; // returns "Name"
|
||||
bool IsMainStream() const throw();
|
||||
};
|
||||
|
||||
class CFindStream: public CFindFileBase
|
||||
{
|
||||
public:
|
||||
bool FindFirst(CFSTR filePath, CStreamInfo &streamInfo);
|
||||
bool FindNext(CStreamInfo &streamInfo);
|
||||
};
|
||||
|
||||
class CStreamEnumerator MY_UNCOPYABLE
|
||||
{
|
||||
CFindStream _find;
|
||||
FString _filePath;
|
||||
|
||||
bool NextAny(CFileInfo &fileInfo, bool &found);
|
||||
public:
|
||||
CStreamEnumerator(const FString &filePath): _filePath(filePath) {}
|
||||
bool Next(CStreamInfo &streamInfo, bool &found);
|
||||
};
|
||||
|
||||
#endif // defined(_WIN32) && !defined(UNDER_CE)
|
||||
|
||||
|
||||
class CEnumerator MY_UNCOPYABLE
|
||||
{
|
||||
CFindFile _findFile;
|
||||
FString _wildcard;
|
||||
|
||||
bool NextAny(CFileInfo &fileInfo);
|
||||
public:
|
||||
void SetDirPrefix(const FString &dirPrefix);
|
||||
bool Next(CFileInfo &fileInfo);
|
||||
bool Next(CFileInfo &fileInfo, bool &found);
|
||||
};
|
||||
|
||||
|
||||
class CFindChangeNotification MY_UNCOPYABLE
|
||||
{
|
||||
HANDLE _handle;
|
||||
public:
|
||||
operator HANDLE () { return _handle; }
|
||||
bool IsHandleAllocated() const
|
||||
{
|
||||
/* at least on win2000/XP (undocumented):
|
||||
if pathName is "" or NULL,
|
||||
FindFirstChangeNotification() could return NULL.
|
||||
So we check for INVALID_HANDLE_VALUE and NULL.
|
||||
*/
|
||||
return _handle != INVALID_HANDLE_VALUE && _handle != NULL;
|
||||
}
|
||||
CFindChangeNotification(): _handle(INVALID_HANDLE_VALUE) {}
|
||||
~CFindChangeNotification() { Close(); }
|
||||
bool Close() throw();
|
||||
HANDLE FindFirst(CFSTR pathName, bool watchSubtree, DWORD notifyFilter);
|
||||
bool FindNext() { return BOOLToBool(::FindNextChangeNotification(_handle)); }
|
||||
};
|
||||
|
||||
#ifndef UNDER_CE
|
||||
bool MyGetLogicalDriveStrings(CObjectVector<FString> &driveStrings);
|
||||
#endif
|
||||
|
||||
typedef CFileInfo CDirEntry;
|
||||
|
||||
|
||||
#else // WIN32
|
||||
|
||||
|
||||
struct CDirEntry
|
||||
{
|
||||
ino_t iNode;
|
||||
#if !defined(_AIX) && !defined(__sun) && !defined(__QNXNTO__)
|
||||
Byte Type;
|
||||
#endif
|
||||
FString Name;
|
||||
|
||||
/*
|
||||
#if !defined(_AIX) && !defined(__sun) && !defined(__QNXNTO__)
|
||||
bool IsDir() const
|
||||
{
|
||||
// (Type == DT_UNKNOWN) on some systems
|
||||
return Type == DT_DIR;
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
bool IsDots() const throw();
|
||||
};
|
||||
|
||||
class CEnumerator MY_UNCOPYABLE
|
||||
{
|
||||
DIR *_dir;
|
||||
FString _wildcard;
|
||||
|
||||
bool NextAny(CDirEntry &fileInfo, bool &found);
|
||||
public:
|
||||
CEnumerator(): _dir(NULL) {}
|
||||
~CEnumerator();
|
||||
void SetDirPrefix(const FString &dirPrefix);
|
||||
|
||||
bool Next(CDirEntry &fileInfo, bool &found);
|
||||
bool Fill_FileInfo(const CDirEntry &de, CFileInfo &fileInfo, bool followLink) const;
|
||||
bool DirEntry_IsDir(const CDirEntry &de, bool followLink) const
|
||||
{
|
||||
#if !defined(_AIX) && !defined(__sun) && !defined(__QNXNTO__)
|
||||
if (de.Type == DT_DIR)
|
||||
return true;
|
||||
if (de.Type != DT_UNKNOWN)
|
||||
return false;
|
||||
#endif
|
||||
CFileInfo fileInfo;
|
||||
if (Fill_FileInfo(de, fileInfo, followLink))
|
||||
{
|
||||
return fileInfo.IsDir();
|
||||
}
|
||||
return false; // change it
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
inline UInt32 Get_WinAttrib_From_PosixMode(UInt32 mode)
|
||||
{
|
||||
UInt32 attrib = S_ISDIR(mode) ?
|
||||
FILE_ATTRIBUTE_DIRECTORY :
|
||||
FILE_ATTRIBUTE_ARCHIVE;
|
||||
if ((st.st_mode & 0222) == 0) // check it !!!
|
||||
attrib |= FILE_ATTRIBUTE_READONLY;
|
||||
return attrib;
|
||||
}
|
||||
*/
|
||||
|
||||
// UInt32 Get_WinAttrib_From_stat(const struct stat &st);
|
||||
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,954 @@
|
||||
// Windows/FileIO.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#ifdef Z7_DEVICE_FILE
|
||||
#include "../../C/Alloc.h"
|
||||
#endif
|
||||
|
||||
// #include <stdio.h>
|
||||
|
||||
/*
|
||||
#ifndef _WIN32
|
||||
// for ioctl BLKGETSIZE64
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/fs.h>
|
||||
#endif
|
||||
*/
|
||||
|
||||
#include "FileIO.h"
|
||||
#include "FileName.h"
|
||||
|
||||
HRESULT GetLastError_noZero_HRESULT()
|
||||
{
|
||||
const DWORD res = ::GetLastError();
|
||||
if (res == 0)
|
||||
return E_FAIL;
|
||||
return HRESULT_FROM_WIN32(res);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifndef _UNICODE
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
|
||||
using namespace NWindows;
|
||||
using namespace NFile;
|
||||
using namespace NName;
|
||||
|
||||
namespace NWindows {
|
||||
namespace NFile {
|
||||
|
||||
#ifdef Z7_DEVICE_FILE
|
||||
|
||||
namespace NSystem
|
||||
{
|
||||
bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace NIO {
|
||||
|
||||
/*
|
||||
WinXP-64 CreateFile():
|
||||
"" - ERROR_PATH_NOT_FOUND
|
||||
:stream - OK
|
||||
.:stream - ERROR_PATH_NOT_FOUND
|
||||
.\:stream - OK
|
||||
|
||||
folder\:stream - ERROR_INVALID_NAME
|
||||
folder:stream - OK
|
||||
|
||||
c:\:stream - OK
|
||||
|
||||
c::stream - ERROR_INVALID_NAME, if current dir is NOT ROOT ( c:\dir1 )
|
||||
c::stream - OK, if current dir is ROOT ( c:\ )
|
||||
*/
|
||||
|
||||
bool CFileBase::Create(CFSTR path, DWORD desiredAccess,
|
||||
DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
|
||||
{
|
||||
if (!Close())
|
||||
return false;
|
||||
|
||||
#ifdef Z7_DEVICE_FILE
|
||||
IsDeviceFile = false;
|
||||
#endif
|
||||
|
||||
#ifndef _UNICODE
|
||||
if (!g_IsNT)
|
||||
{
|
||||
_handle = ::CreateFile(fs2fas(path), desiredAccess, shareMode,
|
||||
(LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
IF_USE_MAIN_PATH
|
||||
_handle = ::CreateFileW(fs2us(path), desiredAccess, shareMode,
|
||||
(LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL);
|
||||
#ifdef Z7_LONG_PATH
|
||||
if (_handle == INVALID_HANDLE_VALUE && USE_SUPER_PATH)
|
||||
{
|
||||
UString superPath;
|
||||
if (GetSuperPath(path, superPath, USE_MAIN_PATH))
|
||||
_handle = ::CreateFileW(superPath, desiredAccess, shareMode,
|
||||
(LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
#ifndef UNDER_CE
|
||||
#ifndef Z7_SFX
|
||||
if (_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
// it's debug hack to open symbolic links in Windows XP and WSL links in Windows 10
|
||||
DWORD lastError = GetLastError();
|
||||
if (lastError == ERROR_CANT_ACCESS_FILE)
|
||||
{
|
||||
CByteBuffer buf;
|
||||
if (NIO::GetReparseData(path, buf, NULL))
|
||||
{
|
||||
CReparseAttr attr;
|
||||
if (attr.Parse(buf, buf.Size()))
|
||||
{
|
||||
FString dirPrefix, fileName;
|
||||
if (NDir::GetFullPathAndSplit(path, dirPrefix, fileName))
|
||||
{
|
||||
FString fullPath;
|
||||
if (GetFullPath(dirPrefix, us2fs(attr.GetPath()), fullPath))
|
||||
{
|
||||
// FIX IT: recursion levels must be restricted
|
||||
return Create(fullPath, desiredAccess,
|
||||
shareMode, creationDisposition, flagsAndAttributes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SetLastError(lastError);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
*/
|
||||
|
||||
return (_handle != INVALID_HANDLE_VALUE);
|
||||
}
|
||||
|
||||
bool CFileBase::Close() throw()
|
||||
{
|
||||
if (_handle == INVALID_HANDLE_VALUE)
|
||||
return true;
|
||||
#if 0
|
||||
if (!IsStdStream)
|
||||
#endif
|
||||
{
|
||||
if (!::CloseHandle(_handle))
|
||||
return false;
|
||||
}
|
||||
#if 0
|
||||
IsStdStream = false;
|
||||
IsStdPipeStream = false;
|
||||
#endif
|
||||
_handle = INVALID_HANDLE_VALUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CFileBase::GetLength(UInt64 &length) const throw()
|
||||
{
|
||||
#ifdef Z7_DEVICE_FILE
|
||||
if (IsDeviceFile && SizeDefined)
|
||||
{
|
||||
length = Size;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
DWORD high = 0;
|
||||
const DWORD low = ::GetFileSize(_handle, &high);
|
||||
if (low == INVALID_FILE_SIZE)
|
||||
if (::GetLastError() != NO_ERROR)
|
||||
return false;
|
||||
length = (((UInt64)high) << 32) + low;
|
||||
return true;
|
||||
|
||||
/*
|
||||
LARGE_INTEGER fileSize;
|
||||
// GetFileSizeEx() is unsupported in 98/ME/NT, and supported in Win2000+
|
||||
if (!GetFileSizeEx(_handle, &fileSize))
|
||||
return false;
|
||||
length = (UInt64)fileSize.QuadPart;
|
||||
return true;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/* Specification for SetFilePointer():
|
||||
|
||||
If a new file pointer is a negative value,
|
||||
{
|
||||
the function fails,
|
||||
the file pointer is not moved,
|
||||
the code returned by GetLastError() is ERROR_NEGATIVE_SEEK.
|
||||
}
|
||||
|
||||
If the hFile handle is opened with the FILE_FLAG_NO_BUFFERING flag set
|
||||
{
|
||||
an application can move the file pointer only to sector-aligned positions.
|
||||
A sector-aligned position is a position that is a whole number multiple of
|
||||
the volume sector size.
|
||||
An application can obtain a volume sector size by calling the GetDiskFreeSpace.
|
||||
}
|
||||
|
||||
It is not an error to set a file pointer to a position beyond the end of the file.
|
||||
The size of the file does not increase until you call the SetEndOfFile, WriteFile, or WriteFileEx function.
|
||||
|
||||
If the return value is INVALID_SET_FILE_POINTER and if lpDistanceToMoveHigh is non-NULL,
|
||||
an application must call GetLastError to determine whether or not the function has succeeded or failed.
|
||||
*/
|
||||
|
||||
bool CFileBase::GetPosition(UInt64 &position) const throw()
|
||||
{
|
||||
LONG high = 0;
|
||||
const DWORD low = ::SetFilePointer(_handle, 0, &high, FILE_CURRENT);
|
||||
if (low == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
|
||||
{
|
||||
// for error case we can set (position) to (-1) or (0) or leave (position) unchanged.
|
||||
// position = (UInt64)(Int64)-1; // for debug
|
||||
position = 0;
|
||||
return false;
|
||||
}
|
||||
position = (((UInt64)(UInt32)high) << 32) + low;
|
||||
return true;
|
||||
// we don't want recursed GetPosition()
|
||||
// return Seek(0, FILE_CURRENT, position);
|
||||
}
|
||||
|
||||
bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw()
|
||||
{
|
||||
#ifdef Z7_DEVICE_FILE
|
||||
if (IsDeviceFile && SizeDefined && moveMethod == FILE_END)
|
||||
{
|
||||
distanceToMove += Size;
|
||||
moveMethod = FILE_BEGIN;
|
||||
}
|
||||
#endif
|
||||
|
||||
LONG high = (LONG)(distanceToMove >> 32);
|
||||
const DWORD low = ::SetFilePointer(_handle, (LONG)(distanceToMove & 0xFFFFFFFF), &high, moveMethod);
|
||||
if (low == INVALID_SET_FILE_POINTER)
|
||||
{
|
||||
const DWORD lastError = ::GetLastError();
|
||||
if (lastError != NO_ERROR)
|
||||
{
|
||||
// 21.07: we set (newPosition) to real position even after error.
|
||||
GetPosition(newPosition);
|
||||
SetLastError(lastError); // restore LastError
|
||||
return false;
|
||||
}
|
||||
}
|
||||
newPosition = (((UInt64)(UInt32)high) << 32) + low;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CFileBase::Seek(UInt64 position, UInt64 &newPosition) const throw()
|
||||
{
|
||||
return Seek((Int64)position, FILE_BEGIN, newPosition);
|
||||
}
|
||||
|
||||
bool CFileBase::SeekToBegin() const throw()
|
||||
{
|
||||
UInt64 newPosition = 0;
|
||||
return Seek(0, newPosition) && (newPosition == 0);
|
||||
}
|
||||
|
||||
bool CFileBase::SeekToEnd(UInt64 &newPosition) const throw()
|
||||
{
|
||||
return Seek(0, FILE_END, newPosition);
|
||||
}
|
||||
|
||||
// ---------- CInFile ---------
|
||||
|
||||
#ifdef Z7_DEVICE_FILE
|
||||
|
||||
void CInFile::CorrectDeviceSize()
|
||||
{
|
||||
// maybe we must decrease kClusterSize to 1 << 12, if we want correct size at tail
|
||||
const UInt32 kClusterSize = 1 << 14;
|
||||
UInt64 pos = Size & ~(UInt64)(kClusterSize - 1);
|
||||
UInt64 realNewPosition;
|
||||
if (!Seek(pos, realNewPosition))
|
||||
return;
|
||||
Byte *buf = (Byte *)MidAlloc(kClusterSize);
|
||||
|
||||
bool needbackward = true;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
UInt32 processed = 0;
|
||||
// up test is slow for "PhysicalDrive".
|
||||
// processed size for latest block for "PhysicalDrive0" is 0.
|
||||
if (!Read1(buf, kClusterSize, processed))
|
||||
break;
|
||||
if (processed == 0)
|
||||
break;
|
||||
needbackward = false;
|
||||
Size = pos + processed;
|
||||
if (processed != kClusterSize)
|
||||
break;
|
||||
pos += kClusterSize;
|
||||
}
|
||||
|
||||
if (needbackward && pos != 0)
|
||||
{
|
||||
pos -= kClusterSize;
|
||||
for (;;)
|
||||
{
|
||||
// break;
|
||||
if (!Seek(pos, realNewPosition))
|
||||
break;
|
||||
if (!buf)
|
||||
{
|
||||
buf = (Byte *)MidAlloc(kClusterSize);
|
||||
if (!buf)
|
||||
break;
|
||||
}
|
||||
UInt32 processed = 0;
|
||||
// that code doesn't work for "PhysicalDrive0"
|
||||
if (!Read1(buf, kClusterSize, processed))
|
||||
break;
|
||||
if (processed != 0)
|
||||
{
|
||||
Size = pos + processed;
|
||||
break;
|
||||
}
|
||||
if (pos == 0)
|
||||
break;
|
||||
pos -= kClusterSize;
|
||||
}
|
||||
}
|
||||
MidFree(buf);
|
||||
}
|
||||
|
||||
|
||||
void CInFile::CalcDeviceSize(CFSTR s)
|
||||
{
|
||||
SizeDefined = false;
|
||||
Size = 0;
|
||||
if (_handle == INVALID_HANDLE_VALUE || !IsDeviceFile)
|
||||
return;
|
||||
#ifdef UNDER_CE
|
||||
|
||||
SizeDefined = true;
|
||||
Size = 128 << 20;
|
||||
|
||||
#else
|
||||
|
||||
PARTITION_INFORMATION partInfo;
|
||||
bool needCorrectSize = true;
|
||||
|
||||
/*
|
||||
WinXP 64-bit:
|
||||
|
||||
HDD \\.\PhysicalDrive0 (MBR):
|
||||
GetPartitionInfo == GeometryEx : corrrect size? (includes tail)
|
||||
Geometry : smaller than GeometryEx (no tail, maybe correct too?)
|
||||
MyGetDiskFreeSpace : FAIL
|
||||
Size correction is slow and block size (kClusterSize) must be small?
|
||||
|
||||
HDD partition \\.\N: (NTFS):
|
||||
MyGetDiskFreeSpace : Size of NTFS clusters. Same size can be calculated after correction
|
||||
GetPartitionInfo : size of partition data: NTFS clusters + TAIL; TAIL contains extra empty sectors and copy of first sector of NTFS
|
||||
Geometry / CdRomGeometry / GeometryEx : size of HDD (not that partition)
|
||||
|
||||
CD-ROM drive (ISO):
|
||||
MyGetDiskFreeSpace : correct size. Same size can be calculated after correction
|
||||
Geometry == CdRomGeometry : smaller than corrrect size
|
||||
GetPartitionInfo == GeometryEx : larger than corrrect size
|
||||
|
||||
Floppy \\.\a: (FAT):
|
||||
Geometry : correct size.
|
||||
CdRomGeometry / GeometryEx / GetPartitionInfo / MyGetDiskFreeSpace - FAIL
|
||||
correction works OK for FAT.
|
||||
correction works OK for non-FAT, if kClusterSize = 512.
|
||||
*/
|
||||
|
||||
if (GetPartitionInfo(&partInfo))
|
||||
{
|
||||
Size = (UInt64)partInfo.PartitionLength.QuadPart;
|
||||
SizeDefined = true;
|
||||
needCorrectSize = false;
|
||||
if ((s)[0] == '\\' && (s)[1] == '\\' && (s)[2] == '.' && (s)[3] == '\\' && (s)[5] == ':' && (s)[6] == 0)
|
||||
{
|
||||
FChar path[4] = { s[4], ':', '\\', 0 };
|
||||
UInt64 clusterSize, totalSize, freeSize;
|
||||
if (NSystem::MyGetDiskFreeSpace(path, clusterSize, totalSize, freeSize))
|
||||
Size = totalSize;
|
||||
else
|
||||
needCorrectSize = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!SizeDefined)
|
||||
{
|
||||
my_DISK_GEOMETRY_EX geomEx;
|
||||
SizeDefined = GetGeometryEx(&geomEx);
|
||||
if (SizeDefined)
|
||||
Size = (UInt64)geomEx.DiskSize.QuadPart;
|
||||
else
|
||||
{
|
||||
DISK_GEOMETRY geom;
|
||||
SizeDefined = GetGeometry(&geom);
|
||||
if (!SizeDefined)
|
||||
SizeDefined = GetCdRomGeometry(&geom);
|
||||
if (SizeDefined)
|
||||
Size = (UInt64)geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack * geom.BytesPerSector;
|
||||
}
|
||||
}
|
||||
|
||||
if (needCorrectSize && SizeDefined && Size != 0)
|
||||
{
|
||||
CorrectDeviceSize();
|
||||
SeekToBegin();
|
||||
}
|
||||
|
||||
// SeekToBegin();
|
||||
#endif
|
||||
}
|
||||
|
||||
// ((desiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE)) == 0 &&
|
||||
|
||||
#define MY_DEVICE_EXTRA_CODE \
|
||||
IsDeviceFile = IsDevicePath(fileName); \
|
||||
CalcDeviceSize(fileName);
|
||||
#else
|
||||
#define MY_DEVICE_EXTRA_CODE
|
||||
#endif
|
||||
|
||||
bool CInFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
|
||||
{
|
||||
DWORD desiredAccess = GENERIC_READ;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (PreserveATime)
|
||||
desiredAccess |= FILE_WRITE_ATTRIBUTES;
|
||||
#endif
|
||||
|
||||
bool res = Create(fileName, desiredAccess, shareMode, creationDisposition, flagsAndAttributes);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (res && PreserveATime)
|
||||
{
|
||||
FILETIME ft;
|
||||
ft.dwHighDateTime = ft.dwLowDateTime = 0xFFFFFFFF;
|
||||
::SetFileTime(_handle, NULL, &ft, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
MY_DEVICE_EXTRA_CODE
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CInFile::OpenShared(CFSTR fileName, bool shareForWrite)
|
||||
{ return Open(fileName, FILE_SHARE_READ | (shareForWrite ? FILE_SHARE_WRITE : 0), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); }
|
||||
|
||||
bool CInFile::Open(CFSTR fileName)
|
||||
{ return OpenShared(fileName, false); }
|
||||
|
||||
// ReadFile and WriteFile functions in Windows have BUG:
|
||||
// If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
|
||||
// from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
|
||||
// (Insufficient system resources exist to complete the requested service).
|
||||
|
||||
// Probably in some version of Windows there are problems with other sizes:
|
||||
// for 32 MB (maybe also for 16 MB).
|
||||
// And message can be "Network connection was lost"
|
||||
|
||||
static const UInt32 kChunkSizeMax = 1 << 22;
|
||||
|
||||
bool CInFile::Read1(void *data, UInt32 size, UInt32 &processedSize) throw()
|
||||
{
|
||||
DWORD processedLoc = 0;
|
||||
const bool res = BOOLToBool(::ReadFile(_handle, data, size, &processedLoc, NULL));
|
||||
processedSize = (UInt32)processedLoc;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CInFile::ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw()
|
||||
{
|
||||
#if 0
|
||||
const UInt32 chunkSizeMax = (0 || IsStdStream) ? (1 << 20) : kChunkSizeMax;
|
||||
if (size > chunkSizeMax)
|
||||
size = chunkSizeMax;
|
||||
#else
|
||||
if (size > kChunkSizeMax)
|
||||
size = kChunkSizeMax;
|
||||
#endif
|
||||
return Read1(data, size, processedSize);
|
||||
}
|
||||
|
||||
bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize) throw()
|
||||
{
|
||||
processedSize = 0;
|
||||
do
|
||||
{
|
||||
UInt32 processedLoc = 0;
|
||||
const bool res = ReadPart(data, size, processedLoc);
|
||||
processedSize += processedLoc;
|
||||
if (!res)
|
||||
return false;
|
||||
if (processedLoc == 0)
|
||||
return true;
|
||||
data = (void *)((Byte *)data + processedLoc);
|
||||
size -= processedLoc;
|
||||
}
|
||||
while (size);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CInFile::ReadFull(void *data, size_t size, size_t &processedSize) throw()
|
||||
{
|
||||
processedSize = 0;
|
||||
do
|
||||
{
|
||||
UInt32 processedLoc = 0;
|
||||
const UInt32 sizeLoc = (size > kChunkSizeMax ? (UInt32)kChunkSizeMax : (UInt32)size);
|
||||
const bool res = Read1(data, sizeLoc, processedLoc);
|
||||
processedSize += processedLoc;
|
||||
if (!res)
|
||||
return false;
|
||||
if (processedLoc == 0)
|
||||
return true;
|
||||
data = (void *)((Byte *)data + processedLoc);
|
||||
size -= processedLoc;
|
||||
}
|
||||
while (size);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------- COutFile ---------
|
||||
|
||||
bool COutFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
|
||||
{ return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); }
|
||||
|
||||
bool COutFile::Open_Disposition(CFSTR fileName, DWORD creationDisposition)
|
||||
{ return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); }
|
||||
|
||||
bool COutFile::Create_ALWAYS_with_Attribs(CFSTR fileName, DWORD flagsAndAttributes)
|
||||
{ return Open(fileName, FILE_SHARE_READ, CREATE_ALWAYS, flagsAndAttributes); }
|
||||
|
||||
bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw()
|
||||
{ return BOOLToBool(::SetFileTime(_handle, cTime, aTime, mTime)); }
|
||||
|
||||
bool COutFile::SetMTime(const FILETIME *mTime) throw() { return SetTime(NULL, NULL, mTime); }
|
||||
|
||||
bool COutFile::WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw()
|
||||
{
|
||||
if (size > kChunkSizeMax)
|
||||
size = kChunkSizeMax;
|
||||
DWORD processedLoc = 0;
|
||||
bool res = BOOLToBool(::WriteFile(_handle, data, size, &processedLoc, NULL));
|
||||
processedSize = (UInt32)processedLoc;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool COutFile::Write(const void *data, UInt32 size, UInt32 &processedSize) throw()
|
||||
{
|
||||
processedSize = 0;
|
||||
do
|
||||
{
|
||||
UInt32 processedLoc = 0;
|
||||
const bool res = WritePart(data, size, processedLoc);
|
||||
processedSize += processedLoc;
|
||||
if (!res)
|
||||
return false;
|
||||
if (processedLoc == 0)
|
||||
return true;
|
||||
data = (const void *)((const Byte *)data + processedLoc);
|
||||
size -= processedLoc;
|
||||
}
|
||||
while (size);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool COutFile::WriteFull(const void *data, size_t size) throw()
|
||||
{
|
||||
do
|
||||
{
|
||||
UInt32 processedLoc = 0;
|
||||
const UInt32 sizeCur = (size > kChunkSizeMax ? kChunkSizeMax : (UInt32)size);
|
||||
if (!WritePart(data, sizeCur, processedLoc))
|
||||
return false;
|
||||
if (processedLoc == 0)
|
||||
return (size == 0);
|
||||
data = (const void *)((const Byte *)data + processedLoc);
|
||||
size -= processedLoc;
|
||||
}
|
||||
while (size);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool COutFile::SetEndOfFile() throw() { return BOOLToBool(::SetEndOfFile(_handle)); }
|
||||
|
||||
bool COutFile::SetLength(UInt64 length) throw()
|
||||
{
|
||||
UInt64 newPosition;
|
||||
if (!Seek(length, newPosition))
|
||||
return false;
|
||||
if (newPosition != length)
|
||||
return false;
|
||||
return SetEndOfFile();
|
||||
}
|
||||
|
||||
bool COutFile::SetLength_KeepPosition(UInt64 length) throw()
|
||||
{
|
||||
UInt64 currentPos = 0;
|
||||
if (!GetPosition(currentPos))
|
||||
return false;
|
||||
DWORD lastError = 0;
|
||||
const bool result = SetLength(length);
|
||||
if (!result)
|
||||
lastError = GetLastError();
|
||||
UInt64 currentPos2;
|
||||
const bool result2 = Seek(currentPos, currentPos2);
|
||||
if (lastError != 0)
|
||||
SetLastError(lastError);
|
||||
return (result && result2);
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
#else // _WIN32
|
||||
|
||||
|
||||
// POSIX
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace NWindows {
|
||||
namespace NFile {
|
||||
|
||||
namespace NDir {
|
||||
bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime);
|
||||
}
|
||||
|
||||
namespace NIO {
|
||||
|
||||
bool CFileBase::OpenBinary(const char *name, int flags, mode_t mode)
|
||||
{
|
||||
#ifdef O_BINARY
|
||||
flags |= O_BINARY;
|
||||
#endif
|
||||
|
||||
Close();
|
||||
_handle = ::open(name, flags, mode);
|
||||
return _handle != -1;
|
||||
|
||||
/*
|
||||
if (_handle == -1)
|
||||
return false;
|
||||
if (IsString1PrefixedByString2(name, "/dev/"))
|
||||
{
|
||||
// /dev/sda
|
||||
// IsDeviceFile = true; // for debug
|
||||
// SizeDefined = false;
|
||||
// SizeDefined = (GetDeviceSize_InBytes(Size) == 0);
|
||||
}
|
||||
return true;
|
||||
*/
|
||||
}
|
||||
|
||||
bool CFileBase::Close()
|
||||
{
|
||||
if (_handle == -1)
|
||||
return true;
|
||||
if (close(_handle) != 0)
|
||||
return false;
|
||||
_handle = -1;
|
||||
/*
|
||||
IsDeviceFile = false;
|
||||
SizeDefined = false;
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CFileBase::GetLength(UInt64 &length) const
|
||||
{
|
||||
length = 0;
|
||||
// length = (UInt64)(Int64)-1; // for debug
|
||||
const off_t curPos = seekToCur();
|
||||
if (curPos == -1)
|
||||
return false;
|
||||
const off_t lengthTemp = seek(0, SEEK_END);
|
||||
seek(curPos, SEEK_SET);
|
||||
length = (UInt64)lengthTemp;
|
||||
|
||||
/*
|
||||
// 22.00:
|
||||
if (lengthTemp == 1)
|
||||
if (IsDeviceFile && SizeDefined)
|
||||
{
|
||||
length = Size;
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
return (lengthTemp != -1);
|
||||
}
|
||||
|
||||
off_t CFileBase::seek(off_t distanceToMove, int moveMethod) const
|
||||
{
|
||||
/*
|
||||
if (IsDeviceFile && SizeDefined && moveMethod == SEEK_END)
|
||||
{
|
||||
printf("\n seek : IsDeviceFile moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove);
|
||||
distanceToMove += Size;
|
||||
moveMethod = SEEK_SET;
|
||||
}
|
||||
*/
|
||||
|
||||
// printf("\nCFileBase::seek() moveMethod = %d, distanceToMove = %lld", moveMethod, (long long)distanceToMove);
|
||||
// off_t res = ::lseek(_handle, distanceToMove, moveMethod);
|
||||
// printf("\n lseek : moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove);
|
||||
return ::lseek(_handle, distanceToMove, moveMethod);
|
||||
// return res;
|
||||
}
|
||||
|
||||
off_t CFileBase::seekToBegin() const throw()
|
||||
{
|
||||
return seek(0, SEEK_SET);
|
||||
}
|
||||
|
||||
off_t CFileBase::seekToCur() const throw()
|
||||
{
|
||||
return seek(0, SEEK_CUR);
|
||||
}
|
||||
|
||||
/*
|
||||
bool CFileBase::SeekToBegin() const throw()
|
||||
{
|
||||
return (::seek(0, SEEK_SET) != -1);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/////////////////////////
|
||||
// CInFile
|
||||
|
||||
bool CInFile::Open(const char *name)
|
||||
{
|
||||
return CFileBase::OpenBinary(name, O_RDONLY);
|
||||
}
|
||||
|
||||
bool CInFile::OpenShared(const char *name, bool)
|
||||
{
|
||||
return Open(name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
int CFileBase::my_ioctl_BLKGETSIZE64(unsigned long long *numBlocks)
|
||||
{
|
||||
// we can read "/sys/block/sda/size" "/sys/block/sda/sda1/size" - partition
|
||||
// #include <linux/fs.h>
|
||||
return ioctl(_handle, BLKGETSIZE64, numBlocks);
|
||||
// in block size
|
||||
}
|
||||
|
||||
int CFileBase::GetDeviceSize_InBytes(UInt64 &size)
|
||||
{
|
||||
size = 0;
|
||||
unsigned long long numBlocks;
|
||||
int res = my_ioctl_BLKGETSIZE64(&numBlocks);
|
||||
if (res == 0)
|
||||
size = numBlocks; // another blockSize s possible?
|
||||
printf("\nGetDeviceSize_InBytes res = %d, size = %lld\n", res, (long long)size);
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
On Linux (32-bit and 64-bit):
|
||||
read(), write() (and similar system calls) will transfer at most
|
||||
0x7ffff000 = (2GiB - 4 KiB) bytes, returning the number of bytes actually transferred.
|
||||
*/
|
||||
|
||||
static const size_t kChunkSizeMax = ((size_t)1 << 22);
|
||||
|
||||
ssize_t CInFile::read_part(void *data, size_t size) throw()
|
||||
{
|
||||
if (size > kChunkSizeMax)
|
||||
size = kChunkSizeMax;
|
||||
return ::read(_handle, data, size);
|
||||
}
|
||||
|
||||
bool CInFile::ReadFull(void *data, size_t size, size_t &processed) throw()
|
||||
{
|
||||
processed = 0;
|
||||
do
|
||||
{
|
||||
const ssize_t res = read_part(data, size);
|
||||
if (res < 0)
|
||||
return false;
|
||||
if (res == 0)
|
||||
break;
|
||||
data = (void *)((Byte *)data + (size_t)res);
|
||||
processed += (size_t)res;
|
||||
size -= (size_t)res;
|
||||
}
|
||||
while (size);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////
|
||||
// COutFile
|
||||
|
||||
bool COutFile::OpenBinary_forWrite_oflag(const char *name, int oflag)
|
||||
{
|
||||
Path = name; // change it : set it only if open is success.
|
||||
return OpenBinary(name, oflag, mode_for_Create);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
windows exist non-exist posix
|
||||
CREATE_NEW Fail Create O_CREAT | O_EXCL
|
||||
CREATE_ALWAYS Trunc Create O_CREAT | O_TRUNC
|
||||
OPEN_ALWAYS Open Create O_CREAT
|
||||
OPEN_EXISTING Open Fail 0
|
||||
TRUNCATE_EXISTING Trunc Fail O_TRUNC ???
|
||||
|
||||
// O_CREAT = If the file exists, this flag has no effect except as noted under O_EXCL below.
|
||||
// If O_CREAT and O_EXCL are set, open() shall fail if the file exists.
|
||||
// O_TRUNC : If the file exists and the file is successfully opened, its length shall be truncated to 0.
|
||||
*/
|
||||
bool COutFile::Open_EXISTING(const char *name)
|
||||
{ return OpenBinary_forWrite_oflag(name, O_WRONLY); }
|
||||
bool COutFile::Create_ALWAYS(const char *name)
|
||||
{ return OpenBinary_forWrite_oflag(name, O_WRONLY | O_CREAT | O_TRUNC); }
|
||||
bool COutFile::Create_NEW(const char *name)
|
||||
{ return OpenBinary_forWrite_oflag(name, O_WRONLY | O_CREAT | O_EXCL); }
|
||||
bool COutFile::Create_ALWAYS_or_Open_ALWAYS(const char *name, bool createAlways)
|
||||
{
|
||||
return OpenBinary_forWrite_oflag(name,
|
||||
createAlways ?
|
||||
O_WRONLY | O_CREAT | O_TRUNC :
|
||||
O_WRONLY | O_CREAT);
|
||||
}
|
||||
/*
|
||||
bool COutFile::Create_ALWAYS_or_NEW(const char *name, bool createAlways)
|
||||
{
|
||||
return OpenBinary_forWrite_oflag(name,
|
||||
createAlways ?
|
||||
O_WRONLY | O_CREAT | O_TRUNC :
|
||||
O_WRONLY | O_CREAT | O_EXCL);
|
||||
}
|
||||
bool COutFile::Open_Disposition(const char *name, DWORD creationDisposition)
|
||||
{
|
||||
int flag;
|
||||
switch (creationDisposition)
|
||||
{
|
||||
case CREATE_NEW: flag = O_WRONLY | O_CREAT | O_EXCL; break;
|
||||
case CREATE_ALWAYS: flag = O_WRONLY | O_CREAT | O_TRUNC; break;
|
||||
case OPEN_ALWAYS: flag = O_WRONLY | O_CREAT; break;
|
||||
case OPEN_EXISTING: flag = O_WRONLY; break;
|
||||
case TRUNCATE_EXISTING: flag = O_WRONLY | O_TRUNC; break;
|
||||
default:
|
||||
SetLastError(EINVAL);
|
||||
return false;
|
||||
}
|
||||
return OpenBinary_forWrite_oflag(name, flag);
|
||||
}
|
||||
*/
|
||||
|
||||
ssize_t COutFile::write_part(const void *data, size_t size) throw()
|
||||
{
|
||||
if (size > kChunkSizeMax)
|
||||
size = kChunkSizeMax;
|
||||
return ::write(_handle, data, size);
|
||||
}
|
||||
|
||||
ssize_t COutFile::write_full(const void *data, size_t size, size_t &processed) throw()
|
||||
{
|
||||
processed = 0;
|
||||
do
|
||||
{
|
||||
const ssize_t res = write_part(data, size);
|
||||
if (res < 0)
|
||||
return res;
|
||||
if (res == 0)
|
||||
break;
|
||||
data = (const void *)((const Byte *)data + (size_t)res);
|
||||
processed += (size_t)res;
|
||||
size -= (size_t)res;
|
||||
}
|
||||
while (size);
|
||||
return (ssize_t)processed;
|
||||
}
|
||||
|
||||
bool COutFile::SetLength(UInt64 length) throw()
|
||||
{
|
||||
const off_t len2 = (off_t)length;
|
||||
if ((Int64)length != len2)
|
||||
{
|
||||
SetLastError(EFBIG);
|
||||
return false;
|
||||
}
|
||||
// The value of the seek pointer shall not be modified by a call to ftruncate().
|
||||
const int iret = ftruncate(_handle, len2);
|
||||
return (iret == 0);
|
||||
}
|
||||
|
||||
bool COutFile::Close()
|
||||
{
|
||||
const bool res = CFileBase::Close();
|
||||
if (!res)
|
||||
return res;
|
||||
if (CTime_defined || ATime_defined || MTime_defined)
|
||||
{
|
||||
/* bool res2 = */ NWindows::NFile::NDir::SetDirTime(Path,
|
||||
CTime_defined ? &CTime : NULL,
|
||||
ATime_defined ? &ATime : NULL,
|
||||
MTime_defined ? &MTime : NULL);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool COutFile::SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw()
|
||||
{
|
||||
// On some OS (cygwin, MacOSX ...), you must close the file before updating times
|
||||
// return true;
|
||||
|
||||
if (cTime) { CTime = *cTime; CTime_defined = true; } else CTime_defined = false;
|
||||
if (aTime) { ATime = *aTime; ATime_defined = true; } else ATime_defined = false;
|
||||
if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false;
|
||||
return true;
|
||||
|
||||
/*
|
||||
struct timespec times[2];
|
||||
UNUSED_VAR(cTime)
|
||||
if (!aTime && !mTime)
|
||||
return true;
|
||||
bool needChange;
|
||||
needChange = FiTime_To_timespec(aTime, times[0]);
|
||||
needChange |= FiTime_To_timespec(mTime, times[1]);
|
||||
if (!needChange)
|
||||
return true;
|
||||
return futimens(_handle, times) == 0;
|
||||
*/
|
||||
}
|
||||
|
||||
bool COutFile::SetMTime(const CFiTime *mTime) throw()
|
||||
{
|
||||
if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,467 @@
|
||||
// Windows/FileIO.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_FILE_IO_H
|
||||
#define ZIP7_INC_WINDOWS_FILE_IO_H
|
||||
|
||||
#include "../Common/MyWindows.h"
|
||||
|
||||
#define Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L)
|
||||
#define Z7_WIN_IO_REPARSE_TAG_SYMLINK (0xA000000CL)
|
||||
#define Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK (0xA000001DL)
|
||||
|
||||
#define Z7_WIN_SYMLINK_FLAG_RELATIVE 1
|
||||
|
||||
#define Z7_WIN_LX_SYMLINK_VERSION_2 2
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
#include <winioctl.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include "../Common/MyString.h"
|
||||
#include "../Common/MyBuffer.h"
|
||||
|
||||
#include "../Windows/TimeUtils.h"
|
||||
|
||||
#include "Defs.h"
|
||||
|
||||
HRESULT GetLastError_noZero_HRESULT();
|
||||
|
||||
#define my_FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // REPARSE_DATA_BUFFER
|
||||
#define my_FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) // REPARSE_DATA_BUFFER
|
||||
#define my_FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // REPARSE_DATA_BUFFER
|
||||
|
||||
namespace NWindows {
|
||||
namespace NFile {
|
||||
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
/*
|
||||
in: (CByteBuffer &dest) is empty
|
||||
in: (path) uses Windows path separator (\).
|
||||
out: (path) uses Linux path separator (/).
|
||||
if (isAbsPath == true), then "c:\\" prefix is replaced to "/mnt/c/" prefix
|
||||
*/
|
||||
void Convert_WinPath_to_WslLinuxPath(FString &path, bool convertDrivePath);
|
||||
// (path) must use Linux path separator (/).
|
||||
void FillLinkData_WslLink(CByteBuffer &dest, const wchar_t *path);
|
||||
|
||||
/*
|
||||
in: (CByteBuffer &dest) is empty
|
||||
if (isSymLink == false) : MOUNT_POINT : (path) must be absolute.
|
||||
if (isSymLink == true) : SYMLINK : Windows
|
||||
(path) must use Windows path separator (\).
|
||||
(path) must be without link "\\??\\" prefix.
|
||||
link "\\??\\" prefix will be added inside FillLinkData(), if path is absolute.
|
||||
*/
|
||||
void FillLinkData_WinLink(CByteBuffer &dest, const wchar_t *path, bool isSymLink);
|
||||
// in: (CByteBuffer &dest) is empty
|
||||
inline void FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL)
|
||||
{
|
||||
if (isWSL)
|
||||
FillLinkData_WslLink(dest, path);
|
||||
else
|
||||
FillLinkData_WinLink(dest, path, isSymLink);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct CReparseShortInfo
|
||||
{
|
||||
unsigned Offset;
|
||||
unsigned Size;
|
||||
|
||||
bool Parse(const Byte *p, size_t size);
|
||||
};
|
||||
|
||||
struct CReparseAttr
|
||||
{
|
||||
UInt32 Tag;
|
||||
UInt32 Flags;
|
||||
UString SubsName;
|
||||
UString PrintName;
|
||||
AString WslName;
|
||||
|
||||
bool HeaderError;
|
||||
bool TagIsUnknown;
|
||||
bool MinorError;
|
||||
DWORD ErrorCode;
|
||||
|
||||
CReparseAttr(): Tag(0), Flags(0) {}
|
||||
|
||||
// returns (true) and (ErrorCode = 0), if (it's correct known link)
|
||||
// returns (false) and (ErrorCode = ERROR_REPARSE_TAG_INVALID), if unknown tag
|
||||
bool Parse(const Byte *p, size_t size);
|
||||
|
||||
bool IsMountPoint() const { return Tag == Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT; } // it's Junction
|
||||
bool IsSymLink_Win() const { return Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK; }
|
||||
bool IsSymLink_WSL() const { return Tag == Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK; }
|
||||
|
||||
// note: "/dir1/path" is marked as relative.
|
||||
bool IsRelative_Win() const { return Flags == Z7_WIN_SYMLINK_FLAG_RELATIVE; }
|
||||
|
||||
bool IsRelative_WSL() const
|
||||
{
|
||||
return WslName[0] != '/'; // WSL uses unix path separator
|
||||
}
|
||||
|
||||
bool IsOkNamePair() const;
|
||||
UString GetPath() const;
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
#define CFiInfo BY_HANDLE_FILE_INFORMATION
|
||||
#define ST_MTIME(st) (st).ftLastWriteTime
|
||||
#else
|
||||
#define CFiInfo stat
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
namespace NIO {
|
||||
|
||||
bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMATION *fileInfo = NULL);
|
||||
bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size);
|
||||
bool DeleteReparseData(CFSTR path);
|
||||
|
||||
class CFileBase MY_UNCOPYABLE
|
||||
{
|
||||
protected:
|
||||
HANDLE _handle;
|
||||
|
||||
bool Create(CFSTR path, DWORD desiredAccess,
|
||||
DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
|
||||
|
||||
public:
|
||||
|
||||
bool DeviceIoControl(DWORD controlCode, LPVOID inBuffer, DWORD inSize,
|
||||
LPVOID outBuffer, DWORD outSize, LPDWORD bytesReturned, LPOVERLAPPED overlapped = NULL) const
|
||||
{
|
||||
return BOOLToBool(::DeviceIoControl(_handle, controlCode, inBuffer, inSize,
|
||||
outBuffer, outSize, bytesReturned, overlapped));
|
||||
}
|
||||
|
||||
bool DeviceIoControlOut(DWORD controlCode, LPVOID outBuffer, DWORD outSize, LPDWORD bytesReturned) const
|
||||
{
|
||||
return DeviceIoControl(controlCode, NULL, 0, outBuffer, outSize, bytesReturned);
|
||||
}
|
||||
|
||||
bool DeviceIoControlOut(DWORD controlCode, LPVOID outBuffer, DWORD outSize) const
|
||||
{
|
||||
DWORD bytesReturned;
|
||||
return DeviceIoControlOut(controlCode, outBuffer, outSize, &bytesReturned);
|
||||
}
|
||||
|
||||
public:
|
||||
bool PreserveATime;
|
||||
#if 0
|
||||
bool IsStdStream;
|
||||
bool IsStdPipeStream;
|
||||
#endif
|
||||
#ifdef Z7_DEVICE_FILE
|
||||
bool IsDeviceFile;
|
||||
bool SizeDefined;
|
||||
UInt64 Size; // it can be larger than real available size
|
||||
#endif
|
||||
|
||||
CFileBase():
|
||||
_handle(INVALID_HANDLE_VALUE),
|
||||
PreserveATime(false)
|
||||
#if 0
|
||||
, IsStdStream(false),
|
||||
, IsStdPipeStream(false)
|
||||
#endif
|
||||
{}
|
||||
~CFileBase() { Close(); }
|
||||
|
||||
HANDLE GetHandle() const { return _handle; }
|
||||
|
||||
// void Detach() { _handle = INVALID_HANDLE_VALUE; }
|
||||
|
||||
bool Close() throw();
|
||||
|
||||
bool GetPosition(UInt64 &position) const throw();
|
||||
bool GetLength(UInt64 &length) const throw();
|
||||
|
||||
bool Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw();
|
||||
bool Seek(UInt64 position, UInt64 &newPosition) const throw();
|
||||
bool SeekToBegin() const throw();
|
||||
bool SeekToEnd(UInt64 &newPosition) const throw();
|
||||
|
||||
bool GetFileInformation(BY_HANDLE_FILE_INFORMATION *info) const
|
||||
{ return BOOLToBool(GetFileInformationByHandle(_handle, info)); }
|
||||
|
||||
static bool GetFileInformation(CFSTR path, BY_HANDLE_FILE_INFORMATION *info)
|
||||
{
|
||||
// probably it can work for complex paths: unsupported by another things
|
||||
NIO::CFileBase file;
|
||||
if (!file.Create(path, 0, FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS))
|
||||
return false;
|
||||
return file.GetFileInformation(info);
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef UNDER_CE
|
||||
#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM
|
||||
#define IOCTL_CDROM_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
// #define IOCTL_CDROM_MEDIA_REMOVAL CTL_CODE(IOCTL_CDROM_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
|
||||
// IOCTL_DISK_GET_DRIVE_GEOMETRY_EX works since WinXP
|
||||
#define my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
struct my_DISK_GEOMETRY_EX
|
||||
{
|
||||
DISK_GEOMETRY Geometry;
|
||||
LARGE_INTEGER DiskSize;
|
||||
BYTE Data[1];
|
||||
};
|
||||
#endif
|
||||
|
||||
class CInFile: public CFileBase
|
||||
{
|
||||
#ifdef Z7_DEVICE_FILE
|
||||
|
||||
#ifndef UNDER_CE
|
||||
|
||||
bool GetGeometry(DISK_GEOMETRY *res) const
|
||||
{ return DeviceIoControlOut(IOCTL_DISK_GET_DRIVE_GEOMETRY, res, sizeof(*res)); }
|
||||
|
||||
bool GetGeometryEx(my_DISK_GEOMETRY_EX *res) const
|
||||
{ return DeviceIoControlOut(my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, res, sizeof(*res)); }
|
||||
|
||||
bool GetCdRomGeometry(DISK_GEOMETRY *res) const
|
||||
{ return DeviceIoControlOut(IOCTL_CDROM_GET_DRIVE_GEOMETRY, res, sizeof(*res)); }
|
||||
|
||||
bool GetPartitionInfo(PARTITION_INFORMATION *res)
|
||||
{ return DeviceIoControlOut(IOCTL_DISK_GET_PARTITION_INFO, LPVOID(res), sizeof(*res)); }
|
||||
|
||||
#endif
|
||||
|
||||
void CorrectDeviceSize();
|
||||
void CalcDeviceSize(CFSTR name);
|
||||
|
||||
#endif
|
||||
|
||||
public:
|
||||
bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
|
||||
bool OpenShared(CFSTR fileName, bool shareForWrite);
|
||||
bool Open(CFSTR fileName);
|
||||
|
||||
#if 0
|
||||
bool AttachStdIn()
|
||||
{
|
||||
IsDeviceFile = false;
|
||||
const HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
|
||||
if (h == INVALID_HANDLE_VALUE || !h)
|
||||
return false;
|
||||
IsStdStream = true;
|
||||
IsStdPipeStream = true;
|
||||
_handle = h;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef UNDER_CE
|
||||
|
||||
bool Open_for_ReadAttributes(CFSTR fileName)
|
||||
{
|
||||
return Create(fileName, FILE_READ_ATTRIBUTES,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS);
|
||||
// we must use (FILE_FLAG_BACKUP_SEMANTICS) to open handle of directory.
|
||||
}
|
||||
|
||||
bool Open_for_FileRenameInformation(CFSTR fileName)
|
||||
{
|
||||
return Create(fileName, DELETE | SYNCHRONIZE | GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL);
|
||||
// we must use (FILE_FLAG_BACKUP_SEMANTICS) to open handle of directory.
|
||||
}
|
||||
|
||||
bool OpenReparse(CFSTR fileName)
|
||||
{
|
||||
// 17.02 fix: to support Windows XP compatibility junctions:
|
||||
// we use Create() with (desiredAccess = 0) instead of Open() with GENERIC_READ
|
||||
return
|
||||
Create(fileName, 0,
|
||||
// Open(fileName,
|
||||
FILE_SHARE_READ, OPEN_EXISTING,
|
||||
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool Read1(void *data, UInt32 size, UInt32 &processedSize) throw();
|
||||
bool ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw();
|
||||
bool Read(void *data, UInt32 size, UInt32 &processedSize) throw();
|
||||
bool ReadFull(void *data, size_t size, size_t &processedSize) throw();
|
||||
};
|
||||
|
||||
class COutFile: public CFileBase
|
||||
{
|
||||
bool Open_Disposition(CFSTR fileName, DWORD creationDisposition);
|
||||
public:
|
||||
bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
|
||||
bool Open_EXISTING(CFSTR fileName)
|
||||
{ return Open_Disposition(fileName, OPEN_EXISTING); }
|
||||
bool Create_ALWAYS_or_Open_ALWAYS(CFSTR fileName, bool createAlways)
|
||||
{ return Open_Disposition(fileName, createAlways ? CREATE_ALWAYS : OPEN_ALWAYS); }
|
||||
bool Create_ALWAYS_or_NEW(CFSTR fileName, bool createAlways)
|
||||
{ return Open_Disposition(fileName, createAlways ? CREATE_ALWAYS : CREATE_NEW); }
|
||||
bool Create_ALWAYS(CFSTR fileName)
|
||||
{ return Open_Disposition(fileName, CREATE_ALWAYS); }
|
||||
bool Create_NEW(CFSTR fileName)
|
||||
{ return Open_Disposition(fileName, CREATE_NEW); }
|
||||
|
||||
bool Create_ALWAYS_with_Attribs(CFSTR fileName, DWORD flagsAndAttributes);
|
||||
|
||||
bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw();
|
||||
bool SetMTime(const CFiTime *mTime) throw();
|
||||
bool WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw();
|
||||
bool Write(const void *data, UInt32 size, UInt32 &processedSize) throw();
|
||||
bool WriteFull(const void *data, size_t size) throw();
|
||||
bool SetEndOfFile() throw();
|
||||
bool SetLength(UInt64 length) throw();
|
||||
bool SetLength_KeepPosition(UInt64 length) throw();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#else // _WIN32
|
||||
|
||||
namespace NIO {
|
||||
|
||||
bool GetReparseData(CFSTR path, CByteBuffer &reparseData);
|
||||
// bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size);
|
||||
|
||||
// parameters are in reverse order of symlink() function !!!
|
||||
bool SetSymLink(CFSTR from, CFSTR to);
|
||||
bool SetSymLink_UString(CFSTR from, const UString &to);
|
||||
|
||||
|
||||
class CFileBase
|
||||
{
|
||||
protected:
|
||||
int _handle;
|
||||
|
||||
/*
|
||||
bool IsDeviceFile;
|
||||
bool SizeDefined;
|
||||
UInt64 Size; // it can be larger than real available size
|
||||
*/
|
||||
|
||||
bool OpenBinary(const char *name, int flags, mode_t mode = 0666);
|
||||
public:
|
||||
bool PreserveATime;
|
||||
#if 0
|
||||
bool IsStdStream;
|
||||
#endif
|
||||
|
||||
CFileBase(): _handle(-1), PreserveATime(false)
|
||||
#if 0
|
||||
, IsStdStream(false)
|
||||
#endif
|
||||
{}
|
||||
~CFileBase() { Close(); }
|
||||
// void Detach() { _handle = -1; }
|
||||
bool Close();
|
||||
bool GetLength(UInt64 &length) const;
|
||||
off_t seek(off_t distanceToMove, int moveMethod) const;
|
||||
off_t seekToBegin() const throw();
|
||||
off_t seekToCur() const throw();
|
||||
// bool SeekToBegin() throw();
|
||||
int my_fstat(struct stat *st) const { return fstat(_handle, st); }
|
||||
/*
|
||||
int my_ioctl_BLKGETSIZE64(unsigned long long *val);
|
||||
int GetDeviceSize_InBytes(UInt64 &size);
|
||||
void CalcDeviceSize(CFSTR s);
|
||||
*/
|
||||
};
|
||||
|
||||
class CInFile: public CFileBase
|
||||
{
|
||||
public:
|
||||
bool Open(const char *name);
|
||||
bool OpenShared(const char *name, bool shareForWrite);
|
||||
#if 0
|
||||
bool AttachStdIn()
|
||||
{
|
||||
_handle = GetStdHandle(STD_INPUT_HANDLE);
|
||||
if (_handle == INVALID_HANDLE_VALUE || !_handle)
|
||||
return false;
|
||||
IsStdStream = true;
|
||||
}
|
||||
#endif
|
||||
ssize_t read_part(void *data, size_t size) throw();
|
||||
// ssize_t read_full(void *data, size_t size, size_t &processed);
|
||||
bool ReadFull(void *data, size_t size, size_t &processedSize) throw();
|
||||
};
|
||||
|
||||
class COutFile: public CFileBase
|
||||
{
|
||||
bool CTime_defined;
|
||||
bool ATime_defined;
|
||||
bool MTime_defined;
|
||||
CFiTime CTime;
|
||||
CFiTime ATime;
|
||||
CFiTime MTime;
|
||||
|
||||
AString Path;
|
||||
ssize_t write_part(const void *data, size_t size) throw();
|
||||
bool OpenBinary_forWrite_oflag(const char *name, int oflag);
|
||||
public:
|
||||
mode_t mode_for_Create;
|
||||
|
||||
COutFile():
|
||||
CTime_defined(false),
|
||||
ATime_defined(false),
|
||||
MTime_defined(false),
|
||||
mode_for_Create(0666)
|
||||
{}
|
||||
|
||||
bool Close();
|
||||
|
||||
bool Open_EXISTING(CFSTR fileName);
|
||||
bool Create_ALWAYS_or_Open_ALWAYS(CFSTR fileName, bool createAlways);
|
||||
bool Create_ALWAYS(CFSTR fileName);
|
||||
bool Create_NEW(CFSTR fileName);
|
||||
// bool Create_ALWAYS_or_NEW(CFSTR fileName, bool createAlways);
|
||||
// bool Open_Disposition(const char *name, DWORD creationDisposition);
|
||||
|
||||
ssize_t write_full(const void *data, size_t size, size_t &processed) throw();
|
||||
|
||||
bool WriteFull(const void *data, size_t size) throw()
|
||||
{
|
||||
size_t processed;
|
||||
ssize_t res = write_full(data, size, processed);
|
||||
if (res == -1)
|
||||
return false;
|
||||
return processed == size;
|
||||
}
|
||||
|
||||
bool SetLength(UInt64 length) throw();
|
||||
bool SetLength_KeepPosition(UInt64 length) throw()
|
||||
{
|
||||
return SetLength(length);
|
||||
}
|
||||
bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw();
|
||||
bool SetMTime(const CFiTime *mTime) throw();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
}}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,697 @@
|
||||
// Windows/FileLink.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../C/CpuArch.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef Z7_DEVICE_FILE
|
||||
#include "../../C/Alloc.h"
|
||||
#endif
|
||||
|
||||
#include "../Common/UTFConvert.h"
|
||||
#include "../Common/StringConvert.h"
|
||||
|
||||
#include "FileDir.h"
|
||||
#include "FileFind.h"
|
||||
#include "FileIO.h"
|
||||
#include "FileName.h"
|
||||
|
||||
#ifdef Z7_OLD_WIN_SDK
|
||||
#ifndef ERROR_INVALID_REPARSE_DATA
|
||||
#define ERROR_INVALID_REPARSE_DATA 4392L
|
||||
#endif
|
||||
#ifndef ERROR_REPARSE_TAG_INVALID
|
||||
#define ERROR_REPARSE_TAG_INVALID 4393L
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef _UNICODE
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
|
||||
namespace NWindows {
|
||||
namespace NFile {
|
||||
|
||||
using namespace NName;
|
||||
|
||||
/*
|
||||
Win10 Junctions/SymLinks:
|
||||
- (/) slash doesn't work as path separator
|
||||
- Win10 preinstalled junctions don't use tail backslash, but tail backslashes also work.
|
||||
- double backslash works only after drive prefix "c:\\dir1\dir2\",
|
||||
and doesn't work in another places.
|
||||
- absolute path without \??\ prefix doesn't work
|
||||
- absolute path "c:" doesn't work
|
||||
*/
|
||||
|
||||
/*
|
||||
Reparse Points (Junctions and Symbolic Links):
|
||||
struct
|
||||
{
|
||||
UInt32 Tag;
|
||||
UInt16 Size; // not including starting 8 bytes
|
||||
UInt16 Reserved; // = 0, DOCs: // Length, in bytes, of the unparsed portion of
|
||||
// the file name pointed to by the FileName member of the associated file object.
|
||||
// This member is only valid for create operations when the I/O fails with STATUS_REPARSE.
|
||||
|
||||
UInt16 SubstituteOffset; // offset in bytes from start of namesChars
|
||||
UInt16 SubstituteLen; // size in bytes, it doesn't include tailed NUL
|
||||
UInt16 PrintOffset; // offset in bytes from start of namesChars
|
||||
UInt16 PrintLen; // size in bytes, it doesn't include tailed NUL
|
||||
|
||||
[UInt32] Flags; // for Symbolic Links only.
|
||||
|
||||
UInt16 namesChars[]
|
||||
}
|
||||
|
||||
MOUNT_POINT (Junction point):
|
||||
1) there is NUL wchar after path
|
||||
2) Default Order in table:
|
||||
Substitute Path
|
||||
Print Path
|
||||
3) pathnames can not contain dot directory names
|
||||
|
||||
SYMLINK:
|
||||
1) there is no NUL wchar after path
|
||||
2) Default Order in table:
|
||||
Print Path
|
||||
Substitute Path
|
||||
|
||||
DOCS:
|
||||
The print name SHOULD be an informative pathname, suitable for display
|
||||
to a user, that also identifies the target of the mount point.
|
||||
Neither of these pathnames can contain dot directory names.
|
||||
|
||||
reparse tags, with the exception of IO_REPARSE_TAG_SYMLINK,
|
||||
are processed on the server and are not processed by a client
|
||||
after transmission over the wire.
|
||||
Clients SHOULD treat associated reparse data as opaque data.
|
||||
*/
|
||||
|
||||
/*
|
||||
Win10 WSL2:
|
||||
admin rights + sudo: it creates normal windows symbolic link.
|
||||
in another cases : it creates IO_REPARSE_TAG_LX_SYMLINK repare point.
|
||||
*/
|
||||
|
||||
/*
|
||||
static const UInt32 kReparseFlags_Alias = (1 << 29);
|
||||
static const UInt32 kReparseFlags_HighLatency = (1 << 30);
|
||||
static const UInt32 kReparseFlags_Microsoft = ((UInt32)1 << 31);
|
||||
|
||||
#define Z7_WIN_IO_REPARSE_TAG_HSM (0xC0000004L)
|
||||
#define Z7_WIN_IO_REPARSE_TAG_HSM2 (0x80000006L)
|
||||
#define Z7_WIN_IO_REPARSE_TAG_SIS (0x80000007L)
|
||||
#define Z7_WIN_IO_REPARSE_TAG_WIM (0x80000008L)
|
||||
#define Z7_WIN_IO_REPARSE_TAG_CSV (0x80000009L)
|
||||
#define Z7_WIN_IO_REPARSE_TAG_DFS (0x8000000AL)
|
||||
#define Z7_WIN_IO_REPARSE_TAG_DFSR (0x80000012L)
|
||||
*/
|
||||
|
||||
#define Get16(p) GetUi16(p)
|
||||
#define Get32(p) GetUi32(p)
|
||||
|
||||
static const char * const k_LinkPrefix = "\\??\\";
|
||||
static const char * const k_LinkPrefix_UNC = "\\??\\UNC\\";
|
||||
static const unsigned k_LinkPrefix_Size = 4;
|
||||
|
||||
static bool IsLinkPrefix(const wchar_t *s)
|
||||
{
|
||||
return IsString1PrefixedByString2(s, k_LinkPrefix);
|
||||
}
|
||||
|
||||
/*
|
||||
static const char * const k_VolumePrefix = "Volume{";
|
||||
static const bool IsVolumeName(const wchar_t *s)
|
||||
{
|
||||
return IsString1PrefixedByString2(s, k_VolumePrefix);
|
||||
}
|
||||
*/
|
||||
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
|
||||
#define Set16(p, v) SetUi16(p, v)
|
||||
#define Set32(p, v) SetUi32(p, v)
|
||||
|
||||
static void WriteString(Byte *dest, const wchar_t *path)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
const wchar_t c = *path++;
|
||||
if (c == 0)
|
||||
return;
|
||||
Set16(dest, (UInt16)c)
|
||||
dest += 2;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
void Convert_WinPath_to_WslLinuxPath(FString &s, bool convertDrivePath)
|
||||
{
|
||||
if (convertDrivePath && IsDrivePath(s))
|
||||
{
|
||||
FChar c = s[0];
|
||||
c = MyCharLower_Ascii(c);
|
||||
s.DeleteFrontal(2);
|
||||
s.InsertAtFront(c);
|
||||
s.Insert(0, FTEXT("/mnt/"));
|
||||
}
|
||||
s.Replace(FCHAR_PATH_SEPARATOR, FTEXT('/'));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static const unsigned k_Link_Size_Limit = 1u << 16; // 16-bit field is used for size.
|
||||
|
||||
void FillLinkData_WslLink(CByteBuffer &dest, const wchar_t *path)
|
||||
{
|
||||
// dest.Free(); // it's empty already
|
||||
// WSL probably uses Replacement Character UTF-16 0xFFFD for unsupported characters?
|
||||
AString utf;
|
||||
ConvertUnicodeToUTF8(path, utf);
|
||||
const unsigned size = 4 + utf.Len();
|
||||
if (size >= k_Link_Size_Limit)
|
||||
return;
|
||||
dest.Alloc(8 + size);
|
||||
Byte *p = dest;
|
||||
Set32(p, Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK)
|
||||
// Set32(p + 4, (UInt32)size)
|
||||
Set16(p + 4, (UInt16)size)
|
||||
Set16(p + 6, 0)
|
||||
Set32(p + 8, Z7_WIN_LX_SYMLINK_VERSION_2)
|
||||
memcpy(p + 12, utf.Ptr(), utf.Len());
|
||||
}
|
||||
|
||||
|
||||
void FillLinkData_WinLink(CByteBuffer &dest, const wchar_t *path, bool isSymLink)
|
||||
{
|
||||
// dest.Free(); // it's empty already
|
||||
bool isAbs = false;
|
||||
if (IS_PATH_SEPAR(path[0]))
|
||||
{
|
||||
// root paths "\dir1\path" are marked as relative
|
||||
if (IS_PATH_SEPAR(path[1]))
|
||||
isAbs = true;
|
||||
}
|
||||
else
|
||||
isAbs = IsAbsolutePath(path);
|
||||
if (!isAbs && !isSymLink)
|
||||
{
|
||||
// Win10 allows us to create relative MOUNT_POINT.
|
||||
// But relative MOUNT_POINT will not work when accessing it.
|
||||
// So we prevent useless creation of a relative MOUNT_POINT.
|
||||
return;
|
||||
}
|
||||
|
||||
bool needPrintName = true;
|
||||
UString subs (path);
|
||||
if (isAbs)
|
||||
{
|
||||
const bool isSuperPath = IsSuperPath(path);
|
||||
if (!isSuperPath && NName::IsNetworkPath(us2fs(path)))
|
||||
{
|
||||
subs = k_LinkPrefix_UNC;
|
||||
subs += (path + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isSuperPath)
|
||||
{
|
||||
// we remove super prefix:
|
||||
path += kSuperPathPrefixSize;
|
||||
// we want to get correct abolute path in PrintName still.
|
||||
if (!IsDrivePath(path))
|
||||
needPrintName = false; // we need "\\server\path" for print name.
|
||||
}
|
||||
subs = k_LinkPrefix;
|
||||
subs += path;
|
||||
}
|
||||
}
|
||||
const size_t len1 = subs.Len() * 2;
|
||||
size_t len2 = (size_t)MyStringLen(path) * 2;
|
||||
if (!needPrintName)
|
||||
len2 = 0;
|
||||
size_t totalNamesSize = len1 + len2;
|
||||
/* some WIM imagex software uses old scheme for symbolic links.
|
||||
so we can use old scheme for byte to byte compatibility */
|
||||
const bool newOrderScheme = isSymLink;
|
||||
// newOrderScheme = false;
|
||||
if (!newOrderScheme)
|
||||
totalNamesSize += 2 * 2; // we use NULL terminators in old scheme.
|
||||
|
||||
const size_t size = 8 + 8 + (isSymLink ? 4 : 0) + totalNamesSize;
|
||||
if (size >= k_Link_Size_Limit)
|
||||
return;
|
||||
dest.Alloc(size);
|
||||
memset(dest, 0, size);
|
||||
const UInt32 tag = isSymLink ?
|
||||
Z7_WIN_IO_REPARSE_TAG_SYMLINK :
|
||||
Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT;
|
||||
Byte *p = dest;
|
||||
Set32(p, tag)
|
||||
// Set32(p + 4, (UInt32)(size - 8))
|
||||
Set16(p + 4, (UInt16)(size - 8))
|
||||
Set16(p + 6, 0)
|
||||
p += 8;
|
||||
|
||||
unsigned subOffs = 0;
|
||||
unsigned printOffs = 0;
|
||||
if (newOrderScheme)
|
||||
subOffs = (unsigned)len2;
|
||||
else
|
||||
printOffs = (unsigned)len1 + 2;
|
||||
|
||||
Set16(p + 0, (UInt16)subOffs)
|
||||
Set16(p + 2, (UInt16)len1)
|
||||
Set16(p + 4, (UInt16)printOffs)
|
||||
Set16(p + 6, (UInt16)len2)
|
||||
p += 8;
|
||||
if (isSymLink)
|
||||
{
|
||||
const UInt32 flags = isAbs ? 0 : Z7_WIN_SYMLINK_FLAG_RELATIVE;
|
||||
Set32(p, flags)
|
||||
p += 4;
|
||||
}
|
||||
WriteString(p + subOffs, subs);
|
||||
if (needPrintName)
|
||||
WriteString(p + printOffs, path);
|
||||
}
|
||||
|
||||
#endif // defined(_WIN32) && !defined(UNDER_CE)
|
||||
|
||||
|
||||
static void GetString(const Byte *p, unsigned len, UString &res)
|
||||
{
|
||||
wchar_t *s = res.GetBuf(len);
|
||||
unsigned i;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
const wchar_t c = Get16(p + (size_t)i * 2);
|
||||
if (c == 0)
|
||||
break;
|
||||
s[i] = c;
|
||||
}
|
||||
s[i] = 0;
|
||||
res.ReleaseBuf_SetLen(i);
|
||||
}
|
||||
|
||||
|
||||
bool CReparseAttr::Parse(const Byte *p, size_t size)
|
||||
{
|
||||
ErrorCode = (DWORD)ERROR_INVALID_REPARSE_DATA;
|
||||
HeaderError = true;
|
||||
TagIsUnknown = true;
|
||||
MinorError = false;
|
||||
|
||||
if (size < 8)
|
||||
return false;
|
||||
Tag = Get32(p);
|
||||
if (Get16(p + 6) != 0) // padding
|
||||
{
|
||||
// DOCs: Reserved : the field SHOULD be set to 0
|
||||
// and MUST be ignored (by parser).
|
||||
// Win10 ignores it.
|
||||
MinorError = true; // optional
|
||||
}
|
||||
unsigned len = Get16(p + 4);
|
||||
p += 8;
|
||||
size -= 8;
|
||||
if (len != size)
|
||||
// if (len > size)
|
||||
return false;
|
||||
/*
|
||||
if ((type & kReparseFlags_Alias) == 0 ||
|
||||
(type & kReparseFlags_Microsoft) == 0 ||
|
||||
(type & 0xFFFF) != 3)
|
||||
*/
|
||||
HeaderError = false;
|
||||
|
||||
if ( Tag != Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT
|
||||
&& Tag != Z7_WIN_IO_REPARSE_TAG_SYMLINK
|
||||
&& Tag != Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK)
|
||||
{
|
||||
// for unsupported reparse points
|
||||
ErrorCode = (DWORD)ERROR_REPARSE_TAG_INVALID; // ERROR_REPARSE_TAG_MISMATCH
|
||||
// errorCode = ERROR_REPARSE_TAG_MISMATCH; // ERROR_REPARSE_TAG_INVALID
|
||||
return false;
|
||||
}
|
||||
|
||||
TagIsUnknown = false;
|
||||
|
||||
if (Tag == Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK)
|
||||
{
|
||||
if (len < 4)
|
||||
return false;
|
||||
if (Get32(p) != Z7_WIN_LX_SYMLINK_VERSION_2)
|
||||
return false;
|
||||
len -= 4;
|
||||
p += 4;
|
||||
char *s = WslName.GetBuf(len);
|
||||
unsigned i;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
const char c = (char)p[i];
|
||||
s[i] = c;
|
||||
if (c == 0)
|
||||
break;
|
||||
}
|
||||
s[i] = 0;
|
||||
WslName.ReleaseBuf_SetLen(i);
|
||||
MinorError = (i != len);
|
||||
ErrorCode = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (len < 8)
|
||||
return false;
|
||||
const unsigned subOffs = Get16(p);
|
||||
const unsigned subLen = Get16(p + 2);
|
||||
const unsigned printOffs = Get16(p + 4);
|
||||
const unsigned printLen = Get16(p + 6);
|
||||
len -= 8;
|
||||
p += 8;
|
||||
|
||||
Flags = 0;
|
||||
if (Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK)
|
||||
{
|
||||
if (len < 4)
|
||||
return false;
|
||||
Flags = Get32(p);
|
||||
len -= 4;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen)
|
||||
return false;
|
||||
if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen)
|
||||
return false;
|
||||
GetString(p + subOffs, subLen >> 1, SubsName);
|
||||
GetString(p + printOffs, printLen >> 1, PrintName);
|
||||
|
||||
ErrorCode = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CReparseShortInfo::Parse(const Byte *p, size_t size)
|
||||
{
|
||||
const Byte * const start = p;
|
||||
Offset = 0;
|
||||
Size = 0;
|
||||
if (size < 8)
|
||||
return false;
|
||||
const UInt32 Tag = Get32(p);
|
||||
UInt32 len = Get16(p + 4);
|
||||
/*
|
||||
if (len + 8 > size)
|
||||
return false;
|
||||
*/
|
||||
/*
|
||||
if ((type & kReparseFlags_Alias) == 0 ||
|
||||
(type & kReparseFlags_Microsoft) == 0 ||
|
||||
(type & 0xFFFF) != 3)
|
||||
*/
|
||||
if (Tag != Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT &&
|
||||
Tag != Z7_WIN_IO_REPARSE_TAG_SYMLINK)
|
||||
// return true;
|
||||
return false;
|
||||
/*
|
||||
if (Get16(p + 6) != 0) // padding
|
||||
return false;
|
||||
*/
|
||||
p += 8;
|
||||
size -= 8;
|
||||
if (len != size) // do we need that check?
|
||||
return false;
|
||||
if (len < 8)
|
||||
return false;
|
||||
unsigned subOffs = Get16(p);
|
||||
unsigned subLen = Get16(p + 2);
|
||||
unsigned printOffs = Get16(p + 4);
|
||||
unsigned printLen = Get16(p + 6);
|
||||
len -= 8;
|
||||
p += 8;
|
||||
|
||||
// UInt32 Flags = 0;
|
||||
if (Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK)
|
||||
{
|
||||
if (len < 4)
|
||||
return false;
|
||||
// Flags = Get32(p);
|
||||
len -= 4;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen)
|
||||
return false;
|
||||
if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen)
|
||||
return false;
|
||||
|
||||
Offset = (unsigned)(p - start) + subOffs;
|
||||
Size = subLen;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CReparseAttr::IsOkNamePair() const
|
||||
{
|
||||
if (IsLinkPrefix(SubsName))
|
||||
{
|
||||
if (PrintName == GetPath())
|
||||
return true;
|
||||
/*
|
||||
if (!IsDrivePath(SubsName.Ptr(k_LinkPrefix_Size)))
|
||||
return PrintName.IsEmpty();
|
||||
if (wcscmp(SubsName.Ptr(k_LinkPrefix_Size), PrintName) == 0)
|
||||
return true;
|
||||
*/
|
||||
}
|
||||
return wcscmp(SubsName, PrintName) == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
bool CReparseAttr::IsVolume() const
|
||||
{
|
||||
if (!IsLinkPrefix(SubsName))
|
||||
return false;
|
||||
return IsVolumeName(SubsName.Ptr(k_LinkPrefix_Size));
|
||||
}
|
||||
*/
|
||||
|
||||
UString CReparseAttr::GetPath() const
|
||||
{
|
||||
UString s (SubsName);
|
||||
if (IsSymLink_WSL())
|
||||
{
|
||||
// if (CheckUTF8(attr.WslName)
|
||||
if (!ConvertUTF8ToUnicode(WslName, s))
|
||||
MultiByteToUnicodeString2(s, WslName);
|
||||
}
|
||||
else if (IsLinkPrefix(s))
|
||||
{
|
||||
if (IsString1PrefixedByString2_NoCase_Ascii(s.Ptr(), k_LinkPrefix_UNC))
|
||||
{
|
||||
s.DeleteFrontal(6);
|
||||
s.ReplaceOneCharAtPos(0, '\\');
|
||||
}
|
||||
else
|
||||
{
|
||||
s.ReplaceOneCharAtPos(1, '\\'); // we normalize prefix from "\??\" to "\\?\"
|
||||
if (IsDrivePath(s.Ptr(k_LinkPrefix_Size)))
|
||||
s.DeleteFrontal(k_LinkPrefix_Size);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
#ifdef Z7_DEVICE_FILE
|
||||
|
||||
namespace NSystem
|
||||
{
|
||||
bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
|
||||
}
|
||||
#endif // Z7_DEVICE_FILE
|
||||
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
|
||||
namespace NIO {
|
||||
|
||||
bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMATION *fileInfo)
|
||||
{
|
||||
reparseData.Free();
|
||||
CInFile file;
|
||||
if (!file.OpenReparse(path))
|
||||
return false;
|
||||
|
||||
if (fileInfo)
|
||||
file.GetFileInformation(fileInfo);
|
||||
|
||||
const unsigned kBufSize = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
|
||||
CByteArr buf(kBufSize);
|
||||
DWORD returnedSize;
|
||||
if (!file.DeviceIoControlOut(my_FSCTL_GET_REPARSE_POINT, buf, kBufSize, &returnedSize))
|
||||
return false;
|
||||
reparseData.CopyFrom(buf, returnedSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CreatePrefixDirOfFile(CFSTR path)
|
||||
{
|
||||
FString path2 (path);
|
||||
const int pos = path2.ReverseFind_PathSepar();
|
||||
if (pos < 0)
|
||||
return true;
|
||||
#ifdef _WIN32
|
||||
if (pos == 2 && path2[1] == L':')
|
||||
return true; // we don't create Disk folder;
|
||||
#endif
|
||||
path2.DeleteFrom((unsigned)pos);
|
||||
return NDir::CreateComplexDir(path2);
|
||||
}
|
||||
|
||||
|
||||
static bool OutIoReparseData(DWORD controlCode, CFSTR path, void *data, DWORD size)
|
||||
{
|
||||
COutFile file;
|
||||
if (!file.Open(path,
|
||||
FILE_SHARE_WRITE,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS))
|
||||
return false;
|
||||
|
||||
DWORD returnedSize;
|
||||
return file.DeviceIoControl(controlCode, data, size, NULL, 0, &returnedSize);
|
||||
}
|
||||
|
||||
|
||||
// MOUNT_POINT (Junction Point) and LX_SYMLINK (WSL) can be written without administrator rights.
|
||||
// SYMLINK requires administrator rights.
|
||||
// If there is Reparse data already, it still writes new Reparse data
|
||||
bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size)
|
||||
{
|
||||
NFile::NFind::CFileInfo fi;
|
||||
if (fi.Find(path))
|
||||
{
|
||||
if (fi.IsDir() != isDir)
|
||||
{
|
||||
::SetLastError(ERROR_DIRECTORY);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isDir)
|
||||
{
|
||||
if (!NDir::CreateComplexDir(path))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
CreatePrefixDirOfFile(path);
|
||||
COutFile file;
|
||||
if (!file.Create_NEW(path))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return OutIoReparseData(my_FSCTL_SET_REPARSE_POINT, path, (void *)(const Byte *)(data), size);
|
||||
}
|
||||
|
||||
|
||||
bool DeleteReparseData(CFSTR path)
|
||||
{
|
||||
CByteBuffer reparseData;
|
||||
if (!GetReparseData(path, reparseData, NULL))
|
||||
return false;
|
||||
/* MSDN: The tag specified in the ReparseTag member of this structure
|
||||
must match the tag of the reparse point to be deleted,
|
||||
and the ReparseDataLength member must be zero */
|
||||
#define my_REPARSE_DATA_BUFFER_HEADER_SIZE 8
|
||||
if (reparseData.Size() < my_REPARSE_DATA_BUFFER_HEADER_SIZE)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_REPARSE_DATA);
|
||||
return false;
|
||||
}
|
||||
// BYTE buf[my_REPARSE_DATA_BUFFER_HEADER_SIZE];
|
||||
// memset(buf, 0, sizeof(buf));
|
||||
// memcpy(buf, reparseData, 4); // tag
|
||||
memset(reparseData + 4, 0, my_REPARSE_DATA_BUFFER_HEADER_SIZE - 4);
|
||||
return OutIoReparseData(my_FSCTL_DELETE_REPARSE_POINT, path, reparseData, my_REPARSE_DATA_BUFFER_HEADER_SIZE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // defined(_WIN32) && !defined(UNDER_CE)
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
namespace NIO {
|
||||
|
||||
bool GetReparseData(CFSTR path, CByteBuffer &reparseData)
|
||||
{
|
||||
reparseData.Free();
|
||||
|
||||
#define MAX_PATHNAME_LEN 1024
|
||||
char buf[MAX_PATHNAME_LEN + 2];
|
||||
const size_t request = sizeof(buf) - 1;
|
||||
|
||||
// printf("\nreadlink() path = %s \n", path);
|
||||
const ssize_t size = readlink(path, buf, request);
|
||||
// there is no tail zero
|
||||
|
||||
if (size < 0)
|
||||
return false;
|
||||
if ((size_t)size >= request)
|
||||
{
|
||||
SetLastError(EINVAL); // check it: ENAMETOOLONG
|
||||
return false;
|
||||
}
|
||||
|
||||
// printf("\nreadlink() res = %s size = %d \n", buf, (int)size);
|
||||
reparseData.CopyFrom((const Byte *)buf, (size_t)size);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// If there is Reparse data already, it still writes new Reparse data
|
||||
bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size)
|
||||
{
|
||||
// AString s;
|
||||
// s.SetFrom_CalcLen(data, size);
|
||||
// return (symlink(s, path) == 0);
|
||||
UNUSED_VAR(path)
|
||||
UNUSED_VAR(isDir)
|
||||
UNUSED_VAR(data)
|
||||
UNUSED_VAR(size)
|
||||
SetLastError(ENOSYS);
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
bool SetSymLink(CFSTR from, CFSTR to)
|
||||
{
|
||||
// printf("\nsymlink() %s -> %s\n", from, to);
|
||||
int ir;
|
||||
// ir = unlink(path);
|
||||
// if (ir == 0)
|
||||
ir = symlink(to, from);
|
||||
return (ir == 0);
|
||||
}
|
||||
|
||||
bool SetSymLink_UString(CFSTR from, const UString &to)
|
||||
{
|
||||
AString utf;
|
||||
ConvertUnicodeToUTF8(to, utf);
|
||||
return SetSymLink(from, utf);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // !_WIN32
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,12 @@
|
||||
// Windows/FileMapping.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "FileMapping.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NFile {
|
||||
namespace NMapping {
|
||||
|
||||
|
||||
}}}
|
||||
@@ -0,0 +1,66 @@
|
||||
// Windows/FileMapping.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_FILE_MAPPING_H
|
||||
#define ZIP7_INC_WINDOWS_FILE_MAPPING_H
|
||||
|
||||
#include "../Common/MyTypes.h"
|
||||
|
||||
#include "Handle.h"
|
||||
|
||||
namespace NWindows {
|
||||
|
||||
class CFileMapping: public CHandle
|
||||
{
|
||||
public:
|
||||
WRes Create(DWORD protect, UInt64 maxSize, LPCTSTR name)
|
||||
{
|
||||
_handle = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, protect, (DWORD)(maxSize >> 32), (DWORD)maxSize, name);
|
||||
return ::GetLastError();
|
||||
}
|
||||
|
||||
WRes Open(DWORD
|
||||
#ifndef UNDER_CE
|
||||
desiredAccess
|
||||
#endif
|
||||
, LPCTSTR name)
|
||||
{
|
||||
#ifdef UNDER_CE
|
||||
WRes res = Create(PAGE_READONLY, 0, name);
|
||||
if (res == ERROR_ALREADY_EXISTS)
|
||||
return 0;
|
||||
Close();
|
||||
if (res == 0)
|
||||
res = ERROR_FILE_NOT_FOUND;
|
||||
return res;
|
||||
#else
|
||||
_handle = ::OpenFileMapping(desiredAccess, FALSE, name);
|
||||
if (_handle != NULL)
|
||||
return 0;
|
||||
return ::GetLastError();
|
||||
#endif
|
||||
}
|
||||
|
||||
LPVOID Map(DWORD desiredAccess, UInt64 fileOffset, SIZE_T numberOfBytesToMap)
|
||||
{
|
||||
return ::MapViewOfFile(_handle, desiredAccess, (DWORD)(fileOffset >> 32), (DWORD)fileOffset, numberOfBytesToMap);
|
||||
}
|
||||
|
||||
#ifndef UNDER_CE
|
||||
LPVOID Map(DWORD desiredAccess, UInt64 fileOffset, SIZE_T numberOfBytesToMap, LPVOID baseAddress)
|
||||
{
|
||||
return ::MapViewOfFileEx(_handle, desiredAccess, (DWORD)(fileOffset >> 32), (DWORD)fileOffset, numberOfBytesToMap, baseAddress);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
class CFileUnmapper
|
||||
{
|
||||
const void *_data;
|
||||
public:
|
||||
CFileUnmapper(const void *data) : _data(data) {}
|
||||
~CFileUnmapper() { ::UnmapViewOfFile(_data); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,911 @@
|
||||
// Windows/FileName.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include "../Common/StringConvert.h"
|
||||
#endif
|
||||
|
||||
#include "FileDir.h"
|
||||
#include "FileName.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
|
||||
namespace NWindows {
|
||||
namespace NFile {
|
||||
namespace NName {
|
||||
|
||||
#define IS_SEPAR(c) IS_PATH_SEPAR(c)
|
||||
|
||||
int FindSepar(const wchar_t *s) throw()
|
||||
{
|
||||
for (const wchar_t *p = s;; p++)
|
||||
{
|
||||
const wchar_t c = *p;
|
||||
if (c == 0)
|
||||
return -1;
|
||||
if (IS_SEPAR(c))
|
||||
return (int)(p - s);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef USE_UNICODE_FSTRING
|
||||
int FindSepar(const FChar *s) throw()
|
||||
{
|
||||
for (const FChar *p = s;; p++)
|
||||
{
|
||||
const FChar c = *p;
|
||||
if (c == 0)
|
||||
return -1;
|
||||
if (IS_SEPAR(c))
|
||||
return (int)(p - s);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef USE_UNICODE_FSTRING
|
||||
void NormalizeDirPathPrefix(FString &dirPath)
|
||||
{
|
||||
if (dirPath.IsEmpty())
|
||||
return;
|
||||
if (!IsPathSepar(dirPath.Back()))
|
||||
dirPath.Add_PathSepar();
|
||||
}
|
||||
#endif
|
||||
|
||||
void NormalizeDirPathPrefix(UString &dirPath)
|
||||
{
|
||||
if (dirPath.IsEmpty())
|
||||
return;
|
||||
if (!IsPathSepar(dirPath.Back()))
|
||||
dirPath.Add_PathSepar();
|
||||
}
|
||||
|
||||
|
||||
#define IS_LETTER_CHAR(c) ((((unsigned)(int)(c) | 0x20) - (unsigned)'a' <= (unsigned)('z' - 'a')))
|
||||
bool IsDrivePath (const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); }
|
||||
// bool IsDriveName2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; }
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
bool IsDrivePath2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; }
|
||||
|
||||
#ifndef USE_UNICODE_FSTRING
|
||||
#ifdef Z7_LONG_PATH
|
||||
static void NormalizeDirSeparators(UString &s)
|
||||
{
|
||||
const unsigned len = s.Len();
|
||||
for (unsigned i = 0; i < len; i++)
|
||||
if (s[i] == '/')
|
||||
s.ReplaceOneCharAtPos(i, WCHAR_PATH_SEPARATOR);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void NormalizeDirSeparators(FString &s)
|
||||
{
|
||||
const unsigned len = s.Len();
|
||||
for (unsigned i = 0; i < len; i++)
|
||||
if (s[i] == '/')
|
||||
s.ReplaceOneCharAtPos(i, FCHAR_PATH_SEPARATOR);
|
||||
}
|
||||
|
||||
bool IsAltPathPrefix(CFSTR s) throw()
|
||||
{
|
||||
unsigned len = MyStringLen(s);
|
||||
if (len == 0)
|
||||
return false;
|
||||
if (s[len - 1] != ':')
|
||||
return false;
|
||||
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
if (IsDevicePath(s))
|
||||
return false;
|
||||
if (IsSuperPath(s))
|
||||
{
|
||||
s += kSuperPathPrefixSize;
|
||||
len -= kSuperPathPrefixSize;
|
||||
}
|
||||
if (len == 2 && IsDrivePath2(s))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
const char * const kSuperPathPrefix =
|
||||
STRING_PATH_SEPARATOR
|
||||
STRING_PATH_SEPARATOR "?"
|
||||
STRING_PATH_SEPARATOR;
|
||||
#ifdef Z7_LONG_PATH
|
||||
static const char * const kSuperUncPrefix =
|
||||
STRING_PATH_SEPARATOR
|
||||
STRING_PATH_SEPARATOR "?"
|
||||
STRING_PATH_SEPARATOR "UNC"
|
||||
STRING_PATH_SEPARATOR;
|
||||
#endif
|
||||
|
||||
#define IS_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '.' && IS_SEPAR((s)[3]))
|
||||
#define IS_SUPER_PREFIX(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '?' && IS_SEPAR((s)[3]))
|
||||
|
||||
#define IS_UNC_WITH_SLASH(s) ( \
|
||||
((s)[0] == 'U' || (s)[0] == 'u') \
|
||||
&& ((s)[1] == 'N' || (s)[1] == 'n') \
|
||||
&& ((s)[2] == 'C' || (s)[2] == 'c') \
|
||||
&& IS_SEPAR((s)[3]))
|
||||
|
||||
static const unsigned kDrivePrefixSize = 3; /* c:\ */
|
||||
|
||||
bool IsSuperPath(const wchar_t *s) throw();
|
||||
bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); }
|
||||
// bool IsSuperUncPath(const wchar_t *s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); }
|
||||
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
|
||||
#define IS_SUPER_OR_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && ((s)[2] == '?' || (s)[2] == '.') && IS_SEPAR((s)[3]))
|
||||
bool IsSuperOrDevicePath(const wchar_t *s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); }
|
||||
bool IsDevicePath(CFSTR s) throw()
|
||||
{
|
||||
#ifdef UNDER_CE
|
||||
|
||||
s = s;
|
||||
return false;
|
||||
/*
|
||||
// actually we don't know the way to open device file in WinCE.
|
||||
unsigned len = MyStringLen(s);
|
||||
if (len < 5 || len > 5 || !IsString1PrefixedByString2(s, "DSK"))
|
||||
return false;
|
||||
if (s[4] != ':')
|
||||
return false;
|
||||
// for reading use SG_REQ sg; if (DeviceIoControl(dsk, IOCTL_DISK_READ));
|
||||
*/
|
||||
|
||||
#else
|
||||
|
||||
if (!IS_DEVICE_PATH(s))
|
||||
return false;
|
||||
const unsigned len = MyStringLen(s);
|
||||
if (len == 6 && s[5] == ':')
|
||||
return true;
|
||||
if (len < 18 || len > 22 || !IsString1PrefixedByString2(s + kDevicePathPrefixSize, "PhysicalDrive"))
|
||||
return false;
|
||||
for (unsigned i = 17; i < len; i++)
|
||||
if (s[i] < '0' || s[i] > '9')
|
||||
return false;
|
||||
return true;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IsSuperUncPath(CFSTR s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); }
|
||||
bool IsNetworkPath(CFSTR s) throw()
|
||||
{
|
||||
if (!IS_SEPAR(s[0]) || !IS_SEPAR(s[1]))
|
||||
return false;
|
||||
if (IsSuperUncPath(s))
|
||||
return true;
|
||||
const FChar c = s[2];
|
||||
return (c != '.' && c != '?');
|
||||
}
|
||||
|
||||
unsigned GetNetworkServerPrefixSize(CFSTR s) throw()
|
||||
{
|
||||
if (!IS_SEPAR(s[0]) || !IS_SEPAR(s[1]))
|
||||
return 0;
|
||||
unsigned prefixSize = 2;
|
||||
if (IsSuperUncPath(s))
|
||||
prefixSize = kSuperUncPathPrefixSize;
|
||||
else
|
||||
{
|
||||
const FChar c = s[2];
|
||||
if (c == '.' || c == '?')
|
||||
return 0;
|
||||
}
|
||||
const int pos = FindSepar(s + prefixSize);
|
||||
if (pos < 0)
|
||||
return 0;
|
||||
return prefixSize + (unsigned)(pos + 1);
|
||||
}
|
||||
|
||||
bool IsNetworkShareRootPath(CFSTR s) throw()
|
||||
{
|
||||
const unsigned prefixSize = GetNetworkServerPrefixSize(s);
|
||||
if (prefixSize == 0)
|
||||
return false;
|
||||
s += prefixSize;
|
||||
const int pos = FindSepar(s);
|
||||
if (pos < 0)
|
||||
return true;
|
||||
return s[(unsigned)pos + 1] == 0;
|
||||
}
|
||||
|
||||
bool IsAltStreamPrefixWithColon(const UString &s) throw()
|
||||
{
|
||||
if (s.IsEmpty())
|
||||
return false;
|
||||
if (s.Back() != ':')
|
||||
return false;
|
||||
unsigned pos = 0;
|
||||
if (IsSuperPath(s))
|
||||
pos = kSuperPathPrefixSize;
|
||||
if (s.Len() - pos == 2 && IsDrivePath2(s.Ptr(pos)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool If_IsSuperPath_RemoveSuperPrefix(UString &s)
|
||||
{
|
||||
if (!IsSuperPath(s))
|
||||
return false;
|
||||
unsigned start = 0;
|
||||
unsigned count = kSuperPathPrefixSize;
|
||||
const wchar_t *s2 = s.Ptr(kSuperPathPrefixSize);
|
||||
if (IS_UNC_WITH_SLASH(s2))
|
||||
{
|
||||
start = 2;
|
||||
count = kSuperUncPathPrefixSize - 2;
|
||||
}
|
||||
s.Delete(start, count);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#ifndef USE_UNICODE_FSTRING
|
||||
bool IsDrivePath2(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; }
|
||||
// bool IsDriveName2(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; }
|
||||
bool IsDrivePath(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); }
|
||||
bool IsSuperPath(CFSTR s) throw() { return IS_SUPER_PREFIX(s); }
|
||||
bool IsSuperOrDevicePath(CFSTR s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); }
|
||||
#endif // USE_UNICODE_FSTRING
|
||||
|
||||
bool IsDrivePath_SuperAllowed(CFSTR s) throw()
|
||||
{
|
||||
if (IsSuperPath(s))
|
||||
s += kSuperPathPrefixSize;
|
||||
return IsDrivePath(s);
|
||||
}
|
||||
|
||||
bool IsDriveRootPath_SuperAllowed(CFSTR s) throw()
|
||||
{
|
||||
if (IsSuperPath(s))
|
||||
s += kSuperPathPrefixSize;
|
||||
return IsDrivePath(s) && s[kDrivePrefixSize] == 0;
|
||||
}
|
||||
|
||||
bool IsAbsolutePath(const wchar_t *s) throw()
|
||||
{
|
||||
return IS_SEPAR(s[0]) || IsDrivePath2(s);
|
||||
}
|
||||
|
||||
int FindAltStreamColon(CFSTR path) throw()
|
||||
{
|
||||
unsigned i = 0;
|
||||
if (IsSuperPath(path))
|
||||
i = kSuperPathPrefixSize;
|
||||
if (IsDrivePath2(path + i))
|
||||
i += 2;
|
||||
int colonPos = -1;
|
||||
for (;; i++)
|
||||
{
|
||||
const FChar c = path[i];
|
||||
if (c == 0)
|
||||
return colonPos;
|
||||
if (c == ':')
|
||||
{
|
||||
if (colonPos < 0)
|
||||
colonPos = (int)i;
|
||||
continue;
|
||||
}
|
||||
if (IS_SEPAR(c))
|
||||
colonPos = -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef USE_UNICODE_FSTRING
|
||||
|
||||
static unsigned GetRootPrefixSize_Of_NetworkPath(CFSTR s)
|
||||
{
|
||||
// Network path: we look "server\path\" as root prefix
|
||||
const int pos = FindSepar(s);
|
||||
if (pos < 0)
|
||||
return 0;
|
||||
const int pos2 = FindSepar(s + (unsigned)pos + 1);
|
||||
if (pos2 < 0)
|
||||
return 0;
|
||||
return (unsigned)pos + (unsigned)pos2 + 2;
|
||||
}
|
||||
|
||||
static unsigned GetRootPrefixSize_Of_SimplePath(CFSTR s)
|
||||
{
|
||||
if (IsDrivePath(s))
|
||||
return kDrivePrefixSize;
|
||||
if (!IS_SEPAR(s[0]))
|
||||
return 0;
|
||||
if (s[1] == 0 || !IS_SEPAR(s[1]))
|
||||
return 1;
|
||||
const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2);
|
||||
return (size == 0) ? 0 : 2 + size;
|
||||
}
|
||||
|
||||
static unsigned GetRootPrefixSize_Of_SuperPath(CFSTR s)
|
||||
{
|
||||
if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize))
|
||||
{
|
||||
const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize);
|
||||
return (size == 0) ? 0 : kSuperUncPathPrefixSize + size;
|
||||
}
|
||||
// we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\"
|
||||
const int pos = FindSepar(s + kSuperPathPrefixSize);
|
||||
if (pos < 0)
|
||||
return 0;
|
||||
return kSuperPathPrefixSize + (unsigned)pos + 1;
|
||||
}
|
||||
|
||||
unsigned GetRootPrefixSize(CFSTR s) throw()
|
||||
{
|
||||
if (IS_DEVICE_PATH(s))
|
||||
return kDevicePathPrefixSize;
|
||||
if (IsSuperPath(s))
|
||||
return GetRootPrefixSize_Of_SuperPath(s);
|
||||
return GetRootPrefixSize_Of_SimplePath(s);
|
||||
}
|
||||
|
||||
#endif // USE_UNICODE_FSTRING
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw()
|
||||
{
|
||||
// Network path: we look "server\path\" as root prefix
|
||||
const int pos = FindSepar(s);
|
||||
if (pos < 0)
|
||||
return 0;
|
||||
const int pos2 = FindSepar(s + (unsigned)pos + 1);
|
||||
if (pos2 < 0)
|
||||
return 0;
|
||||
return (unsigned)(pos + pos2 + 2);
|
||||
}
|
||||
|
||||
static unsigned GetRootPrefixSize_Of_SimplePath(const wchar_t *s) throw()
|
||||
{
|
||||
if (IsDrivePath(s))
|
||||
return kDrivePrefixSize;
|
||||
if (!IS_SEPAR(s[0]))
|
||||
return 0;
|
||||
if (s[1] == 0 || !IS_SEPAR(s[1]))
|
||||
return 1;
|
||||
const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2);
|
||||
return (size == 0) ? 0 : 2 + size;
|
||||
}
|
||||
|
||||
static unsigned GetRootPrefixSize_Of_SuperPath(const wchar_t *s) throw()
|
||||
{
|
||||
if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize))
|
||||
{
|
||||
const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize);
|
||||
return (size == 0) ? 0 : kSuperUncPathPrefixSize + size;
|
||||
}
|
||||
// we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\"
|
||||
const int pos = FindSepar(s + kSuperPathPrefixSize);
|
||||
if (pos < 0)
|
||||
return 0;
|
||||
return kSuperPathPrefixSize + (unsigned)(pos + 1);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
unsigned GetRootPrefixSize(const wchar_t *s) throw()
|
||||
#else
|
||||
unsigned GetRootPrefixSize_WINDOWS(const wchar_t *s) throw()
|
||||
#endif
|
||||
{
|
||||
if (IS_DEVICE_PATH(s))
|
||||
return kDevicePathPrefixSize;
|
||||
if (IsSuperPath(s))
|
||||
return GetRootPrefixSize_Of_SuperPath(s);
|
||||
return GetRootPrefixSize_Of_SimplePath(s);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
bool IsAbsolutePath(const wchar_t *s) throw() { return IS_SEPAR(s[0]); }
|
||||
|
||||
#ifndef USE_UNICODE_FSTRING
|
||||
unsigned GetRootPrefixSize(CFSTR s) throw();
|
||||
unsigned GetRootPrefixSize(CFSTR s) throw() { return IS_SEPAR(s[0]) ? 1 : 0; }
|
||||
#endif
|
||||
unsigned GetRootPrefixSize(const wchar_t *s) throw() { return IS_SEPAR(s[0]) ? 1 : 0; }
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
#ifndef UNDER_CE
|
||||
|
||||
|
||||
#ifdef USE_UNICODE_FSTRING
|
||||
|
||||
#define GetCurDir NDir::GetCurrentDir
|
||||
|
||||
#else
|
||||
|
||||
static bool GetCurDir(UString &path)
|
||||
{
|
||||
path.Empty();
|
||||
FString s;
|
||||
if (!NDir::GetCurrentDir(s))
|
||||
return false;
|
||||
path = fs2us(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static bool ResolveDotsFolders(UString &s)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// s.Replace(L'/', WCHAR_PATH_SEPARATOR);
|
||||
#endif
|
||||
|
||||
for (unsigned i = 0;;)
|
||||
{
|
||||
const wchar_t c = s[i];
|
||||
if (c == 0)
|
||||
return true;
|
||||
if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1])))
|
||||
{
|
||||
const wchar_t c1 = s[i + 1];
|
||||
if (c1 == '.')
|
||||
{
|
||||
const wchar_t c2 = s[i + 2];
|
||||
if (IS_SEPAR(c2) || c2 == 0)
|
||||
{
|
||||
if (i == 0)
|
||||
return false;
|
||||
int k = (int)i - 2;
|
||||
i += 2;
|
||||
|
||||
for (;; k--)
|
||||
{
|
||||
if (k < 0)
|
||||
return false;
|
||||
if (!IS_SEPAR(s[(unsigned)k]))
|
||||
break;
|
||||
}
|
||||
|
||||
do
|
||||
k--;
|
||||
while (k >= 0 && !IS_SEPAR(s[(unsigned)k]));
|
||||
|
||||
unsigned num;
|
||||
|
||||
if (k >= 0)
|
||||
{
|
||||
num = i - (unsigned)k;
|
||||
i = (unsigned)k;
|
||||
}
|
||||
else
|
||||
{
|
||||
num = (c2 == 0 ? i : (i + 1));
|
||||
i = 0;
|
||||
}
|
||||
|
||||
s.Delete(i, num);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (IS_SEPAR(c1) || c1 == 0)
|
||||
{
|
||||
unsigned num = 2;
|
||||
if (i != 0)
|
||||
i--;
|
||||
else if (c1 == 0)
|
||||
num = 1;
|
||||
s.Delete(i, num);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // UNDER_CE
|
||||
|
||||
#define LONG_PATH_DOTS_FOLDERS_PARSING
|
||||
|
||||
|
||||
/*
|
||||
Windows (at least 64-bit XP) can't resolve "." or ".." in paths that start with SuperPrefix \\?\
|
||||
To solve that problem we check such path:
|
||||
- super path contains "." or ".." - we use kSuperPathType_UseOnlySuper
|
||||
- super path doesn't contain "." or ".." - we use kSuperPathType_UseOnlyMain
|
||||
*/
|
||||
#ifdef LONG_PATH_DOTS_FOLDERS_PARSING
|
||||
#ifndef UNDER_CE
|
||||
static bool AreThereDotsFolders(CFSTR s)
|
||||
{
|
||||
for (unsigned i = 0;; i++)
|
||||
{
|
||||
FChar c = s[i];
|
||||
if (c == 0)
|
||||
return false;
|
||||
if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1])))
|
||||
{
|
||||
FChar c1 = s[i + 1];
|
||||
if (c1 == 0 || IS_SEPAR(c1) ||
|
||||
(c1 == '.' && (s[i + 2] == 0 || IS_SEPAR(s[i + 2]))))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // LONG_PATH_DOTS_FOLDERS_PARSING
|
||||
|
||||
#ifdef Z7_LONG_PATH
|
||||
|
||||
/*
|
||||
Most of Windows versions have problems, if some file or dir name
|
||||
contains '.' or ' ' at the end of name (Bad Path).
|
||||
To solve that problem, we always use Super Path ("\\?\" prefix and full path)
|
||||
in such cases. Note that "." and ".." are not bad names.
|
||||
|
||||
There are 3 cases:
|
||||
1) If the path is already Super Path, we use that path
|
||||
2) If the path is not Super Path :
|
||||
2.1) Bad Path; we use only Super Path.
|
||||
2.2) Good Path; we use Main Path. If it fails, we use Super Path.
|
||||
|
||||
NeedToUseOriginalPath returns:
|
||||
kSuperPathType_UseOnlyMain : Super already
|
||||
kSuperPathType_UseOnlySuper : not Super, Bad Path
|
||||
kSuperPathType_UseMainAndSuper : not Super, Good Path
|
||||
*/
|
||||
|
||||
int GetUseSuperPathType(CFSTR s) throw()
|
||||
{
|
||||
if (IsSuperOrDevicePath(s))
|
||||
{
|
||||
#ifdef LONG_PATH_DOTS_FOLDERS_PARSING
|
||||
if ((s)[2] != '.')
|
||||
if (AreThereDotsFolders(s + kSuperPathPrefixSize))
|
||||
return kSuperPathType_UseOnlySuper;
|
||||
#endif
|
||||
return kSuperPathType_UseOnlyMain;
|
||||
}
|
||||
|
||||
for (unsigned i = 0;; i++)
|
||||
{
|
||||
FChar c = s[i];
|
||||
if (c == 0)
|
||||
return kSuperPathType_UseMainAndSuper;
|
||||
if (c == '.' || c == ' ')
|
||||
{
|
||||
FChar c2 = s[i + 1];
|
||||
if (c2 == 0 || IS_SEPAR(c2))
|
||||
{
|
||||
// if it's "." or "..", it's not bad name.
|
||||
if (c == '.')
|
||||
{
|
||||
if (i == 0 || IS_SEPAR(s[i - 1]))
|
||||
continue;
|
||||
if (s[i - 1] == '.')
|
||||
{
|
||||
if (i - 1 == 0 || IS_SEPAR(s[i - 2]))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return kSuperPathType_UseOnlySuper;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
returns false in two cases:
|
||||
- if GetCurDir was used, and GetCurDir returned error.
|
||||
- if we can't resolve ".." name.
|
||||
if path is ".", "..", res is empty.
|
||||
if it's Super Path already, res is empty.
|
||||
for \**** , and if GetCurDir is not drive (c:\), res is empty
|
||||
for absolute paths, returns true, res is Super path.
|
||||
*/
|
||||
|
||||
static bool GetSuperPathBase(CFSTR s, UString &res)
|
||||
{
|
||||
res.Empty();
|
||||
|
||||
FChar c = s[0];
|
||||
if (c == 0)
|
||||
return true;
|
||||
if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0)))
|
||||
return true;
|
||||
|
||||
if (IsSuperOrDevicePath(s))
|
||||
{
|
||||
#ifdef LONG_PATH_DOTS_FOLDERS_PARSING
|
||||
|
||||
if ((s)[2] == '.')
|
||||
return true;
|
||||
|
||||
// we will return true here, so we will try to use these problem paths.
|
||||
|
||||
if (!AreThereDotsFolders(s + kSuperPathPrefixSize))
|
||||
return true;
|
||||
|
||||
UString temp = fs2us(s);
|
||||
const unsigned fixedSize = GetRootPrefixSize_Of_SuperPath(temp);
|
||||
if (fixedSize == 0)
|
||||
return true;
|
||||
|
||||
UString rem = temp.Ptr(fixedSize);
|
||||
if (!ResolveDotsFolders(rem))
|
||||
return true;
|
||||
|
||||
temp.DeleteFrom(fixedSize);
|
||||
res += temp;
|
||||
res += rem;
|
||||
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IS_SEPAR(c))
|
||||
{
|
||||
if (IS_SEPAR(s[1]))
|
||||
{
|
||||
UString temp = fs2us(s + 2);
|
||||
const unsigned fixedSize = GetRootPrefixSize_Of_NetworkPath(temp);
|
||||
// we ignore that error to allow short network paths server\share?
|
||||
/*
|
||||
if (fixedSize == 0)
|
||||
return false;
|
||||
*/
|
||||
UString rem = temp.Ptr(fixedSize);
|
||||
if (!ResolveDotsFolders(rem))
|
||||
return false;
|
||||
res += kSuperUncPrefix;
|
||||
temp.DeleteFrom(fixedSize);
|
||||
res += temp;
|
||||
res += rem;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsDrivePath2(s))
|
||||
{
|
||||
UString temp = fs2us(s);
|
||||
unsigned prefixSize = 2;
|
||||
if (IsDrivePath(s))
|
||||
prefixSize = kDrivePrefixSize;
|
||||
UString rem = temp.Ptr(prefixSize);
|
||||
if (!ResolveDotsFolders(rem))
|
||||
return true;
|
||||
res += kSuperPathPrefix;
|
||||
temp.DeleteFrom(prefixSize);
|
||||
res += temp;
|
||||
res += rem;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
UString curDir;
|
||||
if (!GetCurDir(curDir))
|
||||
return false;
|
||||
NormalizeDirPathPrefix(curDir);
|
||||
|
||||
unsigned fixedSizeStart = 0;
|
||||
unsigned fixedSize = 0;
|
||||
const char *superMarker = NULL;
|
||||
if (IsSuperPath(curDir))
|
||||
{
|
||||
fixedSize = GetRootPrefixSize_Of_SuperPath(curDir);
|
||||
if (fixedSize == 0)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsDrivePath(curDir))
|
||||
{
|
||||
superMarker = kSuperPathPrefix;
|
||||
fixedSize = kDrivePrefixSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!IsPathSepar(curDir[0]) || !IsPathSepar(curDir[1]))
|
||||
return false;
|
||||
fixedSizeStart = 2;
|
||||
fixedSize = GetRootPrefixSize_Of_NetworkPath(curDir.Ptr(2));
|
||||
if (fixedSize == 0)
|
||||
return false;
|
||||
superMarker = kSuperUncPrefix;
|
||||
}
|
||||
}
|
||||
|
||||
UString temp;
|
||||
if (IS_SEPAR(c))
|
||||
{
|
||||
temp = fs2us(s + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
temp += &curDir[fixedSizeStart + fixedSize];
|
||||
temp += fs2us(s);
|
||||
}
|
||||
if (!ResolveDotsFolders(temp))
|
||||
return false;
|
||||
if (superMarker)
|
||||
res += superMarker;
|
||||
res += curDir.Mid(fixedSizeStart, fixedSize);
|
||||
res += temp;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
In that case if GetSuperPathBase doesn't return new path, we don't need
|
||||
to use same path that was used as main path
|
||||
|
||||
GetSuperPathBase superPath.IsEmpty() onlyIfNew
|
||||
false * * GetCurDir Error
|
||||
true false * use Super path
|
||||
true true true don't use any path, we already used mainPath
|
||||
true true false use main path as Super Path, we don't try mainMath
|
||||
That case is possible now if GetCurDir returns unknown
|
||||
type of path (not drive and not network)
|
||||
|
||||
We can change that code if we want to try mainPath, if GetSuperPathBase returns error,
|
||||
and we didn't try mainPath still.
|
||||
If we want to work that way, we don't need to use GetSuperPathBase return code.
|
||||
*/
|
||||
|
||||
bool GetSuperPath(CFSTR path, UString &superPath, bool onlyIfNew)
|
||||
{
|
||||
if (GetSuperPathBase(path, superPath))
|
||||
{
|
||||
if (superPath.IsEmpty())
|
||||
{
|
||||
// actually the only possible when onlyIfNew == true and superPath is empty
|
||||
// is case when
|
||||
|
||||
if (onlyIfNew)
|
||||
return false;
|
||||
superPath = fs2us(path);
|
||||
}
|
||||
|
||||
NormalizeDirSeparators(superPath);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetSuperPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2, bool onlyIfNew)
|
||||
{
|
||||
if (!GetSuperPathBase(s1, d1) ||
|
||||
!GetSuperPathBase(s2, d2))
|
||||
return false;
|
||||
|
||||
NormalizeDirSeparators(d1);
|
||||
NormalizeDirSeparators(d2);
|
||||
|
||||
if (d1.IsEmpty() && d2.IsEmpty() && onlyIfNew)
|
||||
return false;
|
||||
if (d1.IsEmpty()) d1 = fs2us(s1);
|
||||
if (d2.IsEmpty()) d2 = fs2us(s2);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// returns true, if we need additional use with New Super path.
|
||||
bool GetSuperPath(CFSTR path, UString &superPath)
|
||||
{
|
||||
if (GetSuperPathBase(path, superPath))
|
||||
return !superPath.IsEmpty();
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
#endif // Z7_LONG_PATH
|
||||
|
||||
bool GetFullPath(CFSTR dirPrefix, CFSTR s, FString &res)
|
||||
{
|
||||
res = s;
|
||||
|
||||
#ifdef UNDER_CE
|
||||
|
||||
if (!IS_SEPAR(s[0]))
|
||||
{
|
||||
if (!dirPrefix)
|
||||
return false;
|
||||
res = dirPrefix;
|
||||
res += s;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
const unsigned prefixSize = GetRootPrefixSize(s);
|
||||
if (prefixSize != 0)
|
||||
#ifdef _WIN32
|
||||
if (prefixSize != 1)
|
||||
#endif
|
||||
{
|
||||
if (!AreThereDotsFolders(s + prefixSize))
|
||||
return true;
|
||||
|
||||
UString rem = fs2us(s + prefixSize);
|
||||
if (!ResolveDotsFolders(rem))
|
||||
return true; // maybe false;
|
||||
res.DeleteFrom(prefixSize);
|
||||
res += us2fs(rem);
|
||||
return true;
|
||||
}
|
||||
|
||||
UString curDir;
|
||||
if (dirPrefix && prefixSize == 0)
|
||||
curDir = fs2us(dirPrefix); // we use (dirPrefix), only if (s) path is relative
|
||||
else
|
||||
{
|
||||
if (!GetCurDir(curDir))
|
||||
return false;
|
||||
}
|
||||
NormalizeDirPathPrefix(curDir);
|
||||
|
||||
unsigned fixedSize = GetRootPrefixSize(curDir);
|
||||
|
||||
UString temp;
|
||||
#ifdef _WIN32
|
||||
if (prefixSize != 0)
|
||||
{
|
||||
/* (s) is absolute path, but only (prefixSize == 1) is possible here.
|
||||
So for full resolving we need root of current folder and
|
||||
relative part of (s). */
|
||||
s += prefixSize;
|
||||
// (s) is relative part now
|
||||
if (fixedSize == 0)
|
||||
{
|
||||
// (curDir) is not absolute.
|
||||
// That case is unexpected, but we support it too.
|
||||
curDir.Empty();
|
||||
curDir.Add_PathSepar();
|
||||
fixedSize = 1;
|
||||
// (curDir) now is just Separ character.
|
||||
// So final (res) path later also will have Separ prefix.
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif // _WIN32
|
||||
{
|
||||
// (s) is relative path
|
||||
temp = curDir.Ptr(fixedSize);
|
||||
// (temp) is relative_part_of(curDir)
|
||||
}
|
||||
temp += fs2us(s);
|
||||
if (!ResolveDotsFolders(temp))
|
||||
return false;
|
||||
curDir.DeleteFrom(fixedSize);
|
||||
// (curDir) now contains only absolute prefix part
|
||||
res = us2fs(curDir);
|
||||
res += us2fs(temp);
|
||||
|
||||
#endif // UNDER_CE
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool GetFullPath(CFSTR path, FString &fullPath)
|
||||
{
|
||||
return GetFullPath(NULL, path, fullPath);
|
||||
}
|
||||
|
||||
}}}
|
||||
@@ -0,0 +1,142 @@
|
||||
// Windows/FileName.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_FILE_NAME_H
|
||||
#define ZIP7_INC_WINDOWS_FILE_NAME_H
|
||||
|
||||
#include "../Common/MyString.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NFile {
|
||||
namespace NName {
|
||||
|
||||
int FindSepar(const wchar_t *s) throw();
|
||||
#ifndef USE_UNICODE_FSTRING
|
||||
int FindSepar(const FChar *s) throw();
|
||||
#endif
|
||||
|
||||
void NormalizeDirPathPrefix(FString &dirPath); // ensures that it ended with '\\', if dirPath is not epmty
|
||||
void NormalizeDirPathPrefix(UString &dirPath);
|
||||
|
||||
#ifdef _WIN32
|
||||
void NormalizeDirSeparators(FString &s);
|
||||
#endif
|
||||
|
||||
bool IsDrivePath(const wchar_t *s) throw(); // first 3 chars are drive chars like "a:\\"
|
||||
|
||||
bool IsAltPathPrefix(CFSTR s) throw(); /* name: */
|
||||
|
||||
extern const char * const kSuperPathPrefix; /* \\?\ */
|
||||
const unsigned kDevicePathPrefixSize = 4;
|
||||
const unsigned kSuperPathPrefixSize = 4;
|
||||
const unsigned kSuperUncPathPrefixSize = kSuperPathPrefixSize + 4;
|
||||
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
|
||||
bool IsDevicePath(CFSTR s) throw(); /* \\.\ */
|
||||
bool IsSuperUncPath(CFSTR s) throw(); /* \\?\UNC\ */
|
||||
bool IsNetworkPath(CFSTR s) throw(); /* \\?\UNC\ or \\SERVER */
|
||||
|
||||
/* GetNetworkServerPrefixSize() returns size of server prefix:
|
||||
\\?\UNC\SERVER\
|
||||
\\SERVER\
|
||||
in another cases it returns 0
|
||||
*/
|
||||
|
||||
unsigned GetNetworkServerPrefixSize(CFSTR s) throw();
|
||||
|
||||
bool IsNetworkShareRootPath(CFSTR s) throw(); /* \\?\UNC\SERVER\share or \\SERVER\share or with slash */
|
||||
|
||||
bool IsDrivePath_SuperAllowed(CFSTR s) throw(); // first chars are drive chars like "a:\" or "\\?\a:\"
|
||||
bool IsDriveRootPath_SuperAllowed(CFSTR s) throw(); // exact drive root path "a:\" or "\\?\a:\"
|
||||
|
||||
bool IsDrivePath2(const wchar_t *s) throw(); // first 2 chars are drive chars like "a:"
|
||||
// bool IsDriveName2(const wchar_t *s) throw(); // is drive name like "a:"
|
||||
bool IsSuperPath(const wchar_t *s) throw();
|
||||
bool IsSuperOrDevicePath(const wchar_t *s) throw();
|
||||
|
||||
bool IsAltStreamPrefixWithColon(const UString &s) throw();
|
||||
// returns true, if super prefix was removed
|
||||
bool If_IsSuperPath_RemoveSuperPrefix(UString &s);
|
||||
|
||||
#ifndef USE_UNICODE_FSTRING
|
||||
bool IsDrivePath2(CFSTR s) throw(); // first 2 chars are drive chars like "a:"
|
||||
// bool IsDriveName2(CFSTR s) throw(); // is drive name like "a:"
|
||||
bool IsDrivePath(CFSTR s) throw();
|
||||
bool IsSuperPath(CFSTR s) throw();
|
||||
bool IsSuperOrDevicePath(CFSTR s) throw();
|
||||
|
||||
/* GetRootPrefixSize() returns size of ROOT PREFIX for cases:
|
||||
\
|
||||
\\.\
|
||||
C:\
|
||||
\\?\C:\
|
||||
\\?\UNC\SERVER\Shared\
|
||||
\\SERVER\Shared\
|
||||
in another cases it returns 0
|
||||
*/
|
||||
|
||||
unsigned GetRootPrefixSize(CFSTR s) throw();
|
||||
|
||||
#endif
|
||||
|
||||
int FindAltStreamColon(CFSTR path) throw();
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
bool IsAbsolutePath(const wchar_t *s) throw();
|
||||
unsigned GetRootPrefixSize(const wchar_t *s) throw();
|
||||
|
||||
#ifndef _WIN32
|
||||
/* GetRootPrefixSize_WINDOWS() is called in linux, but it parses path by windows rules.
|
||||
It supports only paths system (linux) slash separators (STRING_PATH_SEPARATOR),
|
||||
It doesn't parses paths with backslash (windows) separators.
|
||||
"c:/dir/file" is supported.
|
||||
*/
|
||||
unsigned GetRootPrefixSize_WINDOWS(const wchar_t *s) throw();
|
||||
#endif
|
||||
|
||||
#ifdef Z7_LONG_PATH
|
||||
|
||||
const int kSuperPathType_UseOnlyMain = 0;
|
||||
const int kSuperPathType_UseOnlySuper = 1;
|
||||
const int kSuperPathType_UseMainAndSuper = 2;
|
||||
|
||||
int GetUseSuperPathType(CFSTR s) throw();
|
||||
bool GetSuperPath(CFSTR path, UString &superPath, bool onlyIfNew);
|
||||
bool GetSuperPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2, bool onlyIfNew);
|
||||
|
||||
#define USE_MAIN_PATH (_useSuperPathType != kSuperPathType_UseOnlySuper)
|
||||
#define USE_MAIN_PATH_2 (_useSuperPathType1 != kSuperPathType_UseOnlySuper && _useSuperPathType2 != kSuperPathType_UseOnlySuper)
|
||||
|
||||
#define USE_SUPER_PATH (_useSuperPathType != kSuperPathType_UseOnlyMain)
|
||||
#define USE_SUPER_PATH_2 (_useSuperPathType1 != kSuperPathType_UseOnlyMain || _useSuperPathType2 != kSuperPathType_UseOnlyMain)
|
||||
|
||||
#define IF_USE_MAIN_PATH int _useSuperPathType = GetUseSuperPathType(path); if (USE_MAIN_PATH)
|
||||
#define IF_USE_MAIN_PATH_2(x1, x2) \
|
||||
int _useSuperPathType1 = GetUseSuperPathType(x1); \
|
||||
int _useSuperPathType2 = GetUseSuperPathType(x2); \
|
||||
if (USE_MAIN_PATH_2)
|
||||
|
||||
#else
|
||||
|
||||
#define IF_USE_MAIN_PATH
|
||||
#define IF_USE_MAIN_PATH_2(x1, x2)
|
||||
|
||||
#endif // Z7_LONG_PATH
|
||||
|
||||
/*
|
||||
if (dirPrefix != NULL && (path) is relative)
|
||||
{
|
||||
(dirPrefix) will be used
|
||||
result (fullPath) will contain prefix part of (dirPrefix).
|
||||
}
|
||||
Current_Dir path can be used in 2 cases:
|
||||
1) if (path) is relative && dirPrefix == NULL
|
||||
2) for _WIN32: if (path) is absolute starting wuth "\"
|
||||
*/
|
||||
bool GetFullPath(CFSTR dirPrefix, CFSTR path, FString &fullPath);
|
||||
bool GetFullPath(CFSTR path, FString &fullPath);
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,187 @@
|
||||
// Windows/FileSystem.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#ifndef UNDER_CE
|
||||
|
||||
#ifndef _UNICODE
|
||||
#include "../Common/StringConvert.h"
|
||||
#endif
|
||||
|
||||
#include "FileSystem.h"
|
||||
#include "Defs.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
|
||||
namespace NWindows {
|
||||
namespace NFile {
|
||||
namespace NSystem {
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
bool MyGetVolumeInformation(
|
||||
CFSTR rootPath,
|
||||
UString &volumeName,
|
||||
LPDWORD volumeSerialNumber,
|
||||
LPDWORD maximumComponentLength,
|
||||
LPDWORD fileSystemFlags,
|
||||
UString &fileSystemName)
|
||||
{
|
||||
BOOL res;
|
||||
#ifndef _UNICODE
|
||||
if (!g_IsNT)
|
||||
{
|
||||
TCHAR v[MAX_PATH + 2]; v[0] = 0;
|
||||
TCHAR f[MAX_PATH + 2]; f[0] = 0;
|
||||
res = GetVolumeInformation(fs2fas(rootPath),
|
||||
v, MAX_PATH,
|
||||
volumeSerialNumber, maximumComponentLength, fileSystemFlags,
|
||||
f, MAX_PATH);
|
||||
volumeName = MultiByteToUnicodeString(v);
|
||||
fileSystemName = MultiByteToUnicodeString(f);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
WCHAR v[MAX_PATH + 2]; v[0] = 0;
|
||||
WCHAR f[MAX_PATH + 2]; f[0] = 0;
|
||||
res = GetVolumeInformationW(fs2us(rootPath),
|
||||
v, MAX_PATH,
|
||||
volumeSerialNumber, maximumComponentLength, fileSystemFlags,
|
||||
f, MAX_PATH);
|
||||
volumeName = v;
|
||||
fileSystemName = f;
|
||||
}
|
||||
return BOOLToBool(res);
|
||||
}
|
||||
|
||||
UINT MyGetDriveType(CFSTR pathName)
|
||||
{
|
||||
#ifndef _UNICODE
|
||||
if (!g_IsNT)
|
||||
{
|
||||
return GetDriveType(fs2fas(pathName));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
return GetDriveTypeW(fs2us(pathName));
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0400
|
||||
// GetDiskFreeSpaceEx requires Windows95-OSR2, NT4
|
||||
#define Z7_USE_DYN_GetDiskFreeSpaceEx
|
||||
#endif
|
||||
|
||||
#ifdef Z7_USE_DYN_GetDiskFreeSpaceEx
|
||||
typedef BOOL (WINAPI * Func_GetDiskFreeSpaceExA)(
|
||||
LPCSTR lpDirectoryName, // directory name
|
||||
PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller
|
||||
PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk
|
||||
PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk
|
||||
);
|
||||
|
||||
typedef BOOL (WINAPI * Func_GetDiskFreeSpaceExW)(
|
||||
LPCWSTR lpDirectoryName, // directory name
|
||||
PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller
|
||||
PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk
|
||||
PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk
|
||||
);
|
||||
#endif
|
||||
|
||||
bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize)
|
||||
{
|
||||
DWORD numSectorsPerCluster, bytesPerSector, numFreeClusters, numClusters;
|
||||
bool sizeIsDetected = false;
|
||||
#ifndef _UNICODE
|
||||
if (!g_IsNT)
|
||||
{
|
||||
#ifdef Z7_USE_DYN_GetDiskFreeSpaceEx
|
||||
const
|
||||
Func_GetDiskFreeSpaceExA f = Z7_GET_PROC_ADDRESS(
|
||||
Func_GetDiskFreeSpaceExA, GetModuleHandle(TEXT("kernel32.dll")),
|
||||
"GetDiskFreeSpaceExA");
|
||||
if (f)
|
||||
#endif
|
||||
{
|
||||
ULARGE_INTEGER freeBytesToCaller2, totalSize2, freeSize2;
|
||||
sizeIsDetected = BOOLToBool(
|
||||
#ifdef Z7_USE_DYN_GetDiskFreeSpaceEx
|
||||
f
|
||||
#else
|
||||
GetDiskFreeSpaceExA
|
||||
#endif
|
||||
(fs2fas(rootPath), &freeBytesToCaller2, &totalSize2, &freeSize2));
|
||||
totalSize = totalSize2.QuadPart;
|
||||
freeSize = freeSize2.QuadPart;
|
||||
}
|
||||
if (!::GetDiskFreeSpace(fs2fas(rootPath), &numSectorsPerCluster, &bytesPerSector, &numFreeClusters, &numClusters))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef Z7_USE_DYN_GetDiskFreeSpaceEx
|
||||
const
|
||||
Func_GetDiskFreeSpaceExW f = Z7_GET_PROC_ADDRESS(
|
||||
Func_GetDiskFreeSpaceExW, GetModuleHandle(TEXT("kernel32.dll")),
|
||||
"GetDiskFreeSpaceExW");
|
||||
if (f)
|
||||
#endif
|
||||
{
|
||||
ULARGE_INTEGER freeBytesToCaller2, totalSize2, freeSize2;
|
||||
sizeIsDetected = BOOLToBool(
|
||||
#ifdef Z7_USE_DYN_GetDiskFreeSpaceEx
|
||||
f
|
||||
#else
|
||||
GetDiskFreeSpaceExW
|
||||
#endif
|
||||
(fs2us(rootPath), &freeBytesToCaller2, &totalSize2, &freeSize2));
|
||||
totalSize = totalSize2.QuadPart;
|
||||
freeSize = freeSize2.QuadPart;
|
||||
}
|
||||
if (!::GetDiskFreeSpaceW(fs2us(rootPath), &numSectorsPerCluster, &bytesPerSector, &numFreeClusters, &numClusters))
|
||||
return false;
|
||||
}
|
||||
clusterSize = (UInt64)bytesPerSector * (UInt64)numSectorsPerCluster;
|
||||
if (!sizeIsDetected)
|
||||
{
|
||||
totalSize = clusterSize * (UInt64)numClusters;
|
||||
freeSize = clusterSize * (UInt64)numFreeClusters;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
bool Is_File_LimitedBy_4GB(CFSTR _path, bool &isFsDetected)
|
||||
{
|
||||
isFsDetected = false;
|
||||
FString path (_path);
|
||||
path.DeleteFrom(NName::GetRootPrefixSize(path));
|
||||
// GetVolumeInformation supports super paths.
|
||||
// NName::If_IsSuperPath_RemoveSuperPrefix(path);
|
||||
if (!path.IsEmpty())
|
||||
{
|
||||
DWORD volumeSerialNumber, maximumComponentLength, fileSystemFlags;
|
||||
UString volName, fileSystemName;
|
||||
if (MyGetVolumeInformation(path, volName,
|
||||
&volumeSerialNumber, &maximumComponentLength, &fileSystemFlags,
|
||||
fileSystemName))
|
||||
{
|
||||
isFsDetected = true;
|
||||
if (fileSystemName.IsPrefixedBy_Ascii_NoCase("fat"))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
// Windows/FileSystem.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_FILE_SYSTEM_H
|
||||
#define ZIP7_INC_WINDOWS_FILE_SYSTEM_H
|
||||
|
||||
#include "../Common/MyString.h"
|
||||
#include "../Common/MyTypes.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NFile {
|
||||
namespace NSystem {
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
bool MyGetVolumeInformation(
|
||||
CFSTR rootPath ,
|
||||
UString &volumeName,
|
||||
LPDWORD volumeSerialNumber,
|
||||
LPDWORD maximumComponentLength,
|
||||
LPDWORD fileSystemFlags,
|
||||
UString &fileSystemName);
|
||||
|
||||
UINT MyGetDriveType(CFSTR pathName);
|
||||
|
||||
bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
|
||||
|
||||
#endif
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
// Windows/Handle.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_HANDLE_H
|
||||
#define ZIP7_INC_WINDOWS_HANDLE_H
|
||||
|
||||
#include "../Common/MyWindows.h"
|
||||
|
||||
namespace NWindows {
|
||||
|
||||
class CHandle MY_UNCOPYABLE
|
||||
{
|
||||
protected:
|
||||
HANDLE _handle;
|
||||
public:
|
||||
operator HANDLE() { return _handle; }
|
||||
CHandle(): _handle(NULL) {}
|
||||
~CHandle() { Close(); }
|
||||
bool IsCreated() const { return (_handle != NULL); }
|
||||
bool Close()
|
||||
{
|
||||
if (_handle == NULL)
|
||||
return true;
|
||||
if (!::CloseHandle(_handle))
|
||||
return false;
|
||||
_handle = NULL;
|
||||
return true;
|
||||
}
|
||||
void Attach(HANDLE handle) { _handle = handle; }
|
||||
HANDLE Detach()
|
||||
{
|
||||
const HANDLE handle = _handle;
|
||||
_handle = NULL;
|
||||
return handle;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
// Windows/MemoryGlobal.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "MemoryGlobal.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NMemory {
|
||||
|
||||
bool CGlobal::Alloc(UINT flags, SIZE_T size) throw()
|
||||
{
|
||||
HGLOBAL newBlock = ::GlobalAlloc(flags, size);
|
||||
if (newBlock == NULL)
|
||||
return false;
|
||||
_global = newBlock;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CGlobal::Free() throw()
|
||||
{
|
||||
if (_global == NULL)
|
||||
return true;
|
||||
_global = ::GlobalFree(_global);
|
||||
return (_global == NULL);
|
||||
}
|
||||
|
||||
bool CGlobal::ReAlloc(SIZE_T size) throw()
|
||||
{
|
||||
HGLOBAL newBlock = ::GlobalReAlloc(_global, size, GMEM_MOVEABLE);
|
||||
if (newBlock == NULL)
|
||||
return false;
|
||||
_global = newBlock;
|
||||
return true;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,55 @@
|
||||
// Windows/MemoryGlobal.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_MEMORY_GLOBAL_H
|
||||
#define ZIP7_INC_WINDOWS_MEMORY_GLOBAL_H
|
||||
|
||||
#include "../Common/MyWindows.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NMemory {
|
||||
|
||||
class CGlobal
|
||||
{
|
||||
HGLOBAL _global;
|
||||
public:
|
||||
CGlobal(): _global(NULL) {}
|
||||
~CGlobal() { Free(); }
|
||||
operator HGLOBAL() const { return _global; }
|
||||
void Attach(HGLOBAL hGlobal)
|
||||
{
|
||||
Free();
|
||||
_global = hGlobal;
|
||||
}
|
||||
HGLOBAL Detach()
|
||||
{
|
||||
const HGLOBAL h = _global;
|
||||
_global = NULL;
|
||||
return h;
|
||||
}
|
||||
bool Alloc(UINT flags, SIZE_T size) throw();
|
||||
bool Free() throw();
|
||||
LPVOID Lock() const { return GlobalLock(_global); }
|
||||
void Unlock() const { GlobalUnlock(_global); }
|
||||
bool ReAlloc(SIZE_T size) throw();
|
||||
};
|
||||
|
||||
class CGlobalLock
|
||||
{
|
||||
HGLOBAL _global;
|
||||
LPVOID _ptr;
|
||||
public:
|
||||
LPVOID GetPointer() const { return _ptr; }
|
||||
CGlobalLock(HGLOBAL hGlobal): _global(hGlobal)
|
||||
{
|
||||
_ptr = GlobalLock(hGlobal);
|
||||
}
|
||||
~CGlobalLock()
|
||||
{
|
||||
if (_ptr)
|
||||
GlobalUnlock(_global);
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,127 @@
|
||||
// Windows/MemoryLock.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../C/CpuArch.h"
|
||||
|
||||
#include "MemoryLock.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NSecurity {
|
||||
|
||||
#ifndef UNDER_CE
|
||||
|
||||
#ifdef _UNICODE
|
||||
#define MY_FUNC_SELECT(f) :: f
|
||||
#else
|
||||
#define MY_FUNC_SELECT(f) my_ ## f
|
||||
extern "C" {
|
||||
typedef BOOL (WINAPI * Func_OpenProcessToken)(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle);
|
||||
typedef BOOL (WINAPI * Func_LookupPrivilegeValue)(LPCTSTR lpSystemName, LPCTSTR lpName, PLUID lpLuid);
|
||||
typedef BOOL (WINAPI * Func_AdjustTokenPrivileges)(HANDLE TokenHandle, BOOL DisableAllPrivileges,
|
||||
PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength);
|
||||
}
|
||||
|
||||
#define GET_PROC_ADDR(fff, name) \
|
||||
const Func_ ## fff my_ ## fff = Z7_GET_PROC_ADDRESS( \
|
||||
Func_ ## fff, hModule, name);
|
||||
#endif
|
||||
|
||||
bool EnablePrivilege(LPCTSTR privilegeName, bool enable)
|
||||
{
|
||||
bool res = false;
|
||||
|
||||
#ifndef _UNICODE
|
||||
|
||||
const HMODULE hModule = ::LoadLibrary(TEXT("advapi32.dll"));
|
||||
if (!hModule)
|
||||
return false;
|
||||
|
||||
Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
|
||||
|
||||
GET_PROC_ADDR(
|
||||
OpenProcessToken,
|
||||
"OpenProcessToken")
|
||||
GET_PROC_ADDR(
|
||||
LookupPrivilegeValue,
|
||||
"LookupPrivilegeValueA")
|
||||
GET_PROC_ADDR(
|
||||
AdjustTokenPrivileges,
|
||||
"AdjustTokenPrivileges")
|
||||
|
||||
if (my_OpenProcessToken &&
|
||||
my_AdjustTokenPrivileges &&
|
||||
my_LookupPrivilegeValue)
|
||||
|
||||
#endif
|
||||
|
||||
{
|
||||
HANDLE token;
|
||||
if (MY_FUNC_SELECT(OpenProcessToken)(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
|
||||
{
|
||||
TOKEN_PRIVILEGES tp;
|
||||
if (MY_FUNC_SELECT(LookupPrivilegeValue)(NULL, privilegeName, &(tp.Privileges[0].Luid)))
|
||||
{
|
||||
tp.PrivilegeCount = 1;
|
||||
tp.Privileges[0].Attributes = (enable ? SE_PRIVILEGE_ENABLED : 0);
|
||||
if (MY_FUNC_SELECT(AdjustTokenPrivileges)(token, FALSE, &tp, 0, NULL, NULL))
|
||||
res = (GetLastError() == ERROR_SUCCESS);
|
||||
}
|
||||
::CloseHandle(token);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
|
||||
::FreeLibrary(hModule);
|
||||
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
|
||||
|
||||
typedef void (WINAPI * Func_RtlGetVersion) (OSVERSIONINFOEXW *);
|
||||
|
||||
/*
|
||||
We suppose that Window 10 works incorrectly with "Large Pages" at:
|
||||
- Windows 10 1703 (15063) : incorrect allocating after VirtualFree()
|
||||
- Windows 10 1709 (16299) : incorrect allocating after VirtualFree()
|
||||
- Windows 10 1809 (17763) : the failures for blocks of 1 GiB and larger,
|
||||
if CPU doesn't support 1 GB pages.
|
||||
Windows 10 1903 (18362) probably works correctly.
|
||||
*/
|
||||
|
||||
unsigned Get_LargePages_RiskLevel()
|
||||
{
|
||||
OSVERSIONINFOEXW vi;
|
||||
const HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll");
|
||||
if (!ntdll)
|
||||
return 0;
|
||||
const
|
||||
Func_RtlGetVersion func = Z7_GET_PROC_ADDRESS(
|
||||
Func_RtlGetVersion, ntdll,
|
||||
"RtlGetVersion");
|
||||
if (!func)
|
||||
return 0;
|
||||
func(&vi);
|
||||
if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT)
|
||||
return 0;
|
||||
if (vi.dwMajorVersion + vi.dwMinorVersion != 10)
|
||||
return 0;
|
||||
if (vi.dwBuildNumber <= 16299)
|
||||
return 1;
|
||||
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
if (vi.dwBuildNumber < 18362 && !CPU_IsSupported_PageGB())
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,40 @@
|
||||
// Windows/MemoryLock.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_MEMORY_LOCK_H
|
||||
#define ZIP7_INC_WINDOWS_MEMORY_LOCK_H
|
||||
|
||||
#include "../Common/MyWindows.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NSecurity {
|
||||
|
||||
#ifndef UNDER_CE
|
||||
|
||||
bool EnablePrivilege(LPCTSTR privilegeName, bool enable = true);
|
||||
|
||||
inline bool EnablePrivilege_LockMemory(bool enable = true)
|
||||
{
|
||||
return EnablePrivilege(SE_LOCK_MEMORY_NAME, enable);
|
||||
}
|
||||
|
||||
inline void EnablePrivilege_SymLink()
|
||||
{
|
||||
/* Probably we do not to set any Privilege for junction points.
|
||||
But we need them for Symbolic links */
|
||||
NSecurity::EnablePrivilege(SE_RESTORE_NAME);
|
||||
|
||||
/* Probably we need only SE_RESTORE_NAME, but there is also
|
||||
SE_CREATE_SYMBOLIC_LINK_NAME. So we set it also. Do we need it? */
|
||||
|
||||
NSecurity::EnablePrivilege(TEXT("SeCreateSymbolicLinkPrivilege")); // SE_CREATE_SYMBOLIC_LINK_NAME
|
||||
|
||||
// Do we need to set SE_BACKUP_NAME ?
|
||||
}
|
||||
|
||||
unsigned Get_LargePages_RiskLevel();
|
||||
|
||||
#endif
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,265 @@
|
||||
// Windows/Menu.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
#include "../Common/StringConvert.h"
|
||||
#endif
|
||||
#include "Menu.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
|
||||
namespace NWindows {
|
||||
|
||||
/*
|
||||
structures
|
||||
MENUITEMINFOA
|
||||
MENUITEMINFOW
|
||||
contain additional member:
|
||||
#if (WINVER >= 0x0500)
|
||||
HBITMAP hbmpItem;
|
||||
#endif
|
||||
If we compile the source code with (WINVER >= 0x0500), some functions
|
||||
will not work at NT4, if cbSize is set as sizeof(MENUITEMINFO).
|
||||
So we use size of old version of structure in some conditions.
|
||||
Win98 probably supports full structure including hbmpItem.
|
||||
|
||||
We have 2 ways to get/set string in menu item:
|
||||
win95/NT4: we must use MIIM_TYPE only.
|
||||
MIIM_TYPE : Retrieves or sets the fType and dwTypeData members.
|
||||
win98/win2000: there are new flags that can be used instead of MIIM_TYPE:
|
||||
MIIM_FTYPE : Retrieves or sets the fType member.
|
||||
MIIM_STRING : Retrieves or sets the dwTypeData member.
|
||||
|
||||
Windows versions probably support MIIM_TYPE flag, if we set MENUITEMINFO::cbSize
|
||||
as sizeof of old (small) MENUITEMINFO that doesn't include (hbmpItem) field.
|
||||
But do all Windows versions support old MIIM_TYPE flag, if we use
|
||||
MENUITEMINFO::cbSize as sizeof of new (big) MENUITEMINFO including (hbmpItem) field ?
|
||||
win10 probably supports any combination of small/big (cbSize) and old/new MIIM_TYPE/MIIM_STRING.
|
||||
*/
|
||||
|
||||
#if defined(UNDER_CE) || defined(_WIN64) || (WINVER < 0x0500)
|
||||
#ifndef _UNICODE
|
||||
#define my_compatib_MENUITEMINFOA_size sizeof(MENUITEMINFOA)
|
||||
#endif
|
||||
#define my_compatib_MENUITEMINFOW_size sizeof(MENUITEMINFOW)
|
||||
#else
|
||||
#define MY_STRUCT_SIZE_BEFORE(structname, member) ((UINT)(UINT_PTR)((LPBYTE)(&((structname*)0)->member) - (LPBYTE)(structname*)0))
|
||||
#ifndef _UNICODE
|
||||
#define my_compatib_MENUITEMINFOA_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOA, hbmpItem)
|
||||
#endif
|
||||
#define my_compatib_MENUITEMINFOW_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOW, hbmpItem)
|
||||
#if defined(__clang__) && __clang_major__ >= 13
|
||||
// error : performing pointer subtraction with a null pointer may have undefined behavior
|
||||
#pragma GCC diagnostic ignored "-Wnull-pointer-subtraction"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#define COPY_MENUITEM_field(d, s, name) \
|
||||
d.name = s.name;
|
||||
|
||||
#define COPY_MENUITEM_fields(d, s) \
|
||||
COPY_MENUITEM_field(d, s, fMask) \
|
||||
COPY_MENUITEM_field(d, s, fType) \
|
||||
COPY_MENUITEM_field(d, s, fState) \
|
||||
COPY_MENUITEM_field(d, s, wID) \
|
||||
COPY_MENUITEM_field(d, s, hSubMenu) \
|
||||
COPY_MENUITEM_field(d, s, hbmpChecked) \
|
||||
COPY_MENUITEM_field(d, s, hbmpUnchecked) \
|
||||
COPY_MENUITEM_field(d, s, dwItemData) \
|
||||
|
||||
static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOW &si)
|
||||
{
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.cbSize = my_compatib_MENUITEMINFOW_size; // sizeof(si);
|
||||
COPY_MENUITEM_fields(si, item)
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOA &si)
|
||||
{
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.cbSize = my_compatib_MENUITEMINFOA_size; // sizeof(si);
|
||||
COPY_MENUITEM_fields(si, item)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ConvertItemToMyForm(const MENUITEMINFOW &si, CMenuItem &item)
|
||||
{
|
||||
COPY_MENUITEM_fields(item, si)
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
static void ConvertItemToMyForm(const MENUITEMINFOA &si, CMenuItem &item)
|
||||
{
|
||||
COPY_MENUITEM_fields(item, si)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool CMenu::GetItem(UINT itemIndex, bool byPosition, CMenuItem &item) const
|
||||
{
|
||||
item.StringValue.Empty();
|
||||
const unsigned kMaxSize = 512;
|
||||
#ifndef _UNICODE
|
||||
if (!g_IsNT)
|
||||
{
|
||||
MENUITEMINFOA si;
|
||||
ConvertItemToSysForm(item, si);
|
||||
const bool isString = item.IsString();
|
||||
unsigned bufSize = kMaxSize;
|
||||
AString a;
|
||||
if (isString)
|
||||
{
|
||||
si.cch = bufSize;
|
||||
si.dwTypeData = a.GetBuf(bufSize);
|
||||
}
|
||||
bool res = GetItemInfo(itemIndex, byPosition, &si);
|
||||
if (isString)
|
||||
a.ReleaseBuf_CalcLen(bufSize);
|
||||
if (!res)
|
||||
return false;
|
||||
{
|
||||
if (isString && si.cch >= bufSize - 1)
|
||||
{
|
||||
si.dwTypeData = NULL;
|
||||
res = GetItemInfo(itemIndex, byPosition, &si);
|
||||
if (!res)
|
||||
return false;
|
||||
si.cch++;
|
||||
bufSize = si.cch;
|
||||
si.dwTypeData = a.GetBuf(bufSize);
|
||||
res = GetItemInfo(itemIndex, byPosition, &si);
|
||||
a.ReleaseBuf_CalcLen(bufSize);
|
||||
if (!res)
|
||||
return false;
|
||||
}
|
||||
ConvertItemToMyForm(si, item);
|
||||
if (isString)
|
||||
item.StringValue = GetUnicodeString(a);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
wchar_t s[kMaxSize + 1];
|
||||
s[0] = 0;
|
||||
MENUITEMINFOW si;
|
||||
ConvertItemToSysForm(item, si);
|
||||
const bool isString = item.IsString();
|
||||
unsigned bufSize = kMaxSize;
|
||||
if (isString)
|
||||
{
|
||||
si.cch = bufSize;
|
||||
si.dwTypeData = s;
|
||||
}
|
||||
bool res = GetItemInfo(itemIndex, byPosition, &si);
|
||||
if (!res)
|
||||
return false;
|
||||
if (isString)
|
||||
{
|
||||
s[Z7_ARRAY_SIZE(s) - 1] = 0;
|
||||
item.StringValue = s;
|
||||
if (si.cch >= bufSize - 1)
|
||||
{
|
||||
si.dwTypeData = NULL;
|
||||
res = GetItemInfo(itemIndex, byPosition, &si);
|
||||
if (!res)
|
||||
return false;
|
||||
si.cch++;
|
||||
bufSize = si.cch;
|
||||
si.dwTypeData = item.StringValue.GetBuf(bufSize);
|
||||
res = GetItemInfo(itemIndex, byPosition, &si);
|
||||
item.StringValue.ReleaseBuf_CalcLen(bufSize);
|
||||
if (!res)
|
||||
return false;
|
||||
}
|
||||
// if (item.StringValue.Len() != si.cch) throw 123; // for debug
|
||||
}
|
||||
ConvertItemToMyForm(si, item);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CMenu::SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item)
|
||||
{
|
||||
#ifndef _UNICODE
|
||||
if (!g_IsNT)
|
||||
{
|
||||
MENUITEMINFOA si;
|
||||
ConvertItemToSysForm(item, si);
|
||||
AString s;
|
||||
if (item.IsString())
|
||||
{
|
||||
s = GetSystemString(item.StringValue);
|
||||
si.dwTypeData = s.Ptr_non_const();
|
||||
}
|
||||
return SetItemInfo(itemIndex, byPosition, &si);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
MENUITEMINFOW si;
|
||||
ConvertItemToSysForm(item, si);
|
||||
if (item.IsString())
|
||||
si.dwTypeData = item.StringValue.Ptr_non_const();
|
||||
return SetItemInfo(itemIndex, byPosition, &si);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CMenu::InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item)
|
||||
{
|
||||
#ifndef _UNICODE
|
||||
if (!g_IsNT)
|
||||
{
|
||||
MENUITEMINFOA si;
|
||||
ConvertItemToSysForm(item, si);
|
||||
AString s;
|
||||
if (item.IsString())
|
||||
{
|
||||
s = GetSystemString(item.StringValue);
|
||||
si.dwTypeData = s.Ptr_non_const();
|
||||
}
|
||||
return InsertItem(itemIndex, byPosition, &si);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
MENUITEMINFOW si;
|
||||
ConvertItemToSysForm(item, si);
|
||||
if (item.IsString())
|
||||
si.dwTypeData = item.StringValue.Ptr_non_const();
|
||||
#ifdef UNDER_CE
|
||||
UINT flags = (item.fType & MFT_SEPARATOR) ? MF_SEPARATOR : MF_STRING;
|
||||
UINT_PTR id = item.wID;
|
||||
if ((item.fMask & MIIM_SUBMENU) != 0)
|
||||
{
|
||||
flags |= MF_POPUP;
|
||||
id = (UINT_PTR)item.hSubMenu;
|
||||
}
|
||||
if (!Insert(itemIndex, flags | (byPosition ? MF_BYPOSITION : MF_BYCOMMAND), id, item.StringValue))
|
||||
return false;
|
||||
return SetItemInfo(itemIndex, byPosition, &si);
|
||||
#else
|
||||
return InsertItem(itemIndex, byPosition, &si);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
bool CMenu::AppendItem(UINT flags, UINT_PTR newItemID, LPCWSTR newItem)
|
||||
{
|
||||
if (g_IsNT)
|
||||
return BOOLToBool(::AppendMenuW(_menu, flags, newItemID, newItem));
|
||||
else
|
||||
return AppendItem(flags, newItemID, GetSystemString(newItem));
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
// Windows/Menu.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_MENU_H
|
||||
#define ZIP7_INC_WINDOWS_MENU_H
|
||||
|
||||
#include "../Common/MyWindows.h"
|
||||
#include "../Common/MyString.h"
|
||||
|
||||
#include "Defs.h"
|
||||
|
||||
namespace NWindows {
|
||||
|
||||
#ifndef MIIM_STRING
|
||||
#define MIIM_STRING 0x00000040
|
||||
#endif
|
||||
/*
|
||||
#ifndef MIIM_BITMAP
|
||||
#define MIIM_BITMAP 0x00000080
|
||||
#endif
|
||||
*/
|
||||
#ifndef MIIM_FTYPE
|
||||
#define MIIM_FTYPE 0x00000100
|
||||
#endif
|
||||
|
||||
struct CMenuItem
|
||||
{
|
||||
UString StringValue;
|
||||
UINT fMask;
|
||||
UINT fType;
|
||||
UINT fState;
|
||||
UINT wID;
|
||||
HMENU hSubMenu;
|
||||
HBITMAP hbmpChecked;
|
||||
HBITMAP hbmpUnchecked;
|
||||
ULONG_PTR dwItemData;
|
||||
// LPTSTR dwTypeData;
|
||||
// UINT cch;
|
||||
// HBITMAP hbmpItem;
|
||||
bool IsString() const { return (fMask & (MIIM_TYPE | MIIM_STRING)) != 0; }
|
||||
bool IsSeparator() const { return (fType == MFT_SEPARATOR); }
|
||||
CMenuItem(): fMask(0), fType(0), fState(0), wID(0),
|
||||
hSubMenu(NULL), hbmpChecked(NULL), hbmpUnchecked(NULL), dwItemData(0) {}
|
||||
};
|
||||
|
||||
class CMenu
|
||||
{
|
||||
HMENU _menu;
|
||||
public:
|
||||
CMenu(): _menu(NULL) {}
|
||||
operator HMENU() const { return _menu; }
|
||||
void Attach(HMENU menu) { _menu = menu; }
|
||||
|
||||
HMENU Detach()
|
||||
{
|
||||
const HMENU menu = _menu;
|
||||
_menu = NULL;
|
||||
return menu;
|
||||
}
|
||||
|
||||
bool Create()
|
||||
{
|
||||
_menu = ::CreateMenu();
|
||||
return (_menu != NULL);
|
||||
}
|
||||
|
||||
bool CreatePopup()
|
||||
{
|
||||
_menu = ::CreatePopupMenu();
|
||||
return (_menu != NULL);
|
||||
}
|
||||
|
||||
bool Destroy()
|
||||
{
|
||||
if (!_menu)
|
||||
return false;
|
||||
return BOOLToBool(::DestroyMenu(Detach()));
|
||||
}
|
||||
|
||||
int GetItemCount() const
|
||||
{
|
||||
#ifdef UNDER_CE
|
||||
for (unsigned i = 0;; i++)
|
||||
{
|
||||
CMenuItem item;
|
||||
item.fMask = MIIM_STATE;
|
||||
if (!GetItem(i, true, item))
|
||||
return (int)i;
|
||||
}
|
||||
#else
|
||||
return GetMenuItemCount(_menu);
|
||||
#endif
|
||||
}
|
||||
|
||||
HMENU GetSubMenu(int pos) const { return ::GetSubMenu(_menu, pos); }
|
||||
#ifndef UNDER_CE
|
||||
/*
|
||||
bool GetItemString(UINT idItem, UINT flag, CSysString &result)
|
||||
{
|
||||
result.Empty();
|
||||
int len = ::GetMenuString(_menu, idItem, 0, 0, flag);
|
||||
int len2 = ::GetMenuString(_menu, idItem, result.GetBuf(len + 2), len + 1, flag);
|
||||
if (len > len2)
|
||||
len = len2;
|
||||
result.ReleaseBuf_CalcLen(len + 2);
|
||||
return (len != 0);
|
||||
}
|
||||
*/
|
||||
UINT GetItemID(int pos) const { return ::GetMenuItemID(_menu, pos); }
|
||||
UINT GetItemState(UINT id, UINT flags) const { return ::GetMenuState(_menu, id, flags); }
|
||||
#endif
|
||||
|
||||
bool GetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFO itemInfo) const
|
||||
{ return BOOLToBool(::GetMenuItemInfo(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); }
|
||||
bool SetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFO itemInfo)
|
||||
{ return BOOLToBool(::SetMenuItemInfo(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); }
|
||||
|
||||
bool AppendItem(UINT flags, UINT_PTR newItemID, LPCTSTR newItem)
|
||||
{ return BOOLToBool(::AppendMenu(_menu, flags, newItemID, newItem)); }
|
||||
|
||||
bool Insert(UINT position, UINT flags, UINT_PTR idNewItem, LPCTSTR newItem)
|
||||
{ return BOOLToBool(::InsertMenu(_menu, position, flags, idNewItem, newItem)); }
|
||||
|
||||
#ifndef UNDER_CE
|
||||
bool InsertItem(UINT itemIndex, bool byPosition, LPCMENUITEMINFO itemInfo)
|
||||
{ return BOOLToBool(::InsertMenuItem(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); }
|
||||
#endif
|
||||
|
||||
bool RemoveItem(UINT item, UINT flags) { return BOOLToBool(::RemoveMenu(_menu, item, flags)); }
|
||||
void RemoveAllItemsFrom(UINT index) { while (RemoveItem(index, MF_BYPOSITION)); }
|
||||
void RemoveAllItems() { RemoveAllItemsFrom(0); }
|
||||
|
||||
#ifndef _UNICODE
|
||||
bool GetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo) const
|
||||
{ return BOOLToBool(::GetMenuItemInfoW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); }
|
||||
bool InsertItem(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo)
|
||||
{ return BOOLToBool(::InsertMenuItemW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); }
|
||||
bool SetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo)
|
||||
{ return BOOLToBool(::SetMenuItemInfoW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); }
|
||||
bool AppendItem(UINT flags, UINT_PTR newItemID, LPCWSTR newItem);
|
||||
#endif
|
||||
|
||||
bool GetItem(UINT itemIndex, bool byPosition, CMenuItem &item) const;
|
||||
bool SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item);
|
||||
bool InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item);
|
||||
|
||||
int Track(UINT flags, int x, int y, HWND hWnd) { return ::TrackPopupMenuEx(_menu, flags, x, y, hWnd, NULL); }
|
||||
|
||||
bool CheckRadioItem(UINT idFirst, UINT idLast, UINT idCheck, UINT flags)
|
||||
{ return BOOLToBool(::CheckMenuRadioItem(_menu, idFirst, idLast, idCheck, flags)); }
|
||||
|
||||
DWORD CheckItem(UINT id, UINT uCheck) { return ::CheckMenuItem(_menu, id, uCheck); }
|
||||
DWORD CheckItemByID(UINT id, bool check) { return CheckItem(id, MF_BYCOMMAND | (check ? MF_CHECKED : MF_UNCHECKED)); }
|
||||
|
||||
BOOL EnableItem(UINT uIDEnableItem, UINT uEnable) { return EnableMenuItem(_menu, uIDEnableItem, uEnable); }
|
||||
};
|
||||
|
||||
class CMenuDestroyer
|
||||
{
|
||||
CMenu *_menu;
|
||||
public:
|
||||
CMenuDestroyer(CMenu &menu): _menu(&menu) {}
|
||||
CMenuDestroyer(): _menu(NULL) {}
|
||||
~CMenuDestroyer() { if (_menu) _menu->Destroy(); }
|
||||
void Attach(CMenu &menu) { _menu = &menu; }
|
||||
void Disable() { _menu = NULL; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
// Windows/NationalTime.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "NationalTime.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NNational {
|
||||
namespace NTime {
|
||||
|
||||
bool MyGetTimeFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time,
|
||||
LPCTSTR format, CSysString &resultString)
|
||||
{
|
||||
resultString.Empty();
|
||||
int numChars = ::GetTimeFormat(locale, flags, time, format, NULL, 0);
|
||||
if (numChars == 0)
|
||||
return false;
|
||||
numChars = ::GetTimeFormat(locale, flags, time, format,
|
||||
resultString.GetBuf((unsigned)numChars), numChars + 1);
|
||||
resultString.ReleaseBuf_CalcLen((unsigned)numChars);
|
||||
return (numChars != 0);
|
||||
}
|
||||
|
||||
bool MyGetDateFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time,
|
||||
LPCTSTR format, CSysString &resultString)
|
||||
{
|
||||
resultString.Empty();
|
||||
int numChars = ::GetDateFormat(locale, flags, time, format, NULL, 0);
|
||||
if (numChars == 0)
|
||||
return false;
|
||||
numChars = ::GetDateFormat(locale, flags, time, format,
|
||||
resultString.GetBuf((unsigned)numChars), numChars + 1);
|
||||
resultString.ReleaseBuf_CalcLen((unsigned)numChars);
|
||||
return (numChars != 0);
|
||||
}
|
||||
|
||||
}}}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Windows/NationalTime.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_NATIONAL_TIME_H
|
||||
#define ZIP7_INC_WINDOWS_NATIONAL_TIME_H
|
||||
|
||||
#include "../Common/MyString.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NNational {
|
||||
namespace NTime {
|
||||
|
||||
bool MyGetTimeFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time,
|
||||
LPCTSTR format, CSysString &resultString);
|
||||
|
||||
bool MyGetDateFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time,
|
||||
LPCTSTR format, CSysString &resultString);
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,398 @@
|
||||
// Windows/Net.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/MyBuffer.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
#include "../Common/StringConvert.h"
|
||||
#endif
|
||||
|
||||
#include "Net.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#if !defined(WNetGetResourceParent)
|
||||
// #if defined(Z7_OLD_WIN_SDK)
|
||||
// #if (WINVER >= 0x0400)
|
||||
DWORD APIENTRY WNetGetResourceParentA(IN LPNETRESOURCEA lpNetResource,
|
||||
OUT LPVOID lpBuffer, IN OUT LPDWORD lpcbBuffer);
|
||||
DWORD APIENTRY WNetGetResourceParentW(IN LPNETRESOURCEW lpNetResource,
|
||||
OUT LPVOID lpBuffer, IN OUT LPDWORD lpcbBuffer);
|
||||
#ifdef UNICODE
|
||||
#define WNetGetResourceParent WNetGetResourceParentW
|
||||
#else
|
||||
#define WNetGetResourceParent WNetGetResourceParentA
|
||||
#endif
|
||||
|
||||
DWORD APIENTRY WNetGetResourceInformationA(IN LPNETRESOURCEA lpNetResource,
|
||||
OUT LPVOID lpBuffer, IN OUT LPDWORD lpcbBuffer, OUT LPSTR *lplpSystem);
|
||||
DWORD APIENTRY WNetGetResourceInformationW(IN LPNETRESOURCEW lpNetResource,
|
||||
OUT LPVOID lpBuffer, IN OUT LPDWORD lpcbBuffer, OUT LPWSTR *lplpSystem);
|
||||
#ifdef UNICODE
|
||||
#define WNetGetResourceInformation WNetGetResourceInformationW
|
||||
#else
|
||||
#define WNetGetResourceInformation WNetGetResourceInformationA
|
||||
#endif
|
||||
// #endif // (WINVER >= 0x0400)
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace NWindows {
|
||||
namespace NNet {
|
||||
|
||||
DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCE netResource)
|
||||
{
|
||||
Close();
|
||||
const DWORD result = ::WNetOpenEnum(scope, type, usage, netResource, &_handle);
|
||||
_handleAllocated = (result == NO_ERROR);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCEW netResource)
|
||||
{
|
||||
Close();
|
||||
const DWORD result = ::WNetOpenEnumW(scope, type, usage, netResource, &_handle);
|
||||
_handleAllocated = (result == NO_ERROR);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void SetComplexString(bool &defined, CSysString &destString, LPCTSTR srcString)
|
||||
{
|
||||
defined = (srcString != NULL);
|
||||
if (defined)
|
||||
destString = srcString;
|
||||
else
|
||||
destString.Empty();
|
||||
}
|
||||
|
||||
static void ConvertNETRESOURCEToCResource(const NETRESOURCE &netResource, CResource &resource)
|
||||
{
|
||||
resource.Scope = netResource.dwScope;
|
||||
resource.Type = netResource.dwType;
|
||||
resource.DisplayType = netResource.dwDisplayType;
|
||||
resource.Usage = netResource.dwUsage;
|
||||
SetComplexString(resource.LocalNameIsDefined, resource.LocalName, netResource.lpLocalName);
|
||||
SetComplexString(resource.RemoteNameIsDefined, resource.RemoteName, netResource.lpRemoteName);
|
||||
SetComplexString(resource.CommentIsDefined, resource.Comment, netResource.lpComment);
|
||||
SetComplexString(resource.ProviderIsDefined, resource.Provider, netResource.lpProvider);
|
||||
}
|
||||
|
||||
static void SetComplexString2(LPTSTR *destString, bool defined, const CSysString &srcString)
|
||||
{
|
||||
if (defined)
|
||||
*destString = srcString.Ptr_non_const();
|
||||
else
|
||||
*destString = NULL;
|
||||
}
|
||||
|
||||
static void ConvertCResourceToNETRESOURCE(const CResource &resource, NETRESOURCE &netResource)
|
||||
{
|
||||
netResource.dwScope = resource.Scope;
|
||||
netResource.dwType = resource.Type;
|
||||
netResource.dwDisplayType = resource.DisplayType;
|
||||
netResource.dwUsage = resource.Usage;
|
||||
SetComplexString2(&netResource.lpLocalName, resource.LocalNameIsDefined, resource.LocalName);
|
||||
SetComplexString2(&netResource.lpRemoteName, resource.RemoteNameIsDefined, resource.RemoteName);
|
||||
SetComplexString2(&netResource.lpComment, resource.CommentIsDefined, resource.Comment);
|
||||
SetComplexString2(&netResource.lpProvider, resource.ProviderIsDefined, resource.Provider);
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
|
||||
static void SetComplexString(bool &defined, UString &destString, LPCWSTR src)
|
||||
{
|
||||
defined = (src != NULL);
|
||||
if (defined)
|
||||
destString = src;
|
||||
else
|
||||
destString.Empty();
|
||||
}
|
||||
|
||||
static void ConvertNETRESOURCEToCResource(const NETRESOURCEW &netResource, CResourceW &resource)
|
||||
{
|
||||
resource.Scope = netResource.dwScope;
|
||||
resource.Type = netResource.dwType;
|
||||
resource.DisplayType = netResource.dwDisplayType;
|
||||
resource.Usage = netResource.dwUsage;
|
||||
SetComplexString(resource.LocalNameIsDefined, resource.LocalName, netResource.lpLocalName);
|
||||
SetComplexString(resource.RemoteNameIsDefined, resource.RemoteName, netResource.lpRemoteName);
|
||||
SetComplexString(resource.CommentIsDefined, resource.Comment, netResource.lpComment);
|
||||
SetComplexString(resource.ProviderIsDefined, resource.Provider, netResource.lpProvider);
|
||||
}
|
||||
|
||||
static void SetComplexString2(LPWSTR *destString, bool defined, const UString &srcString)
|
||||
{
|
||||
if (defined)
|
||||
*destString = srcString.Ptr_non_const();
|
||||
else
|
||||
*destString = NULL;
|
||||
}
|
||||
|
||||
static void ConvertCResourceToNETRESOURCE(const CResourceW &resource, NETRESOURCEW &netResource)
|
||||
{
|
||||
netResource.dwScope = resource.Scope;
|
||||
netResource.dwType = resource.Type;
|
||||
netResource.dwDisplayType = resource.DisplayType;
|
||||
netResource.dwUsage = resource.Usage;
|
||||
SetComplexString2(&netResource.lpLocalName, resource.LocalNameIsDefined, resource.LocalName);
|
||||
SetComplexString2(&netResource.lpRemoteName, resource.RemoteNameIsDefined, resource.RemoteName);
|
||||
SetComplexString2(&netResource.lpComment, resource.CommentIsDefined, resource.Comment);
|
||||
SetComplexString2(&netResource.lpProvider, resource.ProviderIsDefined, resource.Provider);
|
||||
}
|
||||
|
||||
static void ConvertResourceWToResource(const CResourceW &resourceW, CResource &resource)
|
||||
{
|
||||
*(CResourceBase *)&resource = *(CResourceBase *)&resourceW;
|
||||
resource.LocalName = GetSystemString(resourceW.LocalName);
|
||||
resource.RemoteName = GetSystemString(resourceW.RemoteName);
|
||||
resource.Comment = GetSystemString(resourceW.Comment);
|
||||
resource.Provider = GetSystemString(resourceW.Provider);
|
||||
}
|
||||
|
||||
static void ConvertResourceToResourceW(const CResource &resource, CResourceW &resourceW)
|
||||
{
|
||||
*(CResourceBase *)&resourceW = *(CResourceBase *)&resource;
|
||||
resourceW.LocalName = GetUnicodeString(resource.LocalName);
|
||||
resourceW.RemoteName = GetUnicodeString(resource.RemoteName);
|
||||
resourceW.Comment = GetUnicodeString(resource.Comment);
|
||||
resourceW.Provider = GetUnicodeString(resource.Provider);
|
||||
}
|
||||
#endif
|
||||
|
||||
DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, const CResource *resource)
|
||||
{
|
||||
NETRESOURCE netResource;
|
||||
LPNETRESOURCE pointer = NULL;
|
||||
if (resource)
|
||||
{
|
||||
ConvertCResourceToNETRESOURCE(*resource, netResource);
|
||||
pointer = &netResource;
|
||||
}
|
||||
return Open(scope, type, usage, pointer);
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, const CResourceW *resource)
|
||||
{
|
||||
if (g_IsNT)
|
||||
{
|
||||
NETRESOURCEW netResource;
|
||||
LPNETRESOURCEW pointer = NULL;
|
||||
if (resource)
|
||||
{
|
||||
ConvertCResourceToNETRESOURCE(*resource, netResource);
|
||||
pointer = &netResource;
|
||||
}
|
||||
return Open(scope, type, usage, pointer);
|
||||
}
|
||||
CResource resourceA;
|
||||
CResource *pointer = NULL;
|
||||
if (resource)
|
||||
{
|
||||
ConvertResourceWToResource(*resource, resourceA);
|
||||
pointer = &resourceA;
|
||||
}
|
||||
return Open(scope, type, usage, pointer);
|
||||
}
|
||||
#endif
|
||||
|
||||
DWORD CEnum::Close()
|
||||
{
|
||||
if (!_handleAllocated)
|
||||
return NO_ERROR;
|
||||
const DWORD result = ::WNetCloseEnum(_handle);
|
||||
_handleAllocated = (result != NO_ERROR);
|
||||
return result;
|
||||
}
|
||||
|
||||
DWORD CEnum::Next(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
|
||||
{
|
||||
return ::WNetEnumResource(_handle, lpcCount, lpBuffer, lpBufferSize);
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
DWORD CEnum::NextW(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
|
||||
{
|
||||
return ::WNetEnumResourceW(_handle, lpcCount, lpBuffer, lpBufferSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
DWORD CEnum::Next(CResource &resource)
|
||||
{
|
||||
const DWORD kBufferSize = 16384;
|
||||
CByteArr byteBuffer(kBufferSize);
|
||||
LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (void *) (BYTE *)(byteBuffer);
|
||||
ZeroMemory(lpnrLocal, kBufferSize);
|
||||
DWORD bufferSize = kBufferSize;
|
||||
DWORD numEntries = 1;
|
||||
const DWORD result = Next(&numEntries, lpnrLocal, &bufferSize);
|
||||
if (result != NO_ERROR)
|
||||
return result;
|
||||
if (numEntries != 1)
|
||||
return (DWORD)E_FAIL;
|
||||
ConvertNETRESOURCEToCResource(lpnrLocal[0], resource);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
DWORD CEnum::Next(CResourceW &resource)
|
||||
{
|
||||
if (g_IsNT)
|
||||
{
|
||||
const DWORD kBufferSize = 16384;
|
||||
CByteArr byteBuffer(kBufferSize);
|
||||
LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (void *) (BYTE *)(byteBuffer);
|
||||
ZeroMemory(lpnrLocal, kBufferSize);
|
||||
DWORD bufferSize = kBufferSize;
|
||||
DWORD numEntries = 1;
|
||||
const DWORD result = NextW(&numEntries, lpnrLocal, &bufferSize);
|
||||
if (result != NO_ERROR)
|
||||
return result;
|
||||
if (numEntries != 1)
|
||||
return (DWORD)E_FAIL;
|
||||
ConvertNETRESOURCEToCResource(lpnrLocal[0], resource);
|
||||
return result;
|
||||
}
|
||||
CResource resourceA;
|
||||
const DWORD result = Next(resourceA);
|
||||
ConvertResourceToResourceW(resourceA, resource);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
DWORD GetResourceParent(const CResource &resource, CResource &parentResource)
|
||||
{
|
||||
const DWORD kBufferSize = 16384;
|
||||
CByteArr byteBuffer(kBufferSize);
|
||||
LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (void *) (BYTE *)(byteBuffer);
|
||||
ZeroMemory(lpnrLocal, kBufferSize);
|
||||
DWORD bufferSize = kBufferSize;
|
||||
NETRESOURCE netResource;
|
||||
ConvertCResourceToNETRESOURCE(resource, netResource);
|
||||
const DWORD result = ::WNetGetResourceParent(&netResource, lpnrLocal, &bufferSize);
|
||||
if (result != NO_ERROR)
|
||||
return result;
|
||||
ConvertNETRESOURCEToCResource(lpnrLocal[0], parentResource);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
DWORD GetResourceParent(const CResourceW &resource, CResourceW &parentResource)
|
||||
{
|
||||
if (g_IsNT)
|
||||
{
|
||||
const DWORD kBufferSize = 16384;
|
||||
CByteArr byteBuffer(kBufferSize);
|
||||
LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (void *) (BYTE *)(byteBuffer);
|
||||
ZeroMemory(lpnrLocal, kBufferSize);
|
||||
DWORD bufferSize = kBufferSize;
|
||||
NETRESOURCEW netResource;
|
||||
ConvertCResourceToNETRESOURCE(resource, netResource);
|
||||
const DWORD result = ::WNetGetResourceParentW(&netResource, lpnrLocal, &bufferSize);
|
||||
if (result != NO_ERROR)
|
||||
return result;
|
||||
ConvertNETRESOURCEToCResource(lpnrLocal[0], parentResource);
|
||||
return result;
|
||||
}
|
||||
CResource resourceA, parentResourceA;
|
||||
ConvertResourceWToResource(resource, resourceA);
|
||||
const DWORD result = GetResourceParent(resourceA, parentResourceA);
|
||||
ConvertResourceToResourceW(parentResourceA, parentResource);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
DWORD GetResourceInformation(const CResource &resource,
|
||||
CResource &destResource, CSysString &systemPathPart)
|
||||
{
|
||||
const DWORD kBufferSize = 16384;
|
||||
CByteArr byteBuffer(kBufferSize);
|
||||
LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (void *) (BYTE *)(byteBuffer);
|
||||
ZeroMemory(lpnrLocal, kBufferSize);
|
||||
DWORD bufferSize = kBufferSize;
|
||||
NETRESOURCE netResource;
|
||||
ConvertCResourceToNETRESOURCE(resource, netResource);
|
||||
LPTSTR lplpSystem;
|
||||
const DWORD result = ::WNetGetResourceInformation(&netResource,
|
||||
lpnrLocal, &bufferSize, &lplpSystem);
|
||||
if (result != NO_ERROR)
|
||||
return result;
|
||||
if (lplpSystem != NULL)
|
||||
systemPathPart = lplpSystem;
|
||||
ConvertNETRESOURCEToCResource(lpnrLocal[0], destResource);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
DWORD GetResourceInformation(const CResourceW &resource,
|
||||
CResourceW &destResource, UString &systemPathPart)
|
||||
{
|
||||
if (g_IsNT)
|
||||
{
|
||||
const DWORD kBufferSize = 16384;
|
||||
CByteArr byteBuffer(kBufferSize);
|
||||
LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (void *) (BYTE *)(byteBuffer);
|
||||
ZeroMemory(lpnrLocal, kBufferSize);
|
||||
DWORD bufferSize = kBufferSize;
|
||||
NETRESOURCEW netResource;
|
||||
ConvertCResourceToNETRESOURCE(resource, netResource);
|
||||
LPWSTR lplpSystem;
|
||||
const DWORD result = ::WNetGetResourceInformationW(&netResource,
|
||||
lpnrLocal, &bufferSize, &lplpSystem);
|
||||
if (result != NO_ERROR)
|
||||
return result;
|
||||
if (lplpSystem != 0)
|
||||
systemPathPart = lplpSystem;
|
||||
ConvertNETRESOURCEToCResource(lpnrLocal[0], destResource);
|
||||
return result;
|
||||
}
|
||||
CResource resourceA, destResourceA;
|
||||
ConvertResourceWToResource(resource, resourceA);
|
||||
AString systemPathPartA;
|
||||
const DWORD result = GetResourceInformation(resourceA, destResourceA, systemPathPartA);
|
||||
ConvertResourceToResourceW(destResourceA, destResource);
|
||||
systemPathPart = GetUnicodeString(systemPathPartA);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
DWORD AddConnection2(const CResource &resource,
|
||||
LPCTSTR password, LPCTSTR userName, DWORD flags)
|
||||
{
|
||||
NETRESOURCE netResource;
|
||||
ConvertCResourceToNETRESOURCE(resource, netResource);
|
||||
return ::WNetAddConnection2(&netResource,
|
||||
password, userName, flags);
|
||||
}
|
||||
|
||||
DWORD AddConnection2(const CResource &resource, LPCTSTR password, LPCTSTR userName, DWORD flags);
|
||||
|
||||
#ifndef _UNICODE
|
||||
DWORD AddConnection2(const CResourceW &resource, LPCWSTR password, LPCWSTR userName, DWORD flags)
|
||||
{
|
||||
if (g_IsNT)
|
||||
{
|
||||
NETRESOURCEW netResource;
|
||||
ConvertCResourceToNETRESOURCE(resource, netResource);
|
||||
return ::WNetAddConnection2W(&netResource,password, userName, flags);
|
||||
}
|
||||
CResource resourceA;
|
||||
ConvertResourceWToResource(resource, resourceA);
|
||||
const CSysString passwordA (GetSystemString(password));
|
||||
const CSysString userNameA (GetSystemString(userName));
|
||||
return AddConnection2(resourceA,
|
||||
password ? (LPCTSTR)passwordA: 0,
|
||||
userName ? (LPCTSTR)userNameA: 0,
|
||||
flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,87 @@
|
||||
// Windows/Net.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_NET_H
|
||||
#define ZIP7_INC_WINDOWS_NET_H
|
||||
|
||||
#include "../Common/MyString.h"
|
||||
#include "../Common/MyWindows.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NNet {
|
||||
|
||||
struct CResourceBase
|
||||
{
|
||||
DWORD Scope;
|
||||
DWORD Type;
|
||||
DWORD DisplayType;
|
||||
DWORD Usage;
|
||||
bool LocalNameIsDefined;
|
||||
bool RemoteNameIsDefined;
|
||||
bool CommentIsDefined;
|
||||
bool ProviderIsDefined;
|
||||
};
|
||||
|
||||
struct CResource: public CResourceBase
|
||||
{
|
||||
CSysString LocalName;
|
||||
CSysString RemoteName;
|
||||
CSysString Comment;
|
||||
CSysString Provider;
|
||||
};
|
||||
|
||||
#ifdef _UNICODE
|
||||
typedef CResource CResourceW;
|
||||
#else
|
||||
struct CResourceW: public CResourceBase
|
||||
{
|
||||
UString LocalName;
|
||||
UString RemoteName;
|
||||
UString Comment;
|
||||
UString Provider;
|
||||
};
|
||||
#endif
|
||||
|
||||
class CEnum
|
||||
{
|
||||
HANDLE _handle;
|
||||
bool _handleAllocated;
|
||||
DWORD Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCE netResource);
|
||||
DWORD Next(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize);
|
||||
#ifndef _UNICODE
|
||||
DWORD Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCEW netResource);
|
||||
DWORD NextW(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize);
|
||||
#endif
|
||||
protected:
|
||||
bool IsHandleAllocated() const { return _handleAllocated; }
|
||||
public:
|
||||
CEnum(): _handleAllocated(false) {}
|
||||
~CEnum() { Close(); }
|
||||
DWORD Close();
|
||||
DWORD Open(DWORD scope, DWORD type, DWORD usage, const CResource *resource);
|
||||
DWORD Next(CResource &resource);
|
||||
#ifndef _UNICODE
|
||||
DWORD Open(DWORD scope, DWORD type, DWORD usage, const CResourceW *resource);
|
||||
DWORD Next(CResourceW &resource);
|
||||
#endif
|
||||
};
|
||||
|
||||
DWORD GetResourceParent(const CResource &resource, CResource &parentResource);
|
||||
#ifndef _UNICODE
|
||||
DWORD GetResourceParent(const CResourceW &resource, CResourceW &parentResource);
|
||||
#endif
|
||||
|
||||
DWORD GetResourceInformation(const CResource &resource,
|
||||
CResource &destResource, CSysString &systemPathPart);
|
||||
#ifndef _UNICODE
|
||||
DWORD GetResourceInformation(const CResourceW &resource,
|
||||
CResourceW &destResource, UString &systemPathPart);
|
||||
#endif
|
||||
|
||||
DWORD AddConnection2(const CResource &resource, LPCTSTR password, LPCTSTR userName, DWORD flags);
|
||||
#ifndef _UNICODE
|
||||
DWORD AddConnection2(const CResourceW &resource, LPCWSTR password, LPCWSTR userName, DWORD flags);
|
||||
#endif
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,58 @@
|
||||
// Windows/NtCheck.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_NT_CHECK_H
|
||||
#define ZIP7_INC_WINDOWS_NT_CHECK_H
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "../Common/MyWindows.h"
|
||||
|
||||
#if !defined(_WIN64) && !defined(UNDER_CE)
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1900
|
||||
#pragma warning(push)
|
||||
// GetVersionExW was declared deprecated
|
||||
#pragma warning(disable : 4996)
|
||||
#endif
|
||||
static inline bool IsItWindowsNT()
|
||||
{
|
||||
OSVERSIONINFO vi;
|
||||
vi.dwOSVersionInfoSize = sizeof(vi);
|
||||
return (::GetVersionEx(&vi) && vi.dwPlatformId == VER_PLATFORM_WIN32_NT);
|
||||
}
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1900
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef _UNICODE
|
||||
extern
|
||||
bool g_IsNT;
|
||||
#if defined(_WIN64) || defined(UNDER_CE)
|
||||
bool g_IsNT = true;
|
||||
#define SET_IS_NT
|
||||
#else
|
||||
bool g_IsNT = false;
|
||||
#define SET_IS_NT g_IsNT = IsItWindowsNT();
|
||||
#endif
|
||||
#define NT_CHECK_ACTION
|
||||
// #define NT_CHECK_ACTION { NT_CHECK_FAIL_ACTION }
|
||||
#else
|
||||
#if !defined(_WIN64) && !defined(UNDER_CE)
|
||||
#define NT_CHECK_ACTION if (!IsItWindowsNT()) { NT_CHECK_FAIL_ACTION }
|
||||
#else
|
||||
#define NT_CHECK_ACTION
|
||||
#endif
|
||||
#define SET_IS_NT
|
||||
#endif
|
||||
|
||||
#define NT_CHECK NT_CHECK_ACTION SET_IS_NT
|
||||
|
||||
#else
|
||||
|
||||
#define NT_CHECK
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
// Windows/ProcessMessages.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "ProcessMessages.h"
|
||||
|
||||
namespace NWindows {
|
||||
|
||||
void ProcessMessages(HWND window)
|
||||
{
|
||||
MSG msg;
|
||||
while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
|
||||
{
|
||||
if (window == (HWND) NULL || !IsDialogMessage(window, &msg))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// Windows/ProcessMessages.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_PROCESS_MESSAGES_H
|
||||
#define ZIP7_INC_WINDOWS_PROCESS_MESSAGES_H
|
||||
|
||||
namespace NWindows {
|
||||
|
||||
void ProcessMessages(HWND window);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,102 @@
|
||||
// ProcessUtils.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/StringConvert.h"
|
||||
|
||||
#include "ProcessUtils.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
|
||||
namespace NWindows {
|
||||
|
||||
#ifndef UNDER_CE
|
||||
static UString GetQuotedString(const UString &s)
|
||||
{
|
||||
UString s2 ('\"');
|
||||
s2 += s;
|
||||
s2.Add_Char('\"');
|
||||
return s2;
|
||||
}
|
||||
#endif
|
||||
|
||||
WRes CProcess::Create(LPCWSTR imageName, const UString ¶ms, LPCWSTR curDir)
|
||||
{
|
||||
/*
|
||||
OutputDebugStringW(L"CProcess::Create");
|
||||
OutputDebugStringW(imageName);
|
||||
if (params)
|
||||
{
|
||||
OutputDebugStringW(L"params:");
|
||||
OutputDebugStringW(params);
|
||||
}
|
||||
if (curDir)
|
||||
{
|
||||
OutputDebugStringW(L"cur dir:");
|
||||
OutputDebugStringW(curDir);
|
||||
}
|
||||
*/
|
||||
|
||||
Close();
|
||||
const UString params2 =
|
||||
#ifndef UNDER_CE
|
||||
GetQuotedString(imageName) + L' ' +
|
||||
#endif
|
||||
params;
|
||||
#ifdef UNDER_CE
|
||||
curDir = NULL;
|
||||
#else
|
||||
imageName = NULL;
|
||||
#endif
|
||||
PROCESS_INFORMATION pi;
|
||||
BOOL result;
|
||||
#ifndef _UNICODE
|
||||
if (!g_IsNT)
|
||||
{
|
||||
STARTUPINFOA si;
|
||||
si.cb = sizeof(si);
|
||||
si.lpReserved = NULL;
|
||||
si.lpDesktop = NULL;
|
||||
si.lpTitle = NULL;
|
||||
si.dwFlags = 0;
|
||||
si.cbReserved2 = 0;
|
||||
si.lpReserved2 = NULL;
|
||||
|
||||
CSysString curDirA;
|
||||
if (curDir != 0)
|
||||
curDirA = GetSystemString(curDir);
|
||||
const AString s = GetSystemString(params2);
|
||||
result = ::CreateProcessA(NULL, s.Ptr_non_const(),
|
||||
NULL, NULL, FALSE, 0, NULL, ((curDir != 0) ? (LPCSTR)curDirA: 0), &si, &pi);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
STARTUPINFOW si;
|
||||
si.cb = sizeof(si);
|
||||
si.lpReserved = NULL;
|
||||
si.lpDesktop = NULL;
|
||||
si.lpTitle = NULL;
|
||||
si.dwFlags = 0;
|
||||
si.cbReserved2 = 0;
|
||||
si.lpReserved2 = NULL;
|
||||
|
||||
result = CreateProcessW(imageName, params2.Ptr_non_const(),
|
||||
NULL, NULL, FALSE, 0, NULL, curDir, &si, &pi);
|
||||
}
|
||||
if (result == 0)
|
||||
return ::GetLastError();
|
||||
::CloseHandle(pi.hThread);
|
||||
_handle = pi.hProcess;
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes MyCreateProcess(LPCWSTR imageName, const UString ¶ms)
|
||||
{
|
||||
CProcess process;
|
||||
return process.Create(imageName, params, NULL);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
// Windows/ProcessUtils.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_PROCESS_UTILS_H
|
||||
#define ZIP7_INC_WINDOWS_PROCESS_UTILS_H
|
||||
|
||||
#include "../Common/MyWindows.h"
|
||||
|
||||
#ifndef Z7_OLD_WIN_SDK
|
||||
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#include <psapi.h>
|
||||
#else
|
||||
#include <Psapi.h>
|
||||
#endif
|
||||
|
||||
#else // Z7_OLD_WIN_SDK
|
||||
|
||||
typedef struct _MODULEINFO {
|
||||
LPVOID lpBaseOfDll;
|
||||
DWORD SizeOfImage;
|
||||
LPVOID EntryPoint;
|
||||
} MODULEINFO, *LPMODULEINFO;
|
||||
|
||||
typedef struct _PROCESS_MEMORY_COUNTERS {
|
||||
DWORD cb;
|
||||
DWORD PageFaultCount;
|
||||
SIZE_T PeakWorkingSetSize;
|
||||
SIZE_T WorkingSetSize;
|
||||
SIZE_T QuotaPeakPagedPoolUsage;
|
||||
SIZE_T QuotaPagedPoolUsage;
|
||||
SIZE_T QuotaPeakNonPagedPoolUsage;
|
||||
SIZE_T QuotaNonPagedPoolUsage;
|
||||
SIZE_T PagefileUsage;
|
||||
SIZE_T PeakPagefileUsage;
|
||||
} PROCESS_MEMORY_COUNTERS;
|
||||
typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS;
|
||||
|
||||
#endif // Z7_OLD_WIN_SDK
|
||||
|
||||
#include "../Common/MyString.h"
|
||||
|
||||
#include "Defs.h"
|
||||
#include "Handle.h"
|
||||
|
||||
namespace NWindows {
|
||||
|
||||
class CProcess: public CHandle
|
||||
{
|
||||
public:
|
||||
bool Open(DWORD desiredAccess, bool inheritHandle, DWORD processId)
|
||||
{
|
||||
_handle = ::OpenProcess(desiredAccess, inheritHandle, processId);
|
||||
return (_handle != NULL);
|
||||
}
|
||||
|
||||
#ifndef UNDER_CE
|
||||
|
||||
bool GetExitCodeProcess(LPDWORD lpExitCode) { return BOOLToBool(::GetExitCodeProcess(_handle, lpExitCode)); }
|
||||
bool Terminate(UINT exitCode) { return BOOLToBool(::TerminateProcess(_handle, exitCode)); }
|
||||
#if (WINVER >= 0x0500)
|
||||
DWORD GetGuiResources (DWORD uiFlags) { return ::GetGuiResources(_handle, uiFlags); }
|
||||
#endif
|
||||
bool SetPriorityClass(DWORD dwPriorityClass) { return BOOLToBool(::SetPriorityClass(_handle, dwPriorityClass)); }
|
||||
DWORD GetPriorityClass() { return ::GetPriorityClass(_handle); }
|
||||
// bool GetIoCounters(PIO_COUNTERS lpIoCounters ) { return BOOLToBool(::GetProcessIoCounters(_handle, lpIoCounters )); }
|
||||
|
||||
bool GetTimes(LPFILETIME creationTime, LPFILETIME exitTime, LPFILETIME kernelTime, LPFILETIME userTime)
|
||||
{ return BOOLToBool(::GetProcessTimes(_handle, creationTime, exitTime, kernelTime, userTime)); }
|
||||
|
||||
DWORD WaitForInputIdle(DWORD milliseconds) { return ::WaitForInputIdle(_handle, milliseconds); }
|
||||
|
||||
// Debug
|
||||
|
||||
bool ReadMemory(LPCVOID baseAddress, LPVOID buffer, SIZE_T size, SIZE_T* numberOfBytesRead)
|
||||
{ return BOOLToBool(::ReadProcessMemory(_handle, baseAddress, buffer, size, numberOfBytesRead)); }
|
||||
|
||||
bool WriteMemory(LPVOID baseAddress, LPCVOID buffer, SIZE_T size, SIZE_T* numberOfBytesWritten)
|
||||
{ return BOOLToBool(::WriteProcessMemory(_handle, baseAddress,
|
||||
#ifdef Z7_OLD_WIN_SDK
|
||||
(LPVOID)
|
||||
#endif
|
||||
buffer,
|
||||
size, numberOfBytesWritten)); }
|
||||
|
||||
bool FlushInstructionCache(LPCVOID baseAddress = NULL, SIZE_T size = 0)
|
||||
{ return BOOLToBool(::FlushInstructionCache(_handle, baseAddress, size)); }
|
||||
|
||||
LPVOID VirtualAlloc(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect)
|
||||
{ return VirtualAllocEx(_handle, address, size, allocationType, protect); }
|
||||
|
||||
bool VirtualFree(LPVOID address, SIZE_T size, DWORD freeType)
|
||||
{ return BOOLToBool(::VirtualFreeEx(_handle, address, size, freeType)); }
|
||||
|
||||
// Process Status API (PSAPI)
|
||||
|
||||
/*
|
||||
bool EmptyWorkingSet()
|
||||
{ return BOOLToBool(::EmptyWorkingSet(_handle)); }
|
||||
bool EnumModules(HMODULE *hModules, DWORD arraySizeInBytes, LPDWORD receivedBytes)
|
||||
{ return BOOLToBool(::EnumProcessModules(_handle, hModules, arraySizeInBytes, receivedBytes)); }
|
||||
DWORD MyGetModuleBaseName(HMODULE hModule, LPTSTR baseName, DWORD size)
|
||||
{ return ::GetModuleBaseName(_handle, hModule, baseName, size); }
|
||||
bool MyGetModuleBaseName(HMODULE hModule, CSysString &name)
|
||||
{
|
||||
const unsigned len = MAX_PATH + 100;
|
||||
const DWORD resultLen = MyGetModuleBaseName(hModule, name.GetBuf(len), len);
|
||||
name.ReleaseBuf_CalcLen(len);
|
||||
return (resultLen != 0);
|
||||
}
|
||||
|
||||
DWORD MyGetModuleFileNameEx(HMODULE hModule, LPTSTR baseName, DWORD size)
|
||||
{ return ::GetModuleFileNameEx(_handle, hModule, baseName, size); }
|
||||
bool MyGetModuleFileNameEx(HMODULE hModule, CSysString &name)
|
||||
{
|
||||
const unsigned len = MAX_PATH + 100;
|
||||
const DWORD resultLen = MyGetModuleFileNameEx(hModule, name.GetBuf(len), len);
|
||||
name.ReleaseBuf_CalcLen(len);
|
||||
return (resultLen != 0);
|
||||
}
|
||||
|
||||
bool GetModuleInformation(HMODULE hModule, LPMODULEINFO moduleInfo)
|
||||
{ return BOOLToBool(::GetModuleInformation(_handle, hModule, moduleInfo, sizeof(MODULEINFO))); }
|
||||
bool GetMemoryInfo(PPROCESS_MEMORY_COUNTERS memCounters)
|
||||
{ return BOOLToBool(::GetProcessMemoryInfo(_handle, memCounters, sizeof(PROCESS_MEMORY_COUNTERS))); }
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
WRes Create(LPCWSTR imageName, const UString ¶ms, LPCWSTR curDir);
|
||||
|
||||
DWORD Wait() { return ::WaitForSingleObject(_handle, INFINITE); }
|
||||
};
|
||||
|
||||
WRes MyCreateProcess(LPCWSTR imageName, const UString ¶ms);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,393 @@
|
||||
// Windows/PropVariant.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/Defs.h"
|
||||
|
||||
#include "PropVariant.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NCOM {
|
||||
|
||||
BSTR AllocBstrFromAscii(const char *s) throw()
|
||||
{
|
||||
if (!s)
|
||||
return NULL;
|
||||
UINT len = (UINT)strlen(s);
|
||||
BSTR p = ::SysAllocStringLen(NULL, len);
|
||||
if (p)
|
||||
{
|
||||
for (UINT i = 0; i <= len; i++)
|
||||
p[i] = (Byte)s[i];
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw()
|
||||
{
|
||||
p->bstrVal = ::SysAllocStringLen(NULL, numChars);
|
||||
if (!p->bstrVal)
|
||||
{
|
||||
p->vt = VT_ERROR;
|
||||
p->scode = E_OUTOFMEMORY;
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
p->vt = VT_BSTR;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT PropVarEm_Set_Str(PROPVARIANT *p, const char *s) throw()
|
||||
{
|
||||
p->bstrVal = AllocBstrFromAscii(s);
|
||||
if (p->bstrVal)
|
||||
{
|
||||
p->vt = VT_BSTR;
|
||||
return S_OK;
|
||||
}
|
||||
p->vt = VT_ERROR;
|
||||
p->scode = E_OUTOFMEMORY;
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
CPropVariant::CPropVariant(const PROPVARIANT &varSrc)
|
||||
{
|
||||
vt = VT_EMPTY;
|
||||
InternalCopy(&varSrc);
|
||||
}
|
||||
|
||||
CPropVariant::CPropVariant(const CPropVariant &varSrc)
|
||||
{
|
||||
vt = VT_EMPTY;
|
||||
InternalCopy(&varSrc);
|
||||
}
|
||||
|
||||
CPropVariant::CPropVariant(BSTR bstrSrc)
|
||||
{
|
||||
vt = VT_EMPTY;
|
||||
*this = bstrSrc;
|
||||
}
|
||||
|
||||
CPropVariant::CPropVariant(LPCOLESTR lpszSrc)
|
||||
{
|
||||
vt = VT_EMPTY;
|
||||
*this = lpszSrc;
|
||||
}
|
||||
|
||||
CPropVariant& CPropVariant::operator=(const CPropVariant &varSrc)
|
||||
{
|
||||
InternalCopy(&varSrc);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CPropVariant& CPropVariant::operator=(const PROPVARIANT &varSrc)
|
||||
{
|
||||
InternalCopy(&varSrc);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CPropVariant& CPropVariant::operator=(BSTR bstrSrc)
|
||||
{
|
||||
*this = (LPCOLESTR)bstrSrc;
|
||||
return *this;
|
||||
}
|
||||
|
||||
static const char * const kMemException = "out of memory";
|
||||
|
||||
CPropVariant& CPropVariant::operator=(LPCOLESTR lpszSrc)
|
||||
{
|
||||
InternalClear();
|
||||
vt = VT_BSTR;
|
||||
wReserved1 = 0;
|
||||
bstrVal = ::SysAllocString(lpszSrc);
|
||||
if (!bstrVal && lpszSrc)
|
||||
{
|
||||
throw kMemException;
|
||||
// vt = VT_ERROR;
|
||||
// scode = E_OUTOFMEMORY;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
CPropVariant& CPropVariant::operator=(const UString &s)
|
||||
{
|
||||
InternalClear();
|
||||
vt = VT_BSTR;
|
||||
wReserved1 = 0;
|
||||
bstrVal = ::SysAllocStringLen(s, s.Len());
|
||||
if (!bstrVal)
|
||||
throw kMemException;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CPropVariant& CPropVariant::operator=(const UString2 &s)
|
||||
{
|
||||
/*
|
||||
if (s.IsEmpty())
|
||||
*this = L"";
|
||||
else
|
||||
*/
|
||||
{
|
||||
InternalClear();
|
||||
vt = VT_BSTR;
|
||||
wReserved1 = 0;
|
||||
bstrVal = ::SysAllocStringLen(s.GetRawPtr(), s.Len());
|
||||
if (!bstrVal)
|
||||
throw kMemException;
|
||||
/* SysAllocStringLen probably appends a null-terminating character for NULL string.
|
||||
But it doesn't specified in MSDN.
|
||||
But we suppose that it works
|
||||
|
||||
if (!s.GetRawPtr())
|
||||
{
|
||||
*bstrVal = 0;
|
||||
}
|
||||
*/
|
||||
|
||||
/* MSDN: Windows CE: SysAllocStringLen() : Passing invalid (and under some circumstances NULL)
|
||||
pointers to this function causes an unexpected termination of the application.
|
||||
Is it safe? Maybe we must chamnge the code for that case ? */
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
CPropVariant& CPropVariant::operator=(const char *s)
|
||||
{
|
||||
InternalClear();
|
||||
vt = VT_BSTR;
|
||||
wReserved1 = 0;
|
||||
bstrVal = AllocBstrFromAscii(s);
|
||||
if (!bstrVal)
|
||||
{
|
||||
throw kMemException;
|
||||
// vt = VT_ERROR;
|
||||
// scode = E_OUTOFMEMORY;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
CPropVariant& CPropVariant::operator=(bool bSrc) throw()
|
||||
{
|
||||
if (vt != VT_BOOL)
|
||||
{
|
||||
InternalClear();
|
||||
vt = VT_BOOL;
|
||||
}
|
||||
boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BSTR CPropVariant::AllocBstr(unsigned numChars)
|
||||
{
|
||||
if (vt != VT_EMPTY)
|
||||
InternalClear();
|
||||
vt = VT_BSTR;
|
||||
wReserved1 = 0;
|
||||
bstrVal = ::SysAllocStringLen(NULL, numChars);
|
||||
if (!bstrVal)
|
||||
{
|
||||
throw kMemException;
|
||||
// vt = VT_ERROR;
|
||||
// scode = E_OUTOFMEMORY;
|
||||
}
|
||||
return bstrVal;
|
||||
}
|
||||
|
||||
#define SET_PROP_id_dest(id, dest) \
|
||||
if (vt != id) { InternalClear(); vt = id; } dest = value; wReserved1 = 0;
|
||||
|
||||
void CPropVariant::Set_Int32(Int32 value) throw()
|
||||
{
|
||||
SET_PROP_id_dest(VT_I4, lVal)
|
||||
}
|
||||
|
||||
void CPropVariant::Set_Int64(Int64 value) throw()
|
||||
{
|
||||
SET_PROP_id_dest(VT_I8, hVal.QuadPart)
|
||||
}
|
||||
|
||||
#define SET_PROP_FUNC(type, id, dest) \
|
||||
CPropVariant& CPropVariant::operator=(type value) throw() \
|
||||
{ SET_PROP_id_dest(id, dest) return *this; }
|
||||
|
||||
SET_PROP_FUNC(Byte, VT_UI1, bVal)
|
||||
// SET_PROP_FUNC(Int16, VT_I2, iVal)
|
||||
// SET_PROP_FUNC(Int32, VT_I4, lVal)
|
||||
SET_PROP_FUNC(UInt32, VT_UI4, ulVal)
|
||||
SET_PROP_FUNC(UInt64, VT_UI8, uhVal.QuadPart)
|
||||
// SET_PROP_FUNC(Int64, VT_I8, hVal.QuadPart)
|
||||
SET_PROP_FUNC(const FILETIME &, VT_FILETIME, filetime)
|
||||
|
||||
#define CASE_SIMPLE_VT_VALUES \
|
||||
case VT_EMPTY: \
|
||||
case VT_BOOL: \
|
||||
case VT_FILETIME: \
|
||||
case VT_UI8: \
|
||||
case VT_UI4: \
|
||||
case VT_UI2: \
|
||||
case VT_UI1: \
|
||||
case VT_I8: \
|
||||
case VT_I4: \
|
||||
case VT_I2: \
|
||||
case VT_I1: \
|
||||
case VT_UINT: \
|
||||
case VT_INT: \
|
||||
case VT_NULL: \
|
||||
case VT_ERROR: \
|
||||
case VT_R4: \
|
||||
case VT_R8: \
|
||||
case VT_CY: \
|
||||
case VT_DATE: \
|
||||
|
||||
|
||||
/*
|
||||
::VariantClear() and ::VariantCopy() don't work, if (vt == VT_FILETIME)
|
||||
So we handle VT_FILETIME and another simple types directly
|
||||
we call system functions for VT_BSTR and for unknown typed
|
||||
*/
|
||||
|
||||
CPropVariant::~CPropVariant() throw()
|
||||
{
|
||||
switch ((unsigned)vt)
|
||||
{
|
||||
CASE_SIMPLE_VT_VALUES
|
||||
// vt = VT_EMPTY; // it's optional
|
||||
return;
|
||||
default: break;
|
||||
}
|
||||
::VariantClear((tagVARIANT *)this);
|
||||
}
|
||||
|
||||
HRESULT PropVariant_Clear(PROPVARIANT *prop) throw()
|
||||
{
|
||||
switch ((unsigned)prop->vt)
|
||||
{
|
||||
CASE_SIMPLE_VT_VALUES
|
||||
prop->vt = VT_EMPTY;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
const HRESULT res = ::VariantClear((VARIANTARG *)prop);
|
||||
if (res != S_OK || prop->vt != VT_EMPTY)
|
||||
return res;
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop->wReserved1 = 0;
|
||||
prop->wReserved2 = 0;
|
||||
prop->wReserved3 = 0;
|
||||
prop->uhVal.QuadPart = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CPropVariant::Clear() throw()
|
||||
{
|
||||
if (vt == VT_EMPTY)
|
||||
{
|
||||
wReserved1 = 0;
|
||||
return S_OK;
|
||||
}
|
||||
return PropVariant_Clear(this);
|
||||
}
|
||||
|
||||
HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw()
|
||||
{
|
||||
Clear();
|
||||
switch ((unsigned)pSrc->vt)
|
||||
{
|
||||
CASE_SIMPLE_VT_VALUES
|
||||
memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT));
|
||||
return S_OK;
|
||||
default: break;
|
||||
}
|
||||
return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)const_cast<PROPVARIANT *>(pSrc));
|
||||
}
|
||||
|
||||
|
||||
HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw()
|
||||
{
|
||||
const HRESULT hr = Clear();
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
// memcpy((PROPVARIANT *)this, pSrc, sizeof(PROPVARIANT));
|
||||
*(PROPVARIANT *)this = *pSrc;
|
||||
pSrc->vt = VT_EMPTY;
|
||||
pSrc->wReserved1 = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CPropVariant::Detach(PROPVARIANT *pDest) throw()
|
||||
{
|
||||
if (pDest->vt != VT_EMPTY)
|
||||
{
|
||||
const HRESULT hr = PropVariant_Clear(pDest);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
}
|
||||
// memcpy(pDest, this, sizeof(PROPVARIANT));
|
||||
*pDest = *(PROPVARIANT *)this;
|
||||
vt = VT_EMPTY;
|
||||
wReserved1 = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CPropVariant::InternalClear() throw()
|
||||
{
|
||||
if (vt == VT_EMPTY)
|
||||
{
|
||||
wReserved1 = 0;
|
||||
return S_OK;
|
||||
}
|
||||
const HRESULT hr = Clear();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
vt = VT_ERROR;
|
||||
scode = hr;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
void CPropVariant::InternalCopy(const PROPVARIANT *pSrc)
|
||||
{
|
||||
const HRESULT hr = Copy(pSrc);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
if (hr == E_OUTOFMEMORY)
|
||||
throw kMemException;
|
||||
vt = VT_ERROR;
|
||||
scode = hr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int CPropVariant::Compare(const CPropVariant &a) throw()
|
||||
{
|
||||
if (vt != a.vt)
|
||||
return MyCompare(vt, a.vt);
|
||||
switch ((unsigned)vt)
|
||||
{
|
||||
case VT_EMPTY: return 0;
|
||||
// case VT_I1: return MyCompare(cVal, a.cVal);
|
||||
case VT_UI1: return MyCompare(bVal, a.bVal);
|
||||
case VT_I2: return MyCompare(iVal, a.iVal);
|
||||
case VT_UI2: return MyCompare(uiVal, a.uiVal);
|
||||
case VT_I4: return MyCompare(lVal, a.lVal);
|
||||
case VT_UI4: return MyCompare(ulVal, a.ulVal);
|
||||
// case VT_UINT: return MyCompare(uintVal, a.uintVal);
|
||||
case VT_I8: return MyCompare(hVal.QuadPart, a.hVal.QuadPart);
|
||||
case VT_UI8: return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart);
|
||||
case VT_BOOL: return -MyCompare(boolVal, a.boolVal);
|
||||
case VT_FILETIME:
|
||||
{
|
||||
const int res = CompareFileTime(&filetime, &a.filetime);
|
||||
if (res != 0)
|
||||
return res;
|
||||
const unsigned v1 = Get_Ns100();
|
||||
const unsigned v2 = a.Get_Ns100();
|
||||
return MyCompare(v1, v2);
|
||||
}
|
||||
case VT_BSTR: return 0; // Not implemented
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,173 @@
|
||||
// Windows/PropVariant.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_PROP_VARIANT_H
|
||||
#define ZIP7_INC_WINDOWS_PROP_VARIANT_H
|
||||
|
||||
#include "../Common/MyTypes.h"
|
||||
#include "../Common/MyWindows.h"
|
||||
#include "../Common/MyString.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NCOM {
|
||||
|
||||
BSTR AllocBstrFromAscii(const char *s) throw();
|
||||
|
||||
HRESULT PropVariant_Clear(PROPVARIANT *p) throw();
|
||||
|
||||
HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw();
|
||||
HRESULT PropVarEm_Set_Str(PROPVARIANT *p, const char *s) throw();
|
||||
|
||||
inline void PropVarEm_Set_UInt32(PROPVARIANT *p, UInt32 v) throw()
|
||||
{
|
||||
p->vt = VT_UI4;
|
||||
p->ulVal = v;
|
||||
}
|
||||
|
||||
inline void PropVarEm_Set_UInt64(PROPVARIANT *p, UInt64 v) throw()
|
||||
{
|
||||
p->vt = VT_UI8;
|
||||
p->uhVal.QuadPart = v;
|
||||
}
|
||||
|
||||
inline void PropVarEm_Set_FileTime64_Prec(PROPVARIANT *p, UInt64 v, unsigned prec) throw()
|
||||
{
|
||||
p->vt = VT_FILETIME;
|
||||
p->filetime.dwLowDateTime = (DWORD)v;
|
||||
p->filetime.dwHighDateTime = (DWORD)(v >> 32);
|
||||
p->wReserved1 = (WORD)prec;
|
||||
p->wReserved2 = 0;
|
||||
p->wReserved3 = 0;
|
||||
}
|
||||
|
||||
inline void PropVarEm_Set_Bool(PROPVARIANT *p, bool b) throw()
|
||||
{
|
||||
p->vt = VT_BOOL;
|
||||
p->boolVal = (b ? VARIANT_TRUE : VARIANT_FALSE);
|
||||
}
|
||||
|
||||
|
||||
class CPropVariant : public tagPROPVARIANT
|
||||
{
|
||||
// ---------- forbidden functions ----------
|
||||
CPropVariant(const char *s);
|
||||
// CPropVariant(const UString &s);
|
||||
#ifdef DEBUG_FSTRING_INHERITS_ASTRING
|
||||
CPropVariant(const FString &s);
|
||||
CPropVariant& operator=(const FString &s);
|
||||
#endif
|
||||
|
||||
public:
|
||||
CPropVariant()
|
||||
{
|
||||
vt = VT_EMPTY;
|
||||
wReserved1 = 0;
|
||||
// wReserved2 = 0;
|
||||
// wReserved3 = 0;
|
||||
// uhVal.QuadPart = 0;
|
||||
bstrVal = NULL;
|
||||
}
|
||||
|
||||
|
||||
void Set_FtPrec(unsigned prec)
|
||||
{
|
||||
wReserved1 = (WORD)prec;
|
||||
wReserved2 = 0;
|
||||
wReserved3 = 0;
|
||||
}
|
||||
|
||||
void SetAsTimeFrom_FT_Prec(const FILETIME &ft, unsigned prec)
|
||||
{
|
||||
operator=(ft);
|
||||
Set_FtPrec(prec);
|
||||
}
|
||||
|
||||
void SetAsTimeFrom_Ft64_Prec(UInt64 v, unsigned prec)
|
||||
{
|
||||
FILETIME ft;
|
||||
ft.dwLowDateTime = (DWORD)(UInt32)v;
|
||||
ft.dwHighDateTime = (DWORD)(UInt32)(v >> 32);
|
||||
operator=(ft);
|
||||
Set_FtPrec(prec);
|
||||
}
|
||||
|
||||
void SetAsTimeFrom_FT_Prec_Ns100(const FILETIME &ft, unsigned prec, unsigned ns100)
|
||||
{
|
||||
operator=(ft);
|
||||
wReserved1 = (WORD)prec;
|
||||
wReserved2 = (WORD)ns100;
|
||||
wReserved3 = 0;
|
||||
}
|
||||
|
||||
unsigned Get_Ns100() const
|
||||
{
|
||||
const unsigned prec = wReserved1;
|
||||
const unsigned ns100 = wReserved2;
|
||||
if (prec == 0
|
||||
&& prec <= k_PropVar_TimePrec_1ns
|
||||
&& ns100 < 100
|
||||
&& wReserved3 == 0)
|
||||
return ns100;
|
||||
return 0;
|
||||
}
|
||||
|
||||
~CPropVariant() throw();
|
||||
CPropVariant(const PROPVARIANT &varSrc);
|
||||
CPropVariant(const CPropVariant &varSrc);
|
||||
CPropVariant(BSTR bstrSrc);
|
||||
CPropVariant(LPCOLESTR lpszSrc);
|
||||
CPropVariant(bool bSrc) { vt = VT_BOOL; wReserved1 = 0; boolVal = (bSrc ? VARIANT_TRUE : VARIANT_FALSE); }
|
||||
CPropVariant(Byte value) { vt = VT_UI1; wReserved1 = 0; bVal = value; }
|
||||
|
||||
private:
|
||||
CPropVariant(UInt16 value); // { vt = VT_UI2; wReserved1 = 0; uiVal = value; }
|
||||
CPropVariant(Int16 value); // { vt = VT_I2; wReserved1 = 0; iVal = value; }
|
||||
CPropVariant(Int32 value); // { vt = VT_I4; wReserved1 = 0; lVal = value; }
|
||||
CPropVariant(Int64 value); // { vt = VT_I8; wReserved1 = 0; hVal.QuadPart = value; }
|
||||
|
||||
public:
|
||||
CPropVariant(UInt32 value) { vt = VT_UI4; wReserved1 = 0; ulVal = value; }
|
||||
CPropVariant(UInt64 value) { vt = VT_UI8; wReserved1 = 0; uhVal.QuadPart = value; }
|
||||
CPropVariant(const FILETIME &value) { vt = VT_FILETIME; wReserved1 = 0; filetime = value; }
|
||||
|
||||
CPropVariant& operator=(const CPropVariant &varSrc);
|
||||
CPropVariant& operator=(const PROPVARIANT &varSrc);
|
||||
CPropVariant& operator=(BSTR bstrSrc);
|
||||
CPropVariant& operator=(LPCOLESTR lpszSrc);
|
||||
CPropVariant& operator=(const UString &s);
|
||||
CPropVariant& operator=(const UString2 &s);
|
||||
CPropVariant& operator=(const char *s);
|
||||
CPropVariant& operator=(const AString &s)
|
||||
{ return (*this)=(const char *)s; }
|
||||
|
||||
CPropVariant& operator=(bool bSrc) throw();
|
||||
CPropVariant& operator=(Byte value) throw();
|
||||
|
||||
private:
|
||||
CPropVariant& operator=(Int16 value) throw();
|
||||
CPropVariant& operator=(UInt16 value) throw();
|
||||
CPropVariant& operator=(Int32 value) throw();
|
||||
CPropVariant& operator=(Int64 value) throw();
|
||||
|
||||
public:
|
||||
CPropVariant& operator=(UInt32 value) throw();
|
||||
CPropVariant& operator=(UInt64 value) throw();
|
||||
CPropVariant& operator=(const FILETIME &value) throw();
|
||||
|
||||
void Set_Int32(Int32 value) throw();
|
||||
void Set_Int64(Int64 value) throw();
|
||||
|
||||
BSTR AllocBstr(unsigned numChars);
|
||||
|
||||
HRESULT Clear() throw();
|
||||
HRESULT Copy(const PROPVARIANT *pSrc) throw();
|
||||
HRESULT Attach(PROPVARIANT *pSrc) throw();
|
||||
HRESULT Detach(PROPVARIANT *pDest) throw();
|
||||
|
||||
HRESULT InternalClear() throw();
|
||||
void InternalCopy(const PROPVARIANT *pSrc);
|
||||
int Compare(const CPropVariant &a) throw();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,274 @@
|
||||
// PropVariantConv.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/IntToString.h"
|
||||
|
||||
#include "Defs.h"
|
||||
#include "PropVariantConv.h"
|
||||
|
||||
#define UINT_TO_STR_2(c, val) { s[0] = (c); s[1] = (char)('0' + (val) / 10); s[2] = (char)('0' + (val) % 10); s += 3; }
|
||||
|
||||
static const unsigned k_TimeStringBufferSize = 64;
|
||||
|
||||
bool g_Timestamp_Show_UTC;
|
||||
#if 0
|
||||
bool g_Timestamp_Show_DisableZ;
|
||||
bool g_Timestamp_Show_TDelimeter;
|
||||
bool g_Timestamp_Show_ZoneOffset;
|
||||
#endif
|
||||
|
||||
Z7_NO_INLINE
|
||||
bool ConvertUtcFileTimeToString2(const FILETIME &utc, unsigned ns100, char *s, int level, unsigned flags) throw()
|
||||
{
|
||||
*s = 0;
|
||||
FILETIME ft;
|
||||
|
||||
#if 0
|
||||
Int64 bias64 = 0;
|
||||
#endif
|
||||
|
||||
const bool show_utc =
|
||||
(flags & kTimestampPrintFlags_Force_UTC) ? true :
|
||||
(flags & kTimestampPrintFlags_Force_LOCAL) ? false :
|
||||
g_Timestamp_Show_UTC;
|
||||
|
||||
if (show_utc)
|
||||
ft = utc;
|
||||
else
|
||||
{
|
||||
if (!FileTimeToLocalFileTime(&utc, &ft))
|
||||
return false;
|
||||
#if 0
|
||||
if (g_Timestamp_Show_ZoneOffset)
|
||||
{
|
||||
const UInt64 utc64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime;
|
||||
const UInt64 loc64 = (((UInt64) ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
|
||||
bias64 = (Int64)utc64 - (Int64)loc64;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SYSTEMTIME st;
|
||||
if (!BOOLToBool(FileTimeToSystemTime(&ft, &st)))
|
||||
{
|
||||
// win10 : that function doesn't work, if bit 63 of 64-bit FILETIME is set.
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
unsigned val = st.wYear;
|
||||
if (val >= 10000)
|
||||
{
|
||||
*s++ = (char)('0' + val / 10000);
|
||||
val %= 10000;
|
||||
}
|
||||
s[3] = (char)('0' + val % 10); val /= 10;
|
||||
s[2] = (char)('0' + val % 10); val /= 10;
|
||||
s[1] = (char)('0' + val % 10);
|
||||
s[0] = (char)('0' + val / 10);
|
||||
s += 4;
|
||||
}
|
||||
UINT_TO_STR_2('-', st.wMonth)
|
||||
UINT_TO_STR_2('-', st.wDay)
|
||||
|
||||
if (level > kTimestampPrintLevel_DAY)
|
||||
{
|
||||
const char setChar =
|
||||
#if 0
|
||||
g_Timestamp_Show_TDelimeter ? 'T' : // ISO 8601
|
||||
#endif
|
||||
' ';
|
||||
UINT_TO_STR_2(setChar, st.wHour)
|
||||
UINT_TO_STR_2(':', st.wMinute)
|
||||
|
||||
if (level >= kTimestampPrintLevel_SEC)
|
||||
{
|
||||
UINT_TO_STR_2(':', st.wSecond)
|
||||
|
||||
if (level > kTimestampPrintLevel_SEC)
|
||||
{
|
||||
*s++ = '.';
|
||||
/*
|
||||
{
|
||||
unsigned val = st.wMilliseconds;
|
||||
s[2] = (char)('0' + val % 10); val /= 10;
|
||||
s[1] = (char)('0' + val % 10);
|
||||
s[0] = (char)('0' + val / 10);
|
||||
s += 3;
|
||||
}
|
||||
*s++ = ' ';
|
||||
*/
|
||||
|
||||
{
|
||||
unsigned numDigits = 7;
|
||||
UInt32 val = (UInt32)((((UInt64)ft.dwHighDateTime << 32) + ft.dwLowDateTime) % 10000000);
|
||||
for (unsigned i = numDigits; i != 0;)
|
||||
{
|
||||
i--;
|
||||
s[i] = (char)('0' + val % 10); val /= 10;
|
||||
}
|
||||
if (numDigits > (unsigned)level)
|
||||
numDigits = (unsigned)level;
|
||||
s += numDigits;
|
||||
}
|
||||
if (level >= kTimestampPrintLevel_NTFS + 1)
|
||||
{
|
||||
*s++ = (char)('0' + (ns100 / 10));
|
||||
if (level >= kTimestampPrintLevel_NTFS + 2)
|
||||
*s++ = (char)('0' + (ns100 % 10));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (show_utc)
|
||||
{
|
||||
if ((flags & kTimestampPrintFlags_DisableZ) == 0
|
||||
#if 0
|
||||
&& !g_Timestamp_Show_DisableZ
|
||||
#endif
|
||||
)
|
||||
*s++ = 'Z';
|
||||
}
|
||||
#if 0
|
||||
else if (g_Timestamp_Show_ZoneOffset)
|
||||
{
|
||||
#if 1
|
||||
{
|
||||
char c;
|
||||
if (bias64 < 0)
|
||||
{
|
||||
bias64 = -bias64;
|
||||
c = '+';
|
||||
}
|
||||
else
|
||||
c = '-';
|
||||
UInt32 bias = (UInt32)((UInt64)bias64 / (10000000 * 60));
|
||||
#else
|
||||
TIME_ZONE_INFORMATION zi;
|
||||
const DWORD dw = GetTimeZoneInformation(&zi);
|
||||
if (dw <= TIME_ZONE_ID_DAYLIGHT) // == 2
|
||||
{
|
||||
// UTC = LOCAL + Bias
|
||||
Int32 bias = zi.Bias;
|
||||
char c;
|
||||
if (bias < 0)
|
||||
{
|
||||
bias = -bias;
|
||||
c = '+';
|
||||
}
|
||||
else
|
||||
c = '-';
|
||||
#endif
|
||||
const UInt32 hours = (UInt32)bias / 60;
|
||||
const UInt32 mins = (UInt32)bias % 60;
|
||||
UINT_TO_STR_2(c, hours)
|
||||
UINT_TO_STR_2(':', mins)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
*s = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ConvertUtcFileTimeToString(const FILETIME &utc, char *s, int level) throw()
|
||||
{
|
||||
return ConvertUtcFileTimeToString2(utc, 0, s, level);
|
||||
}
|
||||
|
||||
bool ConvertUtcFileTimeToString2(const FILETIME &ft, unsigned ns100, wchar_t *dest, int level) throw()
|
||||
{
|
||||
char s[k_TimeStringBufferSize];
|
||||
const bool res = ConvertUtcFileTimeToString2(ft, ns100, s, level);
|
||||
for (unsigned i = 0;; i++)
|
||||
{
|
||||
const Byte c = (Byte)s[i];
|
||||
dest[i] = c;
|
||||
if (c == 0)
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *dest, int level) throw()
|
||||
{
|
||||
char s[k_TimeStringBufferSize];
|
||||
const bool res = ConvertUtcFileTimeToString(ft, s, level);
|
||||
for (unsigned i = 0;; i++)
|
||||
{
|
||||
const Byte c = (Byte)s[i];
|
||||
dest[i] = c;
|
||||
if (c == 0)
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void ConvertPropVariantToShortString(const PROPVARIANT &prop, char *dest) throw()
|
||||
{
|
||||
*dest = 0;
|
||||
switch (prop.vt)
|
||||
{
|
||||
case VT_EMPTY: return;
|
||||
case VT_BSTR: dest[0] = '?'; dest[1] = 0; return;
|
||||
case VT_UI1: ConvertUInt32ToString(prop.bVal, dest); return;
|
||||
case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return;
|
||||
case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return;
|
||||
case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return;
|
||||
case VT_FILETIME:
|
||||
{
|
||||
// const unsigned prec = prop.wReserved1;
|
||||
int level = 0;
|
||||
/*
|
||||
if (prec == 0)
|
||||
level = 7;
|
||||
else if (prec > 16 && prec <= 16 + 9)
|
||||
level = prec - 16;
|
||||
*/
|
||||
ConvertUtcFileTimeToString(prop.filetime, dest, level);
|
||||
return;
|
||||
}
|
||||
// case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return;
|
||||
case VT_I2: ConvertInt64ToString(prop.iVal, dest); return;
|
||||
case VT_I4: ConvertInt64ToString(prop.lVal, dest); return;
|
||||
case VT_I8: ConvertInt64ToString(prop.hVal.QuadPart, dest); return;
|
||||
case VT_BOOL: dest[0] = VARIANT_BOOLToBool(prop.boolVal) ? '+' : '-'; dest[1] = 0; return;
|
||||
default: dest[0] = '?'; dest[1] = ':'; ConvertUInt64ToString(prop.vt, dest + 2);
|
||||
}
|
||||
}
|
||||
|
||||
void ConvertPropVariantToShortString(const PROPVARIANT &prop, wchar_t *dest) throw()
|
||||
{
|
||||
*dest = 0;
|
||||
switch (prop.vt)
|
||||
{
|
||||
case VT_EMPTY: return;
|
||||
case VT_BSTR: dest[0] = '?'; dest[1] = 0; return;
|
||||
case VT_UI1: ConvertUInt32ToString(prop.bVal, dest); return;
|
||||
case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return;
|
||||
case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return;
|
||||
case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return;
|
||||
case VT_FILETIME:
|
||||
{
|
||||
// const unsigned prec = prop.wReserved1;
|
||||
int level = 0;
|
||||
/*
|
||||
if (prec == 0)
|
||||
level = 7;
|
||||
else if (prec > 16 && prec <= 16 + 9)
|
||||
level = prec - 16;
|
||||
*/
|
||||
ConvertUtcFileTimeToString(prop.filetime, dest, level);
|
||||
return;
|
||||
}
|
||||
// case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return;
|
||||
case VT_I2: ConvertInt64ToString(prop.iVal, dest); return;
|
||||
case VT_I4: ConvertInt64ToString(prop.lVal, dest); return;
|
||||
case VT_I8: ConvertInt64ToString(prop.hVal.QuadPart, dest); return;
|
||||
case VT_BOOL: dest[0] = VARIANT_BOOLToBool(prop.boolVal) ? (wchar_t)'+' : (wchar_t)'-'; dest[1] = 0; return;
|
||||
default: dest[0] = '?'; dest[1] = ':'; ConvertUInt32ToString(prop.vt, dest + 2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Windows/PropVariantConv.h
|
||||
|
||||
#ifndef ZIP7_INC_PROP_VARIANT_CONV_H
|
||||
#define ZIP7_INC_PROP_VARIANT_CONV_H
|
||||
|
||||
#include "../Common/MyTypes.h"
|
||||
|
||||
// provide at least 32 bytes for buffer including zero-end
|
||||
|
||||
extern bool g_Timestamp_Show_UTC;
|
||||
|
||||
#define kTimestampPrintLevel_DAY -3
|
||||
// #define kTimestampPrintLevel_HOUR -2
|
||||
#define kTimestampPrintLevel_MIN -1
|
||||
#define kTimestampPrintLevel_SEC 0
|
||||
#define kTimestampPrintLevel_NTFS 7
|
||||
#define kTimestampPrintLevel_NS 9
|
||||
|
||||
|
||||
#define kTimestampPrintFlags_Force_UTC (1 << 0)
|
||||
#define kTimestampPrintFlags_Force_LOCAL (1 << 1)
|
||||
#define kTimestampPrintFlags_DisableZ (1 << 4)
|
||||
|
||||
bool ConvertUtcFileTimeToString(const FILETIME &ft, char *s, int level = kTimestampPrintLevel_SEC) throw();
|
||||
bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *s, int level = kTimestampPrintLevel_SEC) throw();
|
||||
bool ConvertUtcFileTimeToString2(const FILETIME &ft, unsigned ns100, char *s, int level = kTimestampPrintLevel_SEC, unsigned flags = 0) throw();
|
||||
bool ConvertUtcFileTimeToString2(const FILETIME &ft, unsigned ns100, wchar_t *s, int level = kTimestampPrintLevel_SEC) throw();
|
||||
|
||||
// provide at least 32 bytes for buffer including zero-end
|
||||
// don't send VT_BSTR to these functions
|
||||
void ConvertPropVariantToShortString(const PROPVARIANT &prop, char *dest) throw();
|
||||
void ConvertPropVariantToShortString(const PROPVARIANT &prop, wchar_t *dest) throw();
|
||||
|
||||
inline bool ConvertPropVariantToUInt64(const PROPVARIANT &prop, UInt64 &value)
|
||||
{
|
||||
switch (prop.vt)
|
||||
{
|
||||
case VT_UI8: value = (UInt64)prop.uhVal.QuadPart; return true;
|
||||
case VT_UI4: value = prop.ulVal; return true;
|
||||
case VT_UI2: value = prop.uiVal; return true;
|
||||
case VT_UI1: value = prop.bVal; return true;
|
||||
case VT_EMPTY: return false;
|
||||
default: throw 151199;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,161 @@
|
||||
// PropVariantUtils.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/IntToString.h"
|
||||
|
||||
#include "PropVariantUtils.h"
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
static void AddHex(AString &s, UInt32 v)
|
||||
{
|
||||
char sz[16];
|
||||
sz[0] = '0';
|
||||
sz[1] = 'x';
|
||||
ConvertUInt32ToHex(v, sz + 2);
|
||||
s += sz;
|
||||
}
|
||||
|
||||
|
||||
AString TypePairToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 value)
|
||||
{
|
||||
char sz[16];
|
||||
const char *p = NULL;
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
{
|
||||
const CUInt32PCharPair &pair = pairs[i];
|
||||
if (pair.Value == value)
|
||||
p = pair.Name;
|
||||
}
|
||||
if (!p)
|
||||
{
|
||||
ConvertUInt32ToString(value, sz);
|
||||
p = sz;
|
||||
}
|
||||
return (AString)p;
|
||||
}
|
||||
|
||||
void PairToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 value, NCOM::CPropVariant &prop)
|
||||
{
|
||||
prop = TypePairToString(pairs, num, value);
|
||||
}
|
||||
|
||||
|
||||
AString TypeToString(const char * const table[], unsigned num, UInt32 value)
|
||||
{
|
||||
char sz[16];
|
||||
const char *p = NULL;
|
||||
if (value < num)
|
||||
p = table[value];
|
||||
if (!p)
|
||||
{
|
||||
ConvertUInt32ToString(value, sz);
|
||||
p = sz;
|
||||
}
|
||||
return (AString)p;
|
||||
}
|
||||
|
||||
void TypeToProp(const char * const table[], unsigned num, UInt32 value, NWindows::NCOM::CPropVariant &prop)
|
||||
{
|
||||
char sz[16];
|
||||
const char *p = NULL;
|
||||
if (value < num)
|
||||
p = table[value];
|
||||
if (!p)
|
||||
{
|
||||
ConvertUInt32ToString(value, sz);
|
||||
p = sz;
|
||||
}
|
||||
prop = p;
|
||||
}
|
||||
|
||||
|
||||
AString FlagsToString(const char * const *names, unsigned num, UInt32 flags)
|
||||
{
|
||||
AString s;
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
{
|
||||
UInt32 flag = (UInt32)1 << i;
|
||||
if ((flags & flag) != 0)
|
||||
{
|
||||
const char *name = names[i];
|
||||
if (name && name[0] != 0)
|
||||
{
|
||||
s.Add_OptSpaced(name);
|
||||
flags &= ~flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flags != 0)
|
||||
{
|
||||
s.Add_Space_if_NotEmpty();
|
||||
AddHex(s, flags);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
AString FlagsToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags)
|
||||
{
|
||||
AString s;
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
{
|
||||
const CUInt32PCharPair &p = pairs[i];
|
||||
UInt32 flag = (UInt32)1 << (unsigned)p.Value;
|
||||
if ((flags & flag) != 0)
|
||||
{
|
||||
if (p.Name[0] != 0)
|
||||
s.Add_OptSpaced(p.Name);
|
||||
}
|
||||
flags &= ~flag;
|
||||
}
|
||||
if (flags != 0)
|
||||
{
|
||||
s.Add_Space_if_NotEmpty();
|
||||
AddHex(s, flags);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void FlagsToProp(const char * const *names, unsigned num, UInt32 flags, NCOM::CPropVariant &prop)
|
||||
{
|
||||
prop = FlagsToString(names, num, flags);
|
||||
}
|
||||
|
||||
void FlagsToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags, NCOM::CPropVariant &prop)
|
||||
{
|
||||
prop = FlagsToString(pairs, num, flags);
|
||||
}
|
||||
|
||||
|
||||
static AString Flags64ToString(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags)
|
||||
{
|
||||
AString s;
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
{
|
||||
const CUInt32PCharPair &p = pairs[i];
|
||||
UInt64 flag = (UInt64)1 << (unsigned)p.Value;
|
||||
if ((flags & flag) != 0)
|
||||
{
|
||||
if (p.Name[0] != 0)
|
||||
s.Add_OptSpaced(p.Name);
|
||||
}
|
||||
flags &= ~flag;
|
||||
}
|
||||
if (flags != 0)
|
||||
{
|
||||
{
|
||||
char sz[32];
|
||||
sz[0] = '0';
|
||||
sz[1] = 'x';
|
||||
ConvertUInt64ToHex(flags, sz + 2);
|
||||
s.Add_OptSpaced(sz);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void Flags64ToProp(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags, NCOM::CPropVariant &prop)
|
||||
{
|
||||
prop = Flags64ToString(pairs, num, flags);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Windows/PropVariantUtils.h
|
||||
|
||||
#ifndef ZIP7_INC_PROP_VARIANT_UTILS_H
|
||||
#define ZIP7_INC_PROP_VARIANT_UTILS_H
|
||||
|
||||
#include "../Common/MyString.h"
|
||||
|
||||
#include "PropVariant.h"
|
||||
|
||||
struct CUInt32PCharPair
|
||||
{
|
||||
UInt32 Value;
|
||||
const char *Name;
|
||||
};
|
||||
|
||||
AString TypePairToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 value);
|
||||
void PairToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 value, NWindows::NCOM::CPropVariant &prop);
|
||||
|
||||
AString FlagsToString(const char * const *names, unsigned num, UInt32 flags);
|
||||
AString FlagsToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags);
|
||||
void FlagsToProp(const char * const *names, unsigned num, UInt32 flags, NWindows::NCOM::CPropVariant &prop);
|
||||
void FlagsToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags, NWindows::NCOM::CPropVariant &prop);
|
||||
|
||||
AString TypeToString(const char * const table[], unsigned num, UInt32 value);
|
||||
void TypeToProp(const char * const table[], unsigned num, UInt32 value, NWindows::NCOM::CPropVariant &prop);
|
||||
|
||||
#define PAIR_TO_PROP(pairs, value, prop) PairToProp(pairs, Z7_ARRAY_SIZE(pairs), value, prop)
|
||||
#define FLAGS_TO_PROP(pairs, value, prop) FlagsToProp(pairs, Z7_ARRAY_SIZE(pairs), value, prop)
|
||||
#define TYPE_TO_PROP(table, value, prop) TypeToProp(table, Z7_ARRAY_SIZE(table), value, prop)
|
||||
|
||||
void Flags64ToProp(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags, NWindows::NCOM::CPropVariant &prop);
|
||||
#define FLAGS64_TO_PROP(pairs, value, prop) Flags64ToProp(pairs, Z7_ARRAY_SIZE(pairs), value, prop)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,474 @@
|
||||
// Windows/Registry.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include <wchar.h>
|
||||
// #include <stdio.h>
|
||||
|
||||
#ifndef _UNICODE
|
||||
#include "../Common/StringConvert.h"
|
||||
#endif
|
||||
#include "Registry.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
|
||||
namespace NWindows {
|
||||
namespace NRegistry {
|
||||
|
||||
#define MYASSERT(expr) // _ASSERTE(expr)
|
||||
#define MY_ASSUME(expr)
|
||||
|
||||
/*
|
||||
static void Error()
|
||||
{
|
||||
#ifdef _CONSOLE
|
||||
printf("\nregistry error\n");
|
||||
#else
|
||||
MessageBoxW(0, L"registry error", L"", 0);
|
||||
// exit(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define MY_ASSUME(expr) { if (!(expr)) Error(); }
|
||||
*/
|
||||
|
||||
LONG CKey::Create(HKEY parentKey, LPCTSTR keyName,
|
||||
LPTSTR keyClass, DWORD options, REGSAM accessMask,
|
||||
LPSECURITY_ATTRIBUTES securityAttributes, LPDWORD disposition) throw()
|
||||
{
|
||||
MY_ASSUME(parentKey != NULL);
|
||||
DWORD dispositionReal;
|
||||
HKEY key = NULL;
|
||||
LONG res = RegCreateKeyEx(parentKey, keyName, 0, keyClass,
|
||||
options, accessMask, securityAttributes, &key, &dispositionReal);
|
||||
if (disposition != NULL)
|
||||
*disposition = dispositionReal;
|
||||
if (res == ERROR_SUCCESS)
|
||||
{
|
||||
res = Close();
|
||||
_object = key;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
LONG CKey::Open(HKEY parentKey, LPCTSTR keyName, REGSAM accessMask) throw()
|
||||
{
|
||||
MY_ASSUME(parentKey != NULL);
|
||||
HKEY key = NULL;
|
||||
LONG res = RegOpenKeyEx(parentKey, keyName, 0, accessMask, &key);
|
||||
if (res == ERROR_SUCCESS)
|
||||
{
|
||||
res = Close();
|
||||
MYASSERT(res == ERROR_SUCCESS);
|
||||
_object = key;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
LONG CKey::Close() throw()
|
||||
{
|
||||
LONG res = ERROR_SUCCESS;
|
||||
if (_object != NULL)
|
||||
{
|
||||
res = RegCloseKey(_object);
|
||||
_object = NULL;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// win95, win98: deletes subkey and all its subkeys
|
||||
// winNT to be deleted must not have subkeys
|
||||
LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw()
|
||||
{
|
||||
MY_ASSUME(_object != NULL);
|
||||
return RegDeleteKey(_object, subKeyName);
|
||||
}
|
||||
|
||||
LONG CKey::RecurseDeleteKey(LPCTSTR subKeyName) throw()
|
||||
{
|
||||
{
|
||||
CKey key;
|
||||
LONG res = key.Open(_object, subKeyName, KEY_READ | KEY_WRITE);
|
||||
if (res != ERROR_SUCCESS)
|
||||
return res;
|
||||
FILETIME fileTime;
|
||||
const UInt32 kBufSize = MAX_PATH + 1; // 256 in ATL
|
||||
TCHAR buffer[kBufSize];
|
||||
// we use loop limit here for some unexpected code failure
|
||||
for (unsigned loop_cnt = 0; loop_cnt < (1u << 26); loop_cnt++)
|
||||
{
|
||||
DWORD size = kBufSize;
|
||||
// we always request starting item (index==0) in each iteration,
|
||||
// because we remove starting item (index==0) in each loop iteration.
|
||||
res = RegEnumKeyEx(key._object, 0, buffer, &size, NULL, NULL, NULL, &fileTime);
|
||||
if (res != ERROR_SUCCESS)
|
||||
{
|
||||
// possible return codes:
|
||||
// ERROR_NO_MORE_ITEMS : are no more subkeys available
|
||||
// ERROR_MORE_DATA : name buffer is too small
|
||||
// we can try to remove (subKeyName), even if there is non ERROR_NO_MORE_ITEMS error.
|
||||
// if (res != ERROR_NO_MORE_ITEMS) return res;
|
||||
break;
|
||||
}
|
||||
res = key.RecurseDeleteKey(buffer);
|
||||
if (res != ERROR_SUCCESS)
|
||||
return res;
|
||||
}
|
||||
// key.Close();
|
||||
}
|
||||
return DeleteSubKey(subKeyName);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////
|
||||
// Value Functions
|
||||
|
||||
static inline UInt32 BoolToUINT32(bool value) { return (value ? 1: 0); }
|
||||
static inline bool UINT32ToBool(UInt32 value) { return (value != 0); }
|
||||
|
||||
|
||||
LONG CKey::DeleteValue(LPCTSTR name) throw()
|
||||
{
|
||||
MY_ASSUME(_object != NULL);
|
||||
return ::RegDeleteValue(_object, name);
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
LONG CKey::DeleteValue(LPCWSTR name)
|
||||
{
|
||||
MY_ASSUME(_object != NULL);
|
||||
if (g_IsNT)
|
||||
return ::RegDeleteValueW(_object, name);
|
||||
return DeleteValue(name == NULL ? NULL : (LPCSTR)GetSystemString(name));
|
||||
}
|
||||
#endif
|
||||
|
||||
LONG CKey::SetValue(LPCTSTR name, UInt32 value) throw()
|
||||
{
|
||||
MY_ASSUME(_object != NULL);
|
||||
return RegSetValueEx(_object, name, 0, REG_DWORD,
|
||||
(const BYTE *)&value, sizeof(UInt32));
|
||||
}
|
||||
|
||||
LONG CKey::SetValue(LPCTSTR name, bool value) throw()
|
||||
{
|
||||
return SetValue(name, BoolToUINT32(value));
|
||||
}
|
||||
|
||||
|
||||
// value must be string that is NULL terminated
|
||||
LONG CKey::SetValue(LPCTSTR name, LPCTSTR value) throw()
|
||||
{
|
||||
MYASSERT(value != NULL);
|
||||
MY_ASSUME(_object != NULL);
|
||||
// note: RegSetValueEx supports (value == NULL), if (cbData == 0)
|
||||
return RegSetValueEx(_object, name, 0, REG_SZ,
|
||||
(const BYTE *)value, (DWORD)(((DWORD)lstrlen(value) + 1) * sizeof(TCHAR)));
|
||||
}
|
||||
|
||||
/*
|
||||
LONG CKey::SetValue(LPCTSTR name, const CSysString &value)
|
||||
{
|
||||
MYASSERT(value != NULL);
|
||||
MY_ASSUME(_object != NULL);
|
||||
return RegSetValueEx(_object, name, 0, REG_SZ,
|
||||
(const BYTE *)(const TCHAR *)value, (value.Len() + 1) * sizeof(TCHAR));
|
||||
}
|
||||
*/
|
||||
|
||||
#ifndef _UNICODE
|
||||
|
||||
LONG CKey::SetValue(LPCWSTR name, LPCWSTR value)
|
||||
{
|
||||
MYASSERT(value != NULL);
|
||||
MY_ASSUME(_object != NULL);
|
||||
if (g_IsNT)
|
||||
return RegSetValueExW(_object, name, 0, REG_SZ,
|
||||
(const BYTE *)value, (DWORD)(((DWORD)wcslen(value) + 1) * sizeof(wchar_t)));
|
||||
return SetValue(name == NULL ? NULL :
|
||||
(LPCSTR)GetSystemString(name),
|
||||
(LPCSTR)GetSystemString(value));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
LONG CKey::SetValue(LPCTSTR name, const void *value, UInt32 size) throw()
|
||||
{
|
||||
MYASSERT(value != NULL);
|
||||
MY_ASSUME(_object != NULL);
|
||||
return RegSetValueEx(_object, name, 0, REG_BINARY,
|
||||
(const BYTE *)value, size);
|
||||
}
|
||||
|
||||
LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value)
|
||||
{
|
||||
MYASSERT(value != NULL);
|
||||
CKey key;
|
||||
LONG res = key.Create(parentKey, keyName);
|
||||
if (res == ERROR_SUCCESS)
|
||||
res = key.SetValue(valueName, value);
|
||||
return res;
|
||||
}
|
||||
|
||||
LONG CKey::SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw()
|
||||
{
|
||||
MYASSERT(value != NULL);
|
||||
CKey key;
|
||||
LONG res = key.Create(_object, keyName);
|
||||
if (res == ERROR_SUCCESS)
|
||||
res = key.SetValue(valueName, value);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
LONG CKey::GetValue_UInt32_IfOk(LPCTSTR name, UInt32 &value) throw()
|
||||
{
|
||||
DWORD type = 0;
|
||||
DWORD count = sizeof(value);
|
||||
UInt32 value2; // = value;
|
||||
const LONG res = QueryValueEx(name, &type, (LPBYTE)&value2, &count);
|
||||
if (res == ERROR_SUCCESS)
|
||||
{
|
||||
// ERROR_UNSUPPORTED_TYPE
|
||||
if (count != sizeof(value) || type != REG_DWORD)
|
||||
return ERROR_UNSUPPORTED_TYPE; // ERROR_INVALID_DATA;
|
||||
value = value2;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
LONG CKey::GetValue_UInt64_IfOk(LPCTSTR name, UInt64 &value) throw()
|
||||
{
|
||||
DWORD type = 0;
|
||||
DWORD count = sizeof(value);
|
||||
UInt64 value2; // = value;
|
||||
const LONG res = QueryValueEx(name, &type, (LPBYTE)&value2, &count);
|
||||
if (res == ERROR_SUCCESS)
|
||||
{
|
||||
if (count != sizeof(value) || type != REG_QWORD)
|
||||
return ERROR_UNSUPPORTED_TYPE;
|
||||
value = value2;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
LONG CKey::GetValue_bool_IfOk(LPCTSTR name, bool &value) throw()
|
||||
{
|
||||
UInt32 uintValue;
|
||||
const LONG res = GetValue_UInt32_IfOk(name, uintValue);
|
||||
if (res == ERROR_SUCCESS)
|
||||
value = UINT32ToBool(uintValue);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LONG CKey::QueryValue(LPCTSTR name, CSysString &value)
|
||||
{
|
||||
value.Empty();
|
||||
LONG res = ERROR_SUCCESS;
|
||||
{
|
||||
// if we don't want multiple calls here,
|
||||
// we can use big value (264) here.
|
||||
// 3 is default available length in new string.
|
||||
DWORD size_prev = 3 * sizeof(TCHAR);
|
||||
// at least 2 attempts are required. But we use more attempts for cases,
|
||||
// where string can be changed by anothner process
|
||||
for (unsigned i = 0; i < 2 + 2; i++)
|
||||
{
|
||||
DWORD type = 0;
|
||||
DWORD size = size_prev;
|
||||
{
|
||||
LPBYTE buf = (LPBYTE)value.GetBuf(size / sizeof(TCHAR));
|
||||
res = QueryValueEx(name, &type, size == 0 ? NULL : buf, &size);
|
||||
// if (size_prev == 0), then (res == ERROR_SUCCESS) is expected here, because we requested only size.
|
||||
}
|
||||
if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA)
|
||||
{
|
||||
if (type != REG_SZ && type != REG_EXPAND_SZ)
|
||||
{
|
||||
res = ERROR_UNSUPPORTED_TYPE;
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
size = 0;
|
||||
if (size > size_prev)
|
||||
{
|
||||
size_prev = size;
|
||||
size = 0;
|
||||
res = ERROR_MORE_DATA;
|
||||
}
|
||||
value.ReleaseBuf_CalcLen(size / sizeof(TCHAR));
|
||||
if (res != ERROR_MORE_DATA)
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
#ifndef _UNICODE
|
||||
|
||||
LONG CKey::QueryValue(LPCWSTR name, UString &value)
|
||||
{
|
||||
value.Empty();
|
||||
LONG res = ERROR_SUCCESS;
|
||||
if (g_IsNT)
|
||||
{
|
||||
DWORD size_prev = 3 * sizeof(wchar_t);
|
||||
for (unsigned i = 0; i < 2 + 2; i++)
|
||||
{
|
||||
DWORD type = 0;
|
||||
DWORD size = size_prev;
|
||||
{
|
||||
LPBYTE buf = (LPBYTE)value.GetBuf(size / sizeof(wchar_t));
|
||||
res = RegQueryValueExW(_object, name, NULL, &type,
|
||||
size == 0 ? NULL : buf, &size);
|
||||
}
|
||||
if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA)
|
||||
{
|
||||
if (type != REG_SZ && type != REG_EXPAND_SZ)
|
||||
{
|
||||
res = ERROR_UNSUPPORTED_TYPE;
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
size = 0;
|
||||
if (size > size_prev)
|
||||
{
|
||||
size_prev = size;
|
||||
size = 0;
|
||||
res = ERROR_MORE_DATA;
|
||||
}
|
||||
value.ReleaseBuf_CalcLen(size / sizeof(wchar_t));
|
||||
if (res != ERROR_MORE_DATA)
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AString vTemp;
|
||||
res = QueryValue(name == NULL ? NULL : (LPCSTR)GetSystemString(name), vTemp);
|
||||
value = GetUnicodeString(vTemp);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
LONG CKey::QueryValue_Binary(LPCTSTR name, CByteBuffer &value)
|
||||
{
|
||||
// value.Free();
|
||||
DWORD size_prev = 0;
|
||||
LONG res = ERROR_SUCCESS;
|
||||
for (unsigned i = 0; i < 2 + 2; i++)
|
||||
{
|
||||
DWORD type = 0;
|
||||
DWORD size = size_prev;
|
||||
value.Alloc(size_prev);
|
||||
res = QueryValueEx(name, &type, value.NonConstData(), &size);
|
||||
// if (size_prev == 0), then (res == ERROR_SUCCESS) is expected here, because we requested only size.
|
||||
if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA)
|
||||
{
|
||||
if (type != REG_BINARY)
|
||||
{
|
||||
res = ERROR_UNSUPPORTED_TYPE;
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
size = 0;
|
||||
if (size > size_prev)
|
||||
{
|
||||
size_prev = size;
|
||||
size = 0;
|
||||
res = ERROR_MORE_DATA;
|
||||
}
|
||||
if (size < value.Size())
|
||||
value.ChangeSize_KeepData(size, size);
|
||||
if (res != ERROR_MORE_DATA)
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
LONG CKey::EnumKeys(CSysStringVector &keyNames)
|
||||
{
|
||||
keyNames.Clear();
|
||||
CSysString keyName;
|
||||
for (DWORD index = 0; ; index++)
|
||||
{
|
||||
const unsigned kBufSize = MAX_PATH + 1; // 256 in ATL
|
||||
FILETIME lastWriteTime;
|
||||
DWORD nameSize = kBufSize;
|
||||
const LONG res = ::RegEnumKeyEx(_object, index,
|
||||
keyName.GetBuf(kBufSize), &nameSize,
|
||||
NULL, NULL, NULL, &lastWriteTime);
|
||||
keyName.ReleaseBuf_CalcLen(kBufSize);
|
||||
if (res == ERROR_NO_MORE_ITEMS)
|
||||
return ERROR_SUCCESS;
|
||||
if (res != ERROR_SUCCESS)
|
||||
return res;
|
||||
keyNames.Add(keyName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings)
|
||||
{
|
||||
size_t numChars = 0;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < strings.Size(); i++)
|
||||
numChars += strings[i].Len() + 1;
|
||||
|
||||
CObjArray<wchar_t> buffer(numChars);
|
||||
size_t pos = 0;
|
||||
|
||||
for (i = 0; i < strings.Size(); i++)
|
||||
{
|
||||
const UString &s = strings[i];
|
||||
const size_t size = s.Len() + 1;
|
||||
wmemcpy(buffer + pos, s, size);
|
||||
pos += size;
|
||||
}
|
||||
// if (pos != numChars) return E_FAIL;
|
||||
return SetValue(valueName, buffer, (UInt32)numChars * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings)
|
||||
{
|
||||
strings.Clear();
|
||||
CByteBuffer buffer;
|
||||
const LONG res = QueryValue_Binary(valueName, buffer);
|
||||
if (res != ERROR_SUCCESS)
|
||||
return res;
|
||||
const size_t dataSize = buffer.Size();
|
||||
if (dataSize % sizeof(wchar_t))
|
||||
return ERROR_INVALID_DATA;
|
||||
const wchar_t *data = (const wchar_t *)(const void *)(const Byte *)buffer;
|
||||
const size_t numChars = dataSize / sizeof(wchar_t);
|
||||
// we can check that all names are finished
|
||||
// if (numChars != 0 && data[numChars - 1] != 0) return ERROR_INVALID_DATA;
|
||||
size_t prev = 0;
|
||||
UString s;
|
||||
for (size_t i = 0; i < numChars; i++)
|
||||
{
|
||||
if (data[i] == 0)
|
||||
{
|
||||
s = data + prev;
|
||||
strings.Add(s);
|
||||
prev = i + 1;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,96 @@
|
||||
// Windows/Registry.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_REGISTRY_H
|
||||
#define ZIP7_INC_WINDOWS_REGISTRY_H
|
||||
|
||||
#include "../Common/MyBuffer.h"
|
||||
#include "../Common/MyString.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NRegistry {
|
||||
|
||||
LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value);
|
||||
|
||||
class CKey
|
||||
{
|
||||
HKEY _object;
|
||||
|
||||
LONG QueryValueEx(LPCTSTR lpValueName, LPDWORD lpType,
|
||||
LPBYTE lpData, LPDWORD lpcbData)
|
||||
{
|
||||
return RegQueryValueEx(_object, lpValueName, NULL, lpType, lpData, lpcbData);
|
||||
}
|
||||
|
||||
public:
|
||||
CKey(): _object(NULL) {}
|
||||
~CKey() { Close(); }
|
||||
|
||||
operator HKEY() const { return _object; }
|
||||
void Attach(HKEY key) { _object = key; }
|
||||
HKEY Detach()
|
||||
{
|
||||
const HKEY key = _object;
|
||||
_object = NULL;
|
||||
return key;
|
||||
}
|
||||
|
||||
LONG Create(HKEY parentKey, LPCTSTR keyName,
|
||||
LPTSTR keyClass = REG_NONE,
|
||||
DWORD options = REG_OPTION_NON_VOLATILE,
|
||||
REGSAM accessMask = KEY_ALL_ACCESS,
|
||||
LPSECURITY_ATTRIBUTES securityAttributes = NULL,
|
||||
LPDWORD disposition = NULL) throw();
|
||||
LONG Open(HKEY parentKey, LPCTSTR keyName, REGSAM accessMask = KEY_ALL_ACCESS) throw();
|
||||
|
||||
LONG Close() throw();
|
||||
|
||||
LONG DeleteSubKey(LPCTSTR subKeyName) throw();
|
||||
LONG RecurseDeleteKey(LPCTSTR subKeyName) throw();
|
||||
|
||||
LONG DeleteValue(LPCTSTR name) throw();
|
||||
#ifndef _UNICODE
|
||||
LONG DeleteValue(LPCWSTR name);
|
||||
#endif
|
||||
|
||||
LONG SetValue(LPCTSTR valueName, UInt32 value) throw();
|
||||
LONG SetValue(LPCTSTR valueName, bool value) throw();
|
||||
LONG SetValue(LPCTSTR valueName, LPCTSTR value) throw();
|
||||
// LONG SetValue(LPCTSTR valueName, const CSysString &value);
|
||||
#ifndef _UNICODE
|
||||
LONG SetValue(LPCWSTR name, LPCWSTR value);
|
||||
// LONG SetValue(LPCWSTR name, const UString &value);
|
||||
#endif
|
||||
|
||||
LONG SetValue(LPCTSTR name, const void *value, UInt32 size) throw();
|
||||
|
||||
LONG SetValue_Strings(LPCTSTR valueName, const UStringVector &strings);
|
||||
LONG GetValue_Strings(LPCTSTR valueName, UStringVector &strings);
|
||||
|
||||
LONG SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw();
|
||||
|
||||
// GetValue_[type]_IfOk():
|
||||
// if (return_result == ERROR_SUCCESS), (value) variable was read from registry
|
||||
// if (return_result != ERROR_SUCCESS), (value) variable was not changed
|
||||
LONG GetValue_UInt32_IfOk(LPCTSTR name, UInt32 &value) throw();
|
||||
LONG GetValue_UInt64_IfOk(LPCTSTR name, UInt64 &value) throw();
|
||||
LONG GetValue_bool_IfOk(LPCTSTR name, bool &value) throw();
|
||||
|
||||
// QueryValue():
|
||||
// if (return_result == ERROR_SUCCESS), (value) string was read from registry
|
||||
// if (return_result != ERROR_SUCCESS), (value) string was cleared
|
||||
LONG QueryValue(LPCTSTR name, CSysString &value);
|
||||
#ifndef _UNICODE
|
||||
LONG QueryValue(LPCWSTR name, UString &value);
|
||||
#endif
|
||||
|
||||
// QueryValue_Binary():
|
||||
// if (return_result == ERROR_SUCCESS), (value) buffer was read from registry (BINARY data)
|
||||
// if (return_result != ERROR_SUCCESS), (value) buffer was cleared
|
||||
LONG QueryValue_Binary(LPCTSTR name, CByteBuffer &value);
|
||||
|
||||
LONG EnumKeys(CSysStringVector &keyNames);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,103 @@
|
||||
// Windows/ResourceString.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
#include "../Common/StringConvert.h"
|
||||
#endif
|
||||
|
||||
#include "ResourceString.h"
|
||||
|
||||
extern HINSTANCE g_hInstance;
|
||||
#ifndef _UNICODE
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
|
||||
namespace NWindows {
|
||||
|
||||
#ifndef _UNICODE
|
||||
|
||||
static CSysString MyLoadStringA(HINSTANCE hInstance, UINT resourceID)
|
||||
{
|
||||
CSysString s;
|
||||
int size = 128;
|
||||
int len;
|
||||
do
|
||||
{
|
||||
size <<= 1;
|
||||
len = ::LoadString(hInstance, resourceID, s.GetBuf((unsigned)size - 1), size);
|
||||
}
|
||||
while (size - len <= 1);
|
||||
s.ReleaseBuf_CalcLen((unsigned)len);
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static const int kStartSize = 256;
|
||||
|
||||
static void MyLoadString2(HINSTANCE hInstance, UINT resourceID, UString &s)
|
||||
{
|
||||
int size = kStartSize;
|
||||
int len;
|
||||
do
|
||||
{
|
||||
size <<= 1;
|
||||
len = ::LoadStringW(hInstance, resourceID, s.GetBuf((unsigned)size - 1), size);
|
||||
}
|
||||
while (size - len <= 1);
|
||||
s.ReleaseBuf_CalcLen((unsigned)len);
|
||||
}
|
||||
|
||||
// NT4 doesn't support LoadStringW(,,, 0) to get pointer to resource string. So we don't use it.
|
||||
|
||||
UString MyLoadString(UINT resourceID)
|
||||
{
|
||||
#ifndef _UNICODE
|
||||
if (!g_IsNT)
|
||||
return GetUnicodeString(MyLoadStringA(g_hInstance, resourceID));
|
||||
else
|
||||
#endif
|
||||
{
|
||||
{
|
||||
wchar_t s[kStartSize];
|
||||
s[0] = 0;
|
||||
int len = ::LoadStringW(g_hInstance, resourceID, s, kStartSize);
|
||||
if (kStartSize - len > 1)
|
||||
return s;
|
||||
}
|
||||
UString dest;
|
||||
MyLoadString2(g_hInstance, resourceID, dest);
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
|
||||
void MyLoadString(HINSTANCE hInstance, UINT resourceID, UString &dest)
|
||||
{
|
||||
dest.Empty();
|
||||
#ifndef _UNICODE
|
||||
if (!g_IsNT)
|
||||
MultiByteToUnicodeString2(dest, MyLoadStringA(hInstance, resourceID));
|
||||
else
|
||||
#endif
|
||||
{
|
||||
{
|
||||
wchar_t s[kStartSize];
|
||||
s[0] = 0;
|
||||
int len = ::LoadStringW(hInstance, resourceID, s, kStartSize);
|
||||
if (kStartSize - len > 1)
|
||||
{
|
||||
dest = s;
|
||||
return;
|
||||
}
|
||||
}
|
||||
MyLoadString2(hInstance, resourceID, dest);
|
||||
}
|
||||
}
|
||||
|
||||
void MyLoadString(UINT resourceID, UString &dest)
|
||||
{
|
||||
MyLoadString(g_hInstance, resourceID, dest);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Windows/ResourceString.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_RESOURCE_STRING_H
|
||||
#define ZIP7_INC_WINDOWS_RESOURCE_STRING_H
|
||||
|
||||
#include "../Common/MyString.h"
|
||||
#include "../Common/MyWindows.h"
|
||||
|
||||
namespace NWindows {
|
||||
|
||||
UString MyLoadString(UINT resourceID);
|
||||
void MyLoadString(HINSTANCE hInstance, UINT resourceID, UString &dest);
|
||||
void MyLoadString(UINT resourceID, UString &dest);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,186 @@
|
||||
// Windows/SecurityUtils.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "SecurityUtils.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NSecurity {
|
||||
|
||||
/*
|
||||
bool MyLookupAccountSid(LPCTSTR systemName, PSID sid,
|
||||
CSysString &accountName, CSysString &domainName, PSID_NAME_USE sidNameUse)
|
||||
{
|
||||
DWORD accountNameSize = 0, domainNameSize = 0;
|
||||
|
||||
if (!::LookupAccountSid(systemName, sid,
|
||||
accountName.GetBuf(0), &accountNameSize,
|
||||
domainName.GetBuf(0), &domainNameSize, sidNameUse))
|
||||
{
|
||||
if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
return false;
|
||||
}
|
||||
DWORD accountNameSize2 = accountNameSize, domainNameSize2 = domainNameSize;
|
||||
bool result = BOOLToBool(::LookupAccountSid(systemName, sid,
|
||||
accountName.GetBuf(accountNameSize), &accountNameSize2,
|
||||
domainName.GetBuf(domainNameSize), &domainNameSize2, sidNameUse));
|
||||
accountName.ReleaseBuf_CalcLen(accountNameSize);
|
||||
domainName.ReleaseBuf_CalcLen(domainNameSize);
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
|
||||
static void SetLsaString(LPWSTR src, PLSA_UNICODE_STRING dest)
|
||||
{
|
||||
const size_t len = (size_t)wcslen(src);
|
||||
dest->Length = (USHORT)(len * sizeof(WCHAR));
|
||||
dest->MaximumLength = (USHORT)((len + 1) * sizeof(WCHAR));
|
||||
dest->Buffer = src;
|
||||
}
|
||||
|
||||
/*
|
||||
static void MyLookupSids(CPolicy &policy, PSID ps)
|
||||
{
|
||||
LSA_REFERENCED_DOMAIN_LIST *referencedDomains = NULL;
|
||||
LSA_TRANSLATED_NAME *names = NULL;
|
||||
NTSTATUS nts = policy.LookupSids(1, &ps, &referencedDomains, &names);
|
||||
int res = LsaNtStatusToWinError(nts);
|
||||
LsaFreeMemory(referencedDomains);
|
||||
LsaFreeMemory(names);
|
||||
}
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
|
||||
#ifndef _UNICODE
|
||||
typedef BOOL (WINAPI * Func_LookupAccountNameW)(
|
||||
LPCWSTR lpSystemName,
|
||||
LPCWSTR lpAccountName,
|
||||
PSID Sid,
|
||||
LPDWORD cbSid,
|
||||
LPWSTR ReferencedDomainName,
|
||||
LPDWORD cchReferencedDomainName,
|
||||
PSID_NAME_USE peUse
|
||||
);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static PSID GetSid(LPWSTR accountName)
|
||||
{
|
||||
#ifndef _UNICODE
|
||||
const HMODULE hModule = GetModuleHandle(TEXT("advapi32.dll"));
|
||||
if (!hModule)
|
||||
return NULL;
|
||||
const
|
||||
Func_LookupAccountNameW lookupAccountNameW = Z7_GET_PROC_ADDRESS(
|
||||
Func_LookupAccountNameW, hModule,
|
||||
"LookupAccountNameW");
|
||||
if (!lookupAccountNameW)
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
DWORD sidLen = 0, domainLen = 0;
|
||||
SID_NAME_USE sidNameUse;
|
||||
if (!
|
||||
#ifdef _UNICODE
|
||||
::LookupAccountNameW
|
||||
#else
|
||||
lookupAccountNameW
|
||||
#endif
|
||||
(NULL, accountName, NULL, &sidLen, NULL, &domainLen, &sidNameUse))
|
||||
{
|
||||
if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
const PSID pSid = ::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sidLen);
|
||||
LPWSTR domainName = (LPWSTR)::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (domainLen + 1) * sizeof(WCHAR));
|
||||
const BOOL res =
|
||||
#ifdef _UNICODE
|
||||
::LookupAccountNameW
|
||||
#else
|
||||
lookupAccountNameW
|
||||
#endif
|
||||
(NULL, accountName, pSid, &sidLen, domainName, &domainLen, &sidNameUse);
|
||||
::HeapFree(GetProcessHeap(), 0, domainName);
|
||||
if (res)
|
||||
return pSid;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define Z7_WIN_SE_LOCK_MEMORY_NAME L"SeLockMemoryPrivilege"
|
||||
|
||||
bool AddLockMemoryPrivilege()
|
||||
{
|
||||
CPolicy policy;
|
||||
LSA_OBJECT_ATTRIBUTES attr;
|
||||
attr.Length = sizeof(attr);
|
||||
attr.RootDirectory = NULL;
|
||||
attr.ObjectName = NULL;
|
||||
attr.Attributes = 0;
|
||||
attr.SecurityDescriptor = NULL;
|
||||
attr.SecurityQualityOfService = NULL;
|
||||
if (policy.Open(NULL, &attr,
|
||||
// GENERIC_WRITE)
|
||||
POLICY_ALL_ACCESS)
|
||||
// STANDARD_RIGHTS_REQUIRED,
|
||||
// GENERIC_READ | GENERIC_EXECUTE | POLICY_VIEW_LOCAL_INFORMATION | POLICY_LOOKUP_NAMES)
|
||||
!= 0)
|
||||
return false;
|
||||
LSA_UNICODE_STRING userRights;
|
||||
wchar_t s[128] = Z7_WIN_SE_LOCK_MEMORY_NAME;
|
||||
SetLsaString(s, &userRights);
|
||||
WCHAR userName[256 + 2];
|
||||
DWORD size = 256;
|
||||
if (!GetUserNameW(userName, &size))
|
||||
return false;
|
||||
const PSID psid = GetSid(userName);
|
||||
if (psid == NULL)
|
||||
return false;
|
||||
bool res = false;
|
||||
|
||||
/*
|
||||
PLSA_UNICODE_STRING userRightsArray;
|
||||
ULONG countOfRights;
|
||||
NTSTATUS status = policy.EnumerateAccountRights(psid, &userRightsArray, &countOfRights);
|
||||
if (status != 0)
|
||||
return false;
|
||||
bool finded = false;
|
||||
for (ULONG i = 0; i < countOfRights; i++)
|
||||
{
|
||||
LSA_UNICODE_STRING &ur = userRightsArray[i];
|
||||
if (ur.Length != s.Length() * sizeof(WCHAR))
|
||||
continue;
|
||||
if (wcsncmp(ur.Buffer, s, s.Length()) != 0)
|
||||
continue;
|
||||
finded = true;
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
if (!finded)
|
||||
*/
|
||||
{
|
||||
/*
|
||||
LSA_ENUMERATION_INFORMATION *enums;
|
||||
ULONG countReturned;
|
||||
NTSTATUS status = policy.EnumerateAccountsWithUserRight(&userRights, &enums, &countReturned);
|
||||
if (status == 0)
|
||||
{
|
||||
for (ULONG i = 0; i < countReturned; i++)
|
||||
MyLookupSids(policy, enums[i].Sid);
|
||||
if (enums)
|
||||
::LsaFreeMemory(enums);
|
||||
res = true;
|
||||
}
|
||||
*/
|
||||
const NTSTATUS status = policy.AddAccountRights(psid, &userRights);
|
||||
if (status == 0)
|
||||
res = true;
|
||||
// ULONG res = LsaNtStatusToWinError(status);
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, psid);
|
||||
return res;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,154 @@
|
||||
// Windows/SecurityUtils.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_SECURITY_UTILS_H
|
||||
#define ZIP7_INC_WINDOWS_SECURITY_UTILS_H
|
||||
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#include <ntsecapi.h>
|
||||
#else
|
||||
#include <NTSecAPI.h>
|
||||
#endif
|
||||
|
||||
#include "Defs.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
|
||||
extern "C" {
|
||||
typedef NTSTATUS (NTAPI *Func_LsaOpenPolicy)(PLSA_UNICODE_STRING SystemName,
|
||||
PLSA_OBJECT_ATTRIBUTES ObjectAttributes, ACCESS_MASK DesiredAccess, PLSA_HANDLE PolicyHandle);
|
||||
typedef NTSTATUS (NTAPI *Func_LsaClose)(LSA_HANDLE ObjectHandle);
|
||||
typedef NTSTATUS (NTAPI *Func_LsaAddAccountRights)(LSA_HANDLE PolicyHandle,
|
||||
PSID AccountSid, PLSA_UNICODE_STRING UserRights, ULONG CountOfRights );
|
||||
#define MY_STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L)
|
||||
}
|
||||
|
||||
Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
|
||||
|
||||
#define POLICY_FUNC_CALL(fff, str) \
|
||||
if (hModule == NULL) return MY_STATUS_NOT_IMPLEMENTED; \
|
||||
const Func_ ## fff v = Z7_GET_PROC_ADDRESS(Func_ ## fff, hModule, str); \
|
||||
if (!v) return MY_STATUS_NOT_IMPLEMENTED; \
|
||||
const NTSTATUS res = v
|
||||
|
||||
#else
|
||||
|
||||
#define POLICY_FUNC_CALL(fff, str) \
|
||||
const NTSTATUS res = ::fff
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
namespace NWindows {
|
||||
namespace NSecurity {
|
||||
|
||||
class CAccessToken
|
||||
{
|
||||
HANDLE _handle;
|
||||
public:
|
||||
CAccessToken(): _handle(NULL) {}
|
||||
~CAccessToken() { Close(); }
|
||||
bool Close()
|
||||
{
|
||||
if (_handle == NULL)
|
||||
return true;
|
||||
bool res = BOOLToBool(::CloseHandle(_handle));
|
||||
if (res)
|
||||
_handle = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool OpenProcessToken(HANDLE processHandle, DWORD desiredAccess)
|
||||
{
|
||||
Close();
|
||||
return BOOLToBool(::OpenProcessToken(processHandle, desiredAccess, &_handle));
|
||||
}
|
||||
|
||||
/*
|
||||
bool OpenThreadToken(HANDLE threadHandle, DWORD desiredAccess, bool openAsSelf)
|
||||
{
|
||||
Close();
|
||||
return BOOLToBool(::OpenTreadToken(threadHandle, desiredAccess, BoolToBOOL(anOpenAsSelf), &_handle));
|
||||
}
|
||||
*/
|
||||
|
||||
bool AdjustPrivileges(bool disableAllPrivileges, PTOKEN_PRIVILEGES newState,
|
||||
DWORD bufferLength, PTOKEN_PRIVILEGES previousState, PDWORD returnLength)
|
||||
{ return BOOLToBool(::AdjustTokenPrivileges(_handle, BoolToBOOL(disableAllPrivileges),
|
||||
newState, bufferLength, previousState, returnLength)); }
|
||||
|
||||
bool AdjustPrivileges(bool disableAllPrivileges, PTOKEN_PRIVILEGES newState)
|
||||
{ return AdjustPrivileges(disableAllPrivileges, newState, 0, NULL, NULL); }
|
||||
|
||||
bool AdjustPrivileges(PTOKEN_PRIVILEGES newState)
|
||||
{ return AdjustPrivileges(false, newState); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct CPolicy
|
||||
{
|
||||
protected:
|
||||
LSA_HANDLE _handle;
|
||||
#ifndef _UNICODE
|
||||
HMODULE hModule;
|
||||
#endif
|
||||
public:
|
||||
operator LSA_HANDLE() const { return _handle; }
|
||||
CPolicy(): _handle(NULL)
|
||||
{
|
||||
#ifndef _UNICODE
|
||||
hModule = GetModuleHandle(TEXT("advapi32.dll"));
|
||||
#endif
|
||||
}
|
||||
~CPolicy() { Close(); }
|
||||
|
||||
NTSTATUS Open(PLSA_UNICODE_STRING systemName, PLSA_OBJECT_ATTRIBUTES objectAttributes,
|
||||
ACCESS_MASK desiredAccess)
|
||||
{
|
||||
Close();
|
||||
POLICY_FUNC_CALL (LsaOpenPolicy, "LsaOpenPolicy")
|
||||
(systemName, objectAttributes, desiredAccess, &_handle);
|
||||
return res;
|
||||
}
|
||||
|
||||
NTSTATUS Close()
|
||||
{
|
||||
if (_handle == NULL)
|
||||
return 0;
|
||||
POLICY_FUNC_CALL (LsaClose, "LsaClose")
|
||||
(_handle);
|
||||
_handle = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
NTSTATUS EnumerateAccountsWithUserRight(PLSA_UNICODE_STRING userRights,
|
||||
PLSA_ENUMERATION_INFORMATION *enumerationBuffer, PULONG countReturned)
|
||||
{ return LsaEnumerateAccountsWithUserRight(_handle, userRights, (void **)enumerationBuffer, countReturned); }
|
||||
|
||||
NTSTATUS EnumerateAccountRights(PSID sid, PLSA_UNICODE_STRING* userRights, PULONG countOfRights)
|
||||
{ return ::LsaEnumerateAccountRights(_handle, sid, userRights, countOfRights); }
|
||||
|
||||
NTSTATUS LookupSids(ULONG count, PSID* sids,
|
||||
PLSA_REFERENCED_DOMAIN_LIST* referencedDomains, PLSA_TRANSLATED_NAME* names)
|
||||
{ return LsaLookupSids(_handle, count, sids, referencedDomains, names); }
|
||||
|
||||
NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights, ULONG countOfRights)
|
||||
{
|
||||
POLICY_FUNC_CALL (LsaAddAccountRights, "LsaAddAccountRights")
|
||||
(_handle, accountSid, userRights, countOfRights);
|
||||
return res;
|
||||
}
|
||||
NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights)
|
||||
{ return AddAccountRights(accountSid, userRights, 1); }
|
||||
|
||||
NTSTATUS RemoveAccountRights(PSID accountSid, bool allRights, PLSA_UNICODE_STRING userRights, ULONG countOfRights)
|
||||
{ return LsaRemoveAccountRights(_handle, accountSid, (BOOLEAN)(allRights ? TRUE : FALSE), userRights, countOfRights); }
|
||||
};
|
||||
|
||||
bool AddLockMemoryPrivilege();
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,839 @@
|
||||
// Windows/Shell.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/MyCom.h"
|
||||
#include "../Common/StringConvert.h"
|
||||
|
||||
#include "COM.h"
|
||||
#include "FileName.h"
|
||||
#include "MemoryGlobal.h"
|
||||
#include "Shell.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
|
||||
// MSVC6 and old SDK don't support this function:
|
||||
// #define LWSTDAPI EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE
|
||||
// LWSTDAPI StrRetToStrW(STRRET *pstr, LPCITEMIDLIST pidl, LPWSTR *ppsz);
|
||||
|
||||
// #define SHOW_DEBUG_SHELL
|
||||
|
||||
#ifdef SHOW_DEBUG_SHELL
|
||||
|
||||
#include "../Common/IntToString.h"
|
||||
|
||||
static void Print_Number(UInt32 number, const char *s)
|
||||
{
|
||||
AString s2;
|
||||
s2.Add_UInt32(number);
|
||||
s2.Add_Space();
|
||||
s2 += s;
|
||||
OutputDebugStringA(s2);
|
||||
}
|
||||
|
||||
#define ODS(sz) { OutputDebugStringA(sz); }
|
||||
#define ODS_U(s) { OutputDebugStringW(s); }
|
||||
#define ODS_(op) { op; }
|
||||
|
||||
#else
|
||||
|
||||
#define ODS(sz)
|
||||
#define ODS_U(s)
|
||||
#define ODS_(op)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
namespace NWindows {
|
||||
namespace NShell {
|
||||
|
||||
#ifndef UNDER_CE
|
||||
|
||||
// SHGetMalloc is unsupported in Windows Mobile?
|
||||
|
||||
void CItemIDList::Free()
|
||||
{
|
||||
if (!m_Object)
|
||||
return;
|
||||
/* DOCs:
|
||||
SHGetMalloc was introduced in Windows 95 and Microsoft Windows NT 4.0,
|
||||
but as of Windows 2000 it is no longer necessary.
|
||||
In its place, programs can call the equivalent (and easier to use) CoTaskMemAlloc and CoTaskMemFree.
|
||||
Description from oldnewthings:
|
||||
shell functions could work without COM (if OLE32.DLL is not loaded),
|
||||
but now if OLE32.DLL is loaded, then shell functions and com functions do same things.
|
||||
22.02: so we use OLE32.DLL function to free memory:
|
||||
*/
|
||||
/*
|
||||
CMyComPtr<IMalloc> shellMalloc;
|
||||
if (::SHGetMalloc(&shellMalloc) != NOERROR)
|
||||
throw 41099;
|
||||
shellMalloc->Free(m_Object);
|
||||
*/
|
||||
CoTaskMemFree(m_Object);
|
||||
m_Object = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
CItemIDList::(LPCITEMIDLIST itemIDList): m_Object(NULL)
|
||||
{ *this = itemIDList; }
|
||||
CItemIDList::(const CItemIDList& itemIDList): m_Object(NULL)
|
||||
{ *this = itemIDList; }
|
||||
|
||||
CItemIDList& CItemIDList::operator=(LPCITEMIDLIST object)
|
||||
{
|
||||
Free();
|
||||
if (object != 0)
|
||||
{
|
||||
UINT32 size = GetSize(object);
|
||||
m_Object = (LPITEMIDLIST)CoTaskMemAlloc(size);
|
||||
if (m_Object != NULL)
|
||||
MoveMemory(m_Object, object, size);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
CItemIDList& CItemIDList::operator=(const CItemIDList &object)
|
||||
{
|
||||
Free();
|
||||
if (object.m_Object != NULL)
|
||||
{
|
||||
UINT32 size = GetSize(object.m_Object);
|
||||
m_Object = (LPITEMIDLIST)CoTaskMemAlloc(size);
|
||||
if (m_Object != NULL)
|
||||
MoveMemory(m_Object, object.m_Object, size);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
static HRESULT ReadUnicodeStrings(const wchar_t *p, size_t size, UStringVector &names)
|
||||
{
|
||||
names.Clear();
|
||||
const wchar_t *lim = p + size;
|
||||
UString s;
|
||||
/*
|
||||
if (size == 0 || p[size - 1] != 0)
|
||||
return E_INVALIDARG;
|
||||
if (size == 1)
|
||||
return S_OK;
|
||||
if (p[size - 2] != 0)
|
||||
return E_INVALIDARG;
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
const wchar_t *start = p;
|
||||
for (;;)
|
||||
{
|
||||
if (p == lim) return E_INVALIDARG; // S_FALSE
|
||||
if (*p++ == 0)
|
||||
break;
|
||||
}
|
||||
const size_t num = (size_t)(p - start);
|
||||
if (num == 1)
|
||||
{
|
||||
if (p != lim) return E_INVALIDARG; // S_FALSE
|
||||
return S_OK;
|
||||
}
|
||||
s.SetFrom(start, (unsigned)(num - 1));
|
||||
ODS_U(s)
|
||||
names.Add(s);
|
||||
// names.ReserveOnePosition();
|
||||
// names.AddInReserved_Ptr_of_new(new UString((unsigned)num - 1, start));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static HRESULT ReadAnsiStrings(const char *p, size_t size, UStringVector &names)
|
||||
{
|
||||
names.Clear();
|
||||
AString name;
|
||||
for (; size != 0; size--)
|
||||
{
|
||||
const char c = *p++;
|
||||
if (c == 0)
|
||||
{
|
||||
if (name.IsEmpty())
|
||||
return S_OK;
|
||||
names.Add(GetUnicodeString(name));
|
||||
name.Empty();
|
||||
}
|
||||
else
|
||||
name.Add_Char(c);
|
||||
}
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
|
||||
#define INIT_FORMATETC_HGLOBAL(type) { (type), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }
|
||||
|
||||
static HRESULT DataObject_GetData_HGLOBAL(IDataObject *dataObject, CLIPFORMAT cf, NCOM::CStgMedium &medium)
|
||||
{
|
||||
FORMATETC etc = INIT_FORMATETC_HGLOBAL(cf);
|
||||
RINOK(dataObject->GetData(&etc, &medium))
|
||||
if (medium.tymed != TYMED_HGLOBAL)
|
||||
return E_INVALIDARG;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT DataObject_GetData_HDROP_Names(IDataObject *dataObject, UStringVector &names)
|
||||
{
|
||||
names.Clear();
|
||||
NCOM::CStgMedium medium;
|
||||
|
||||
/* Win10 : if (dataObject) is from IContextMenu::Initialize() and
|
||||
if (len_of_path >= MAX_PATH (260) for some file in data object)
|
||||
{
|
||||
GetData() returns HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
|
||||
"The data area passed to a system call is too small",
|
||||
Is there a way to fix this code for long paths?
|
||||
} */
|
||||
|
||||
RINOK(DataObject_GetData_HGLOBAL(dataObject, CF_HDROP, medium))
|
||||
const size_t blockSize = GlobalSize(medium.hGlobal);
|
||||
if (blockSize < sizeof(DROPFILES))
|
||||
return E_INVALIDARG;
|
||||
NMemory::CGlobalLock dropLock(medium.hGlobal);
|
||||
const DROPFILES *dropFiles = (const DROPFILES *)dropLock.GetPointer();
|
||||
if (!dropFiles)
|
||||
return E_INVALIDARG;
|
||||
if (blockSize < dropFiles->pFiles
|
||||
|| dropFiles->pFiles < sizeof(DROPFILES)
|
||||
// || dropFiles->pFiles != sizeof(DROPFILES)
|
||||
)
|
||||
return E_INVALIDARG;
|
||||
const size_t size = blockSize - dropFiles->pFiles;
|
||||
const void *namesData = (const Byte *)(const void *)dropFiles + dropFiles->pFiles;
|
||||
HRESULT hres;
|
||||
if (dropFiles->fWide)
|
||||
{
|
||||
if (size % sizeof(wchar_t) != 0)
|
||||
return E_INVALIDARG;
|
||||
hres = ReadUnicodeStrings((const wchar_t *)namesData, size / sizeof(wchar_t), names);
|
||||
}
|
||||
else
|
||||
hres = ReadAnsiStrings((const char *)namesData, size, names);
|
||||
|
||||
ODS_(Print_Number(names.Size(), "DataObject_GetData_HDROP_Names"))
|
||||
return hres;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// CF_IDLIST:
|
||||
#define MYWIN_CFSTR_SHELLIDLIST TEXT("Shell IDList Array")
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT cidl;
|
||||
UINT aoffset[1];
|
||||
} MYWIN_CIDA;
|
||||
/*
|
||||
cidl : number of PIDLs that are being transferred, not including the parent folder.
|
||||
aoffset : An array of offsets, relative to the beginning of this structure.
|
||||
aoffset[0] - fully qualified PIDL of a parent folder.
|
||||
If this PIDL is empty, the parent folder is the desktop.
|
||||
aoffset[1] ... aoffset[cidl] : offset to one of the PIDLs to be transferred.
|
||||
All of these PIDLs are relative to the PIDL of the parent folder.
|
||||
*/
|
||||
|
||||
static HRESULT DataObject_GetData_IDLIST(IDataObject *dataObject, UStringVector &names)
|
||||
{
|
||||
names.Clear();
|
||||
NCOM::CStgMedium medium;
|
||||
RINOK(DataObject_GetData_HGLOBAL(dataObject, (CLIPFORMAT)
|
||||
RegisterClipboardFormat(MYWIN_CFSTR_SHELLIDLIST), medium))
|
||||
const size_t blockSize = GlobalSize(medium.hGlobal);
|
||||
if (blockSize < sizeof(MYWIN_CIDA) || blockSize >= (UInt32)((UInt32)0 - 1))
|
||||
return E_INVALIDARG;
|
||||
NMemory::CGlobalLock dropLock(medium.hGlobal);
|
||||
const MYWIN_CIDA *cida = (const MYWIN_CIDA *)dropLock.GetPointer();
|
||||
if (!cida)
|
||||
return E_INVALIDARG;
|
||||
if (cida->cidl == 0)
|
||||
{
|
||||
// is it posssible to have no selected items?
|
||||
// it's unexpected case.
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if (cida->cidl >= (blockSize - (UInt32)sizeof(MYWIN_CIDA)) / sizeof(UINT))
|
||||
return E_INVALIDARG;
|
||||
const UInt32 start = cida->cidl * (UInt32)sizeof(UINT) + (UInt32)sizeof(MYWIN_CIDA);
|
||||
|
||||
STRRET strret;
|
||||
CMyComPtr<IShellFolder> parentFolder;
|
||||
{
|
||||
const UINT offset = cida->aoffset[0];
|
||||
if (offset < start || offset >= blockSize
|
||||
// || offset != start
|
||||
)
|
||||
return E_INVALIDARG;
|
||||
|
||||
CMyComPtr<IShellFolder> desktopFolder;
|
||||
RINOK(::SHGetDesktopFolder(&desktopFolder))
|
||||
if (!desktopFolder)
|
||||
return E_FAIL;
|
||||
|
||||
LPCITEMIDLIST const lpcItem = (LPCITEMIDLIST)(const void *)((const Byte *)cida + offset);
|
||||
|
||||
#ifdef SHOW_DEBUG_SHELL
|
||||
{
|
||||
const HRESULT res = desktopFolder->GetDisplayNameOf(
|
||||
lpcItem, SHGDN_FORPARSING, &strret);
|
||||
if (res == S_OK && strret.uType == STRRET_WSTR)
|
||||
{
|
||||
ODS_U(strret.pOleStr)
|
||||
/* if lpcItem is empty, the path will be
|
||||
"C:\Users\user_name\Desktop"
|
||||
if lpcItem is "My Computer" folder, the path will be
|
||||
"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" */
|
||||
CoTaskMemFree(strret.pOleStr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
RINOK(desktopFolder->BindToObject(lpcItem,
|
||||
NULL, IID_IShellFolder, (void **)&parentFolder))
|
||||
if (!parentFolder)
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
names.ClearAndReserve(cida->cidl);
|
||||
UString path;
|
||||
|
||||
// for (int y = 0; y < 1; y++) // for debug
|
||||
for (unsigned i = 1; i <= cida->cidl; i++)
|
||||
{
|
||||
const UINT offset = cida->aoffset[i];
|
||||
if (offset < start || offset >= blockSize)
|
||||
return E_INVALIDARG;
|
||||
const void *p = (const Byte *)(const void *)cida + offset;
|
||||
/* ITEMIDLIST of file can contain more than one SHITEMID item.
|
||||
In win10 only SHGDN_FORPARSING returns path that contains
|
||||
all path parts related to parts of ITEMIDLIST.
|
||||
So we can use only SHGDN_FORPARSING here.
|
||||
Don't use (SHGDN_INFOLDER)
|
||||
Don't use (SHGDN_INFOLDER | SHGDN_FORPARSING)
|
||||
*/
|
||||
RINOK(parentFolder->GetDisplayNameOf((LPCITEMIDLIST)p, SHGDN_FORPARSING, &strret))
|
||||
|
||||
/*
|
||||
// MSVC6 and old SDK do not support StrRetToStrW().
|
||||
LPWSTR lpstr;
|
||||
RINOK (StrRetToStrW(&strret, NULL, &lpstr))
|
||||
ODS_U(lpstr)
|
||||
path = lpstr;
|
||||
CoTaskMemFree(lpstr);
|
||||
*/
|
||||
if (strret.uType != STRRET_WSTR)
|
||||
return E_INVALIDARG;
|
||||
ODS_U(strret.pOleStr)
|
||||
path = strret.pOleStr;
|
||||
// the path could have super path prefix "\\\\?\\"
|
||||
// we can remove super path prefix here, if we don't need that prefix
|
||||
#ifdef Z7_LONG_PATH
|
||||
// we remove super prefix, if we can work without that prefix
|
||||
NFile::NName::If_IsSuperPath_RemoveSuperPrefix(path);
|
||||
#endif
|
||||
names.AddInReserved(path);
|
||||
CoTaskMemFree(strret.pOleStr);
|
||||
}
|
||||
|
||||
ODS_(Print_Number(cida->cidl, "CFSTR_SHELLIDLIST END"))
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT DataObject_GetData_HDROP_or_IDLIST_Names(IDataObject *dataObject, UStringVector &paths)
|
||||
{
|
||||
ODS("-- DataObject_GetData_HDROP_or_IDLIST_Names START")
|
||||
HRESULT hres = NShell::DataObject_GetData_HDROP_Names(dataObject, paths);
|
||||
// if (hres == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
|
||||
if (hres != S_OK)
|
||||
{
|
||||
ODS("-- DataObject_GetData_IDLIST START")
|
||||
// for (int y = 0; y < 10000; y++) // for debug
|
||||
hres = NShell::DataObject_GetData_IDLIST(dataObject, paths);
|
||||
}
|
||||
ODS("-- DataObject_GetData_HDROP_or_IDLIST_Names END")
|
||||
return hres;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// #if (NTDDI_VERSION >= NTDDI_VISTA)
|
||||
typedef struct
|
||||
{
|
||||
UINT cItems; // number of items in rgdwFileAttributes array
|
||||
DWORD dwSumFileAttributes; // all of the attributes ORed together
|
||||
DWORD dwProductFileAttributes; // all of the attributes ANDed together
|
||||
DWORD rgdwFileAttributes[1]; // array
|
||||
} MYWIN_FILE_ATTRIBUTES_ARRAY;
|
||||
|
||||
#define MYWIN_CFSTR_FILE_ATTRIBUTES_ARRAY TEXT("File Attributes Array")
|
||||
|
||||
HRESULT DataObject_GetData_FILE_ATTRS(IDataObject *dataObject, CFileAttribs &attribs)
|
||||
{
|
||||
attribs.Clear();
|
||||
NCOM::CStgMedium medium;
|
||||
RINOK(DataObject_GetData_HGLOBAL(dataObject, (CLIPFORMAT)
|
||||
RegisterClipboardFormat(MYWIN_CFSTR_FILE_ATTRIBUTES_ARRAY), medium))
|
||||
const size_t blockSize = GlobalSize(medium.hGlobal);
|
||||
if (blockSize < sizeof(MYWIN_FILE_ATTRIBUTES_ARRAY))
|
||||
return E_INVALIDARG;
|
||||
NMemory::CGlobalLock dropLock(medium.hGlobal);
|
||||
const MYWIN_FILE_ATTRIBUTES_ARRAY *faa = (const MYWIN_FILE_ATTRIBUTES_ARRAY *)dropLock.GetPointer();
|
||||
if (!faa)
|
||||
return E_INVALIDARG;
|
||||
const unsigned numFiles = faa->cItems;
|
||||
if (numFiles == 0)
|
||||
{
|
||||
// is it posssible to have empty array here?
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if ((blockSize - (sizeof(MYWIN_FILE_ATTRIBUTES_ARRAY) - sizeof(DWORD)))
|
||||
/ sizeof(DWORD) != numFiles)
|
||||
return E_INVALIDARG;
|
||||
// attribs.Sum = faa->dwSumFileAttributes;
|
||||
// attribs.Product = faa->dwProductFileAttributes;
|
||||
// attribs.Vals.SetFromArray(faa->rgdwFileAttributes, numFiles);
|
||||
// attribs.IsDirVector.ClearAndSetSize(numFiles);
|
||||
|
||||
if ((faa->dwSumFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
|
||||
{
|
||||
/* in win10: if selected items are volumes (c:\, d:\ ..) in My Compter,
|
||||
all items have FILE_ATTRIBUTE_DIRECTORY attribute
|
||||
ntfs volume also have FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM
|
||||
udf volume: FILE_ATTRIBUTE_READONLY
|
||||
dvd-rom device: (-1) : all bits are set
|
||||
*/
|
||||
const DWORD *attr = faa->rgdwFileAttributes;
|
||||
// DWORD product = (UInt32)0 - 1, sum = 0;
|
||||
for (unsigned i = 0; i < numFiles; i++)
|
||||
{
|
||||
if (attr[i] & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
// attribs.ThereAreDirs = true;
|
||||
attribs.FirstDirIndex = (int)i;
|
||||
break;
|
||||
}
|
||||
// attribs.IsDirVector[i] = (attr[i] & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
// product &= v;
|
||||
// sum |= v;
|
||||
}
|
||||
// ODS_(Print_Number(product, "Product calc FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names"))
|
||||
// ODS_(Print_Number(sum, "Sum calc FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names"))
|
||||
}
|
||||
// ODS_(Print_Number(attribs.Product, "Product FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names"))
|
||||
// ODS_(Print_Number(attribs.Sum, "Sum FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names"))
|
||||
ODS_(Print_Number(numFiles, "FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names"))
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////
|
||||
// CDrop
|
||||
|
||||
/*
|
||||
win10:
|
||||
DragQueryFile() implementation code is not effective because
|
||||
there is no pointer inside DROP internal file list, so
|
||||
DragQueryFile(fileIndex) runs all names in range [0, fileIndex].
|
||||
DragQueryFile(,, buf, bufSize)
|
||||
if (buf == NULL) by spec
|
||||
{
|
||||
returns value is the required size
|
||||
in characters, of the buffer, not including the terminating null character
|
||||
tests show that if (bufSize == 0), then it also returns required size.
|
||||
}
|
||||
if (bufSize != NULL)
|
||||
{
|
||||
returns: the count of the characters copied, not including null character.
|
||||
win10: null character is also copied at position buf[ret_count];
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
void CDrop::Attach(HDROP object)
|
||||
{
|
||||
Free();
|
||||
m_Object = object;
|
||||
m_Assigned = true;
|
||||
}
|
||||
|
||||
void CDrop::Free()
|
||||
{
|
||||
if (m_MustBeFinished && m_Assigned)
|
||||
Finish();
|
||||
m_Assigned = false;
|
||||
}
|
||||
|
||||
UINT CDrop::QueryCountOfFiles()
|
||||
{
|
||||
return QueryFile(0xFFFFFFFF, (LPTSTR)NULL, 0);
|
||||
}
|
||||
|
||||
void CDrop::QueryFileName(UINT fileIndex, UString &fileName)
|
||||
{
|
||||
#ifndef _UNICODE
|
||||
if (!g_IsNT)
|
||||
{
|
||||
AString fileNameA;
|
||||
const UINT len = QueryFile(fileIndex, (LPTSTR)NULL, 0);
|
||||
const UINT numCopied = QueryFile(fileIndex, fileNameA.GetBuf(len + 2), len + 2);
|
||||
fileNameA.ReleaseBuf_CalcLen(len);
|
||||
if (numCopied != len)
|
||||
throw 20221223;
|
||||
fileName = GetUnicodeString(fileNameA);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// kReserve must be >= 3 for additional buffer size
|
||||
// safety and for optimal performance
|
||||
const unsigned kReserve = 3;
|
||||
{
|
||||
unsigned len = 0;
|
||||
wchar_t *buf = fileName.GetBuf_GetMaxAvail(len);
|
||||
if (len >= kReserve)
|
||||
{
|
||||
const UINT numCopied = QueryFile(fileIndex, buf, len);
|
||||
if (numCopied < len - 1)
|
||||
{
|
||||
// (numCopied < len - 1) case means that it have copied full string.
|
||||
fileName.ReleaseBuf_CalcLen(numCopied);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
const UINT len = QueryFile(fileIndex, (LPWSTR)NULL, 0);
|
||||
const UINT numCopied = QueryFile(fileIndex,
|
||||
fileName.GetBuf(len + kReserve), len + kReserve);
|
||||
fileName.ReleaseBuf_CalcLen(len);
|
||||
if (numCopied != len)
|
||||
throw 20221223;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CDrop::QueryFileNames(UStringVector &fileNames)
|
||||
{
|
||||
UINT numFiles = QueryCountOfFiles();
|
||||
|
||||
Print_Number(numFiles, "\n====== CDrop::QueryFileNames START ===== \n");
|
||||
|
||||
fileNames.ClearAndReserve(numFiles);
|
||||
UString s;
|
||||
for (UINT i = 0; i < numFiles; i++)
|
||||
{
|
||||
QueryFileName(i, s);
|
||||
if (!s.IsEmpty())
|
||||
fileNames.AddInReserved(s);
|
||||
}
|
||||
Print_Number(numFiles, "\n====== CDrop::QueryFileNames END ===== \n");
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// #if (NTDDI_VERSION >= NTDDI_VISTA)
|
||||
// SHGetPathFromIDListEx returns a win32 file system path for the item in the name space.
|
||||
typedef int Z7_WIN_GPFIDL_FLAGS;
|
||||
|
||||
extern "C" {
|
||||
#ifndef _UNICODE
|
||||
typedef BOOL (WINAPI * Func_SHGetPathFromIDListW)(LPCITEMIDLIST pidl, LPWSTR pszPath); // nt4
|
||||
#endif
|
||||
|
||||
#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0600 // Vista
|
||||
#define Z7_USE_DYN_SHGetPathFromIDListEx
|
||||
#endif
|
||||
|
||||
#ifdef Z7_USE_DYN_SHGetPathFromIDListEx
|
||||
Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
|
||||
typedef BOOL (WINAPI * Func_SHGetPathFromIDListEx)(LPCITEMIDLIST pidl, PWSTR pszPath, DWORD cchPath, Z7_WIN_GPFIDL_FLAGS uOpts); // vista
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
|
||||
bool GetPathFromIDList(LPCITEMIDLIST itemIDList, AString &path)
|
||||
{
|
||||
path.Empty();
|
||||
const unsigned len = MAX_PATH + 16;
|
||||
const bool result = BOOLToBool(::SHGetPathFromIDList(itemIDList, path.GetBuf(len)));
|
||||
path.ReleaseBuf_CalcLen(len);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path)
|
||||
{
|
||||
path.Empty();
|
||||
unsigned len = MAX_PATH + 16;
|
||||
|
||||
#ifdef _UNICODE
|
||||
bool result = BOOLToBool(::SHGetPathFromIDList(itemIDList, path.GetBuf(len)));
|
||||
#else
|
||||
const
|
||||
Func_SHGetPathFromIDListW
|
||||
shGetPathFromIDListW = Z7_GET_PROC_ADDRESS(
|
||||
Func_SHGetPathFromIDListW, ::GetModuleHandleW(L"shell32.dll"),
|
||||
"SHGetPathFromIDListW");
|
||||
if (!shGetPathFromIDListW)
|
||||
return false;
|
||||
bool result = BOOLToBool(shGetPathFromIDListW(itemIDList, path.GetBuf(len)));
|
||||
#endif
|
||||
|
||||
if (!result)
|
||||
{
|
||||
ODS("==== GetPathFromIDList() SHGetPathFromIDList() returned false")
|
||||
/* for long path we need SHGetPathFromIDListEx().
|
||||
win10: SHGetPathFromIDListEx() for long path returns path with
|
||||
with super path prefix "\\\\?\\". */
|
||||
#ifdef Z7_USE_DYN_SHGetPathFromIDListEx
|
||||
const
|
||||
Func_SHGetPathFromIDListEx
|
||||
func_SHGetPathFromIDListEx = Z7_GET_PROC_ADDRESS(
|
||||
Func_SHGetPathFromIDListEx, ::GetModuleHandleW(L"shell32.dll"),
|
||||
"SHGetPathFromIDListEx");
|
||||
if (func_SHGetPathFromIDListEx)
|
||||
#endif
|
||||
{
|
||||
ODS("==== GetPathFromIDList() (SHGetPathFromIDListEx)")
|
||||
do
|
||||
{
|
||||
len *= 4;
|
||||
result = BOOLToBool(
|
||||
#ifdef Z7_USE_DYN_SHGetPathFromIDListEx
|
||||
func_SHGetPathFromIDListEx
|
||||
#else
|
||||
SHGetPathFromIDListEx
|
||||
#endif
|
||||
(itemIDList, path.GetBuf(len), len, 0));
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
while (len <= (1 << 16));
|
||||
}
|
||||
}
|
||||
|
||||
path.ReleaseBuf_CalcLen(len);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef UNDER_CE
|
||||
|
||||
bool BrowseForFolder(LPBROWSEINFO, CSysString)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BrowseForFolder(HWND, LPCTSTR, UINT, LPCTSTR, CSysString &)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BrowseForFolder(HWND /* owner */, LPCTSTR /* title */,
|
||||
LPCTSTR /* initialFolder */, CSysString & /* resultPath */)
|
||||
{
|
||||
/*
|
||||
// SHBrowseForFolder doesn't work before CE 6.0 ?
|
||||
if (GetProcAddress(LoadLibrary(L"ceshell.dll", L"SHBrowseForFolder") == 0)
|
||||
MessageBoxW(0, L"no", L"", 0);
|
||||
else
|
||||
MessageBoxW(0, L"yes", L"", 0);
|
||||
*/
|
||||
/*
|
||||
UString s = "all files";
|
||||
s += " (*.*)";
|
||||
return MyGetOpenFileName(owner, title, initialFolder, s, resultPath, true);
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* win10: SHBrowseForFolder() doesn't support long paths,
|
||||
even if long path suppport is enabled in registry and in manifest.
|
||||
and SHBrowseForFolder() doesn't support super path prefix "\\\\?\\". */
|
||||
|
||||
bool BrowseForFolder(LPBROWSEINFO browseInfo, CSysString &resultPath)
|
||||
{
|
||||
resultPath.Empty();
|
||||
NWindows::NCOM::CComInitializer comInitializer;
|
||||
LPITEMIDLIST itemIDList = ::SHBrowseForFolder(browseInfo);
|
||||
if (!itemIDList)
|
||||
return false;
|
||||
CItemIDList itemIDListHolder;
|
||||
itemIDListHolder.Attach(itemIDList);
|
||||
return GetPathFromIDList(itemIDList, resultPath);
|
||||
}
|
||||
|
||||
|
||||
static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data)
|
||||
{
|
||||
#ifndef UNDER_CE
|
||||
switch (uMsg)
|
||||
{
|
||||
case BFFM_INITIALIZED:
|
||||
{
|
||||
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, data);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
case BFFM_SELCHANGED:
|
||||
{
|
||||
TCHAR dir[MAX_PATH];
|
||||
if (::SHGetPathFromIDList((LPITEMIDLIST) lp , dir))
|
||||
SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)dir);
|
||||
else
|
||||
SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)TEXT(""));
|
||||
break;
|
||||
}
|
||||
*/
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static bool BrowseForFolder(HWND owner, LPCTSTR title, UINT ulFlags,
|
||||
LPCTSTR initialFolder, CSysString &resultPath)
|
||||
{
|
||||
CSysString displayName;
|
||||
BROWSEINFO browseInfo;
|
||||
browseInfo.hwndOwner = owner;
|
||||
browseInfo.pidlRoot = NULL;
|
||||
|
||||
// there are Unicode/Astring problems in some WinCE SDK ?
|
||||
/*
|
||||
#ifdef UNDER_CE
|
||||
browseInfo.pszDisplayName = (LPSTR)displayName.GetBuf(MAX_PATH);
|
||||
browseInfo.lpszTitle = (LPCSTR)title;
|
||||
#else
|
||||
*/
|
||||
browseInfo.pszDisplayName = displayName.GetBuf(MAX_PATH);
|
||||
browseInfo.lpszTitle = title;
|
||||
// #endif
|
||||
browseInfo.ulFlags = ulFlags;
|
||||
browseInfo.lpfn = initialFolder ? BrowseCallbackProc : NULL;
|
||||
browseInfo.lParam = (LPARAM)initialFolder;
|
||||
return BrowseForFolder(&browseInfo, resultPath);
|
||||
}
|
||||
|
||||
#ifdef Z7_OLD_WIN_SDK
|
||||
// ShlObj.h:
|
||||
#ifndef BIF_NEWDIALOGSTYLE
|
||||
#define BIF_NEWDIALOGSTYLE 0x0040
|
||||
#endif
|
||||
#endif
|
||||
|
||||
bool BrowseForFolder(HWND owner, LPCTSTR title,
|
||||
LPCTSTR initialFolder, CSysString &resultPath)
|
||||
{
|
||||
return BrowseForFolder(owner, title,
|
||||
#ifndef UNDER_CE
|
||||
BIF_NEWDIALOGSTYLE |
|
||||
#endif
|
||||
BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT, initialFolder, resultPath);
|
||||
// BIF_STATUSTEXT; BIF_USENEWUI (Version 5.0)
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
|
||||
extern "C" {
|
||||
typedef LPITEMIDLIST (WINAPI * Func_SHBrowseForFolderW)(LPBROWSEINFOW lpbi);
|
||||
}
|
||||
|
||||
static bool BrowseForFolder(LPBROWSEINFOW browseInfo, UString &resultPath)
|
||||
{
|
||||
NWindows::NCOM::CComInitializer comInitializer;
|
||||
const
|
||||
Func_SHBrowseForFolderW
|
||||
f_SHBrowseForFolderW = Z7_GET_PROC_ADDRESS(
|
||||
Func_SHBrowseForFolderW, ::GetModuleHandleW(L"shell32.dll"),
|
||||
"SHBrowseForFolderW");
|
||||
if (!f_SHBrowseForFolderW)
|
||||
return false;
|
||||
LPITEMIDLIST itemIDList = f_SHBrowseForFolderW(browseInfo);
|
||||
if (!itemIDList)
|
||||
return false;
|
||||
CItemIDList itemIDListHolder;
|
||||
itemIDListHolder.Attach(itemIDList);
|
||||
return GetPathFromIDList(itemIDList, resultPath);
|
||||
}
|
||||
|
||||
static
|
||||
int CALLBACK BrowseCallbackProc2(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case BFFM_INITIALIZED:
|
||||
{
|
||||
SendMessageW(hwnd, BFFM_SETSELECTIONW, TRUE, data);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
case BFFM_SELCHANGED:
|
||||
{
|
||||
wchar_t dir[MAX_PATH * 2];
|
||||
|
||||
if (shGetPathFromIDListW((LPITEMIDLIST)lp , dir))
|
||||
SendMessageW(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)dir);
|
||||
else
|
||||
SendMessageW(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)L"");
|
||||
break;
|
||||
}
|
||||
*/
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static bool BrowseForFolder(HWND owner, LPCWSTR title, UINT ulFlags,
|
||||
LPCWSTR initialFolder, UString &resultPath)
|
||||
{
|
||||
UString displayName;
|
||||
BROWSEINFOW browseInfo;
|
||||
browseInfo.hwndOwner = owner;
|
||||
browseInfo.pidlRoot = NULL;
|
||||
browseInfo.pszDisplayName = displayName.GetBuf(MAX_PATH);
|
||||
browseInfo.lpszTitle = title;
|
||||
browseInfo.ulFlags = ulFlags;
|
||||
browseInfo.lpfn = initialFolder ? BrowseCallbackProc2 : NULL;
|
||||
browseInfo.lParam = (LPARAM)initialFolder;
|
||||
return BrowseForFolder(&browseInfo, resultPath);
|
||||
}
|
||||
|
||||
bool BrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR initialFolder, UString &resultPath)
|
||||
{
|
||||
if (g_IsNT)
|
||||
return BrowseForFolder(owner, title,
|
||||
BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS
|
||||
// | BIF_STATUSTEXT // This flag is not supported when BIF_NEWDIALOGSTYLE is specified.
|
||||
, initialFolder, resultPath);
|
||||
// BIF_STATUSTEXT; BIF_USENEWUI (Version 5.0)
|
||||
CSysString s;
|
||||
bool res = BrowseForFolder(owner, GetSystemString(title),
|
||||
BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS
|
||||
// | BIF_STATUSTEXT // This flag is not supported when BIF_NEWDIALOGSTYLE is specified.
|
||||
, GetSystemString(initialFolder), s);
|
||||
resultPath = GetUnicodeString(s);
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,129 @@
|
||||
// Windows/Shell.h
|
||||
|
||||
#ifndef ZIP7_WINDOWS_SHELL_H
|
||||
#define ZIP7_WINDOWS_SHELL_H
|
||||
|
||||
#include "../Common/MyWindows.h"
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#include <shlobj.h>
|
||||
#else
|
||||
#include <ShlObj.h>
|
||||
#endif
|
||||
|
||||
#include "../Common/MyString.h"
|
||||
|
||||
#include "Defs.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NShell {
|
||||
|
||||
/////////////////////////
|
||||
// CItemIDList
|
||||
#ifndef UNDER_CE
|
||||
|
||||
class CItemIDList
|
||||
{
|
||||
LPITEMIDLIST m_Object;
|
||||
Z7_CLASS_NO_COPY(CItemIDList)
|
||||
public:
|
||||
CItemIDList(): m_Object(NULL) {}
|
||||
// CItemIDList(LPCITEMIDLIST itemIDList);
|
||||
// CItemIDList(const CItemIDList& itemIDList);
|
||||
~CItemIDList() { Free(); }
|
||||
void Free();
|
||||
void Attach(LPITEMIDLIST object)
|
||||
{
|
||||
Free();
|
||||
m_Object = object;
|
||||
}
|
||||
LPITEMIDLIST Detach()
|
||||
{
|
||||
LPITEMIDLIST object = m_Object;
|
||||
m_Object = NULL;
|
||||
return object;
|
||||
}
|
||||
operator LPITEMIDLIST() { return m_Object;}
|
||||
operator LPCITEMIDLIST() const { return m_Object;}
|
||||
LPITEMIDLIST* operator&() { return &m_Object; }
|
||||
LPITEMIDLIST operator->() { return m_Object; }
|
||||
|
||||
// CItemIDList& operator=(LPCITEMIDLIST object);
|
||||
// CItemIDList& operator=(const CItemIDList &object);
|
||||
};
|
||||
|
||||
/////////////////////////////
|
||||
// CDrop
|
||||
|
||||
/*
|
||||
class CDrop
|
||||
{
|
||||
HDROP m_Object;
|
||||
bool m_MustBeFinished;
|
||||
bool m_Assigned;
|
||||
void Free();
|
||||
public:
|
||||
CDrop(bool mustBeFinished) : m_MustBeFinished(mustBeFinished), m_Assigned(false) {}
|
||||
~CDrop() { Free(); }
|
||||
|
||||
void Attach(HDROP object);
|
||||
operator HDROP() { return m_Object;}
|
||||
bool QueryPoint(LPPOINT point)
|
||||
{ return BOOLToBool(::DragQueryPoint(m_Object, point)); }
|
||||
void Finish()
|
||||
{
|
||||
::DragFinish(m_Object);
|
||||
}
|
||||
UINT QueryFile(UINT fileIndex, LPTSTR fileName, UINT bufSize)
|
||||
{ return ::DragQueryFile(m_Object, fileIndex, fileName, bufSize); }
|
||||
#ifndef _UNICODE
|
||||
UINT QueryFile(UINT fileIndex, LPWSTR fileName, UINT bufSize)
|
||||
{ return ::DragQueryFileW(m_Object, fileIndex, fileName, bufSize); }
|
||||
#endif
|
||||
UINT QueryCountOfFiles();
|
||||
void QueryFileName(UINT fileIndex, UString &fileName);
|
||||
void QueryFileNames(UStringVector &fileNames);
|
||||
};
|
||||
*/
|
||||
#endif
|
||||
|
||||
struct CFileAttribs
|
||||
{
|
||||
int FirstDirIndex;
|
||||
// DWORD Sum;
|
||||
// DWORD Product;
|
||||
// CRecordVector<DWORD> Vals;
|
||||
// CRecordVector<bool> IsDirVector;
|
||||
|
||||
CFileAttribs()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
FirstDirIndex = -1;
|
||||
// Sum = 0;
|
||||
// Product = 0;
|
||||
// IsDirVector.Clear();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* read pathnames from HDROP or SHELLIDLIST.
|
||||
The parser can return E_INVALIDARG, if there is some unexpected data in dataObject */
|
||||
HRESULT DataObject_GetData_HDROP_or_IDLIST_Names(IDataObject *dataObject, UStringVector &names);
|
||||
|
||||
HRESULT DataObject_GetData_FILE_ATTRS(IDataObject *dataObject, CFileAttribs &attribs);
|
||||
|
||||
bool GetPathFromIDList(LPCITEMIDLIST itemIDList, CSysString &path);
|
||||
bool BrowseForFolder(LPBROWSEINFO lpbi, CSysString &resultPath);
|
||||
bool BrowseForFolder(HWND owner, LPCTSTR title, LPCTSTR initialFolder, CSysString &resultPath);
|
||||
|
||||
#ifndef _UNICODE
|
||||
bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path);
|
||||
bool BrowseForFolder(LPBROWSEINFO lpbi, UString &resultPath);
|
||||
bool BrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR initialFolder, UString &resultPath);
|
||||
#endif
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
// StdAfx.h
|
||||
|
||||
#ifndef ZIP7_INC_STDAFX_H
|
||||
#define ZIP7_INC_STDAFX_H
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1800
|
||||
#pragma warning(disable : 4464) // relative include path contains '..'
|
||||
#endif
|
||||
#include "../Common/Common.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,87 @@
|
||||
// Windows/Synchronization.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include "Synchronization.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NSynchronization {
|
||||
|
||||
/*
|
||||
#define INFINITE 0xFFFFFFFF
|
||||
#define MAXIMUM_WAIT_OBJECTS 64
|
||||
#define STATUS_ABANDONED_WAIT_0 ((NTSTATUS)0x00000080L)
|
||||
#define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0 ) + 0 )
|
||||
#define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0 ) + 0 )
|
||||
// WINAPI
|
||||
DWORD WaitForMultipleObjects(DWORD count, const HANDLE *handles, BOOL wait_all, DWORD timeout);
|
||||
*/
|
||||
|
||||
/* clang: we need to place some virtual functions in cpp file to rid off the warning:
|
||||
'CBaseHandle_WFMO' has no out-of-line virtual method definitions;
|
||||
its vtable will be emitted in every translation unit */
|
||||
CBaseHandle_WFMO::~CBaseHandle_WFMO()
|
||||
{
|
||||
}
|
||||
|
||||
bool CBaseEvent_WFMO::IsSignaledAndUpdate()
|
||||
{
|
||||
if (this->_state == false)
|
||||
return false;
|
||||
if (this->_manual_reset == false)
|
||||
this->_state = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSemaphore_WFMO::IsSignaledAndUpdate()
|
||||
{
|
||||
if (this->_count == 0)
|
||||
return false;
|
||||
this->_count--;
|
||||
return true;
|
||||
}
|
||||
|
||||
DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles)
|
||||
{
|
||||
if (count < 1)
|
||||
{
|
||||
// abort();
|
||||
SetLastError(EINVAL);
|
||||
return WAIT_FAILED;
|
||||
}
|
||||
|
||||
CSynchro *synchro = handles[0]->_sync;
|
||||
synchro->Enter();
|
||||
|
||||
// #ifdef DEBUG_SYNCHRO
|
||||
for (DWORD i = 1; i < count; i++)
|
||||
{
|
||||
if (synchro != handles[i]->_sync)
|
||||
{
|
||||
// abort();
|
||||
synchro->Leave();
|
||||
SetLastError(EINVAL);
|
||||
return WAIT_FAILED;
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
|
||||
for (;;)
|
||||
{
|
||||
for (DWORD i = 0; i < count; i++)
|
||||
{
|
||||
if (handles[i]->IsSignaledAndUpdate())
|
||||
{
|
||||
synchro->Leave();
|
||||
return WAIT_OBJECT_0 + i;
|
||||
}
|
||||
}
|
||||
synchro->WaitCond();
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,386 @@
|
||||
// Windows/Synchronization.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_SYNCHRONIZATION_H
|
||||
#define ZIP7_INC_WINDOWS_SYNCHRONIZATION_H
|
||||
|
||||
#include "../../C/Threads.h"
|
||||
|
||||
#include "../Common/MyTypes.h"
|
||||
|
||||
#include "Defs.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Handle.h"
|
||||
#endif
|
||||
|
||||
namespace NWindows {
|
||||
namespace NSynchronization {
|
||||
|
||||
class CBaseEvent MY_UNCOPYABLE
|
||||
{
|
||||
protected:
|
||||
::CEvent _object;
|
||||
public:
|
||||
bool IsCreated() { return Event_IsCreated(&_object) != 0; }
|
||||
|
||||
CBaseEvent() { Event_Construct(&_object); }
|
||||
~CBaseEvent() { Close(); }
|
||||
WRes Close() { return Event_Close(&_object); }
|
||||
|
||||
#ifdef _WIN32
|
||||
operator HANDLE() { return _object; }
|
||||
WRes Create(bool manualReset, bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL)
|
||||
{
|
||||
_object = ::CreateEvent(sa, BoolToBOOL(manualReset), BoolToBOOL(initiallyOwn), name);
|
||||
if (name == NULL && _object != NULL)
|
||||
return 0;
|
||||
return ::GetLastError();
|
||||
}
|
||||
WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name)
|
||||
{
|
||||
_object = ::OpenEvent(desiredAccess, BoolToBOOL(inheritHandle), name);
|
||||
if (_object != NULL)
|
||||
return 0;
|
||||
return ::GetLastError();
|
||||
}
|
||||
#endif
|
||||
|
||||
WRes Set() { return Event_Set(&_object); }
|
||||
// bool Pulse() { return BOOLToBool(::PulseEvent(_handle)); }
|
||||
WRes Reset() { return Event_Reset(&_object); }
|
||||
WRes Lock() { return Event_Wait(&_object); }
|
||||
};
|
||||
|
||||
class CManualResetEvent: public CBaseEvent
|
||||
{
|
||||
public:
|
||||
WRes Create(bool initiallyOwn = false)
|
||||
{
|
||||
return ManualResetEvent_Create(&_object, initiallyOwn ? 1: 0);
|
||||
}
|
||||
WRes CreateIfNotCreated_Reset()
|
||||
{
|
||||
if (IsCreated())
|
||||
return Reset();
|
||||
return ManualResetEvent_CreateNotSignaled(&_object);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
WRes CreateWithName(bool initiallyOwn, LPCTSTR name)
|
||||
{
|
||||
return CBaseEvent::Create(true, initiallyOwn, name);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
class CAutoResetEvent: public CBaseEvent
|
||||
{
|
||||
public:
|
||||
WRes Create()
|
||||
{
|
||||
return AutoResetEvent_CreateNotSignaled(&_object);
|
||||
}
|
||||
WRes CreateIfNotCreated_Reset()
|
||||
{
|
||||
if (IsCreated())
|
||||
return Reset();
|
||||
return AutoResetEvent_CreateNotSignaled(&_object);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
#ifdef _WIN32
|
||||
|
||||
class CObject: public CHandle
|
||||
{
|
||||
public:
|
||||
WRes Lock(DWORD timeoutInterval = INFINITE)
|
||||
{ return (::WaitForSingleObject(_handle, timeoutInterval) == WAIT_OBJECT_0 ? 0 : ::GetLastError()); }
|
||||
};
|
||||
|
||||
class CMutex: public CObject
|
||||
{
|
||||
public:
|
||||
WRes Create(bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL)
|
||||
{
|
||||
_handle = ::CreateMutex(sa, BoolToBOOL(initiallyOwn), name);
|
||||
if (name == NULL && _handle != 0)
|
||||
return 0;
|
||||
return ::GetLastError();
|
||||
}
|
||||
#ifndef UNDER_CE
|
||||
WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name)
|
||||
{
|
||||
_handle = ::OpenMutex(desiredAccess, BoolToBOOL(inheritHandle), name);
|
||||
if (_handle != 0)
|
||||
return 0;
|
||||
return ::GetLastError();
|
||||
}
|
||||
#endif
|
||||
WRes Release()
|
||||
{
|
||||
return ::ReleaseMutex(_handle) ? 0 : ::GetLastError();
|
||||
}
|
||||
};
|
||||
|
||||
class CMutexLock MY_UNCOPYABLE
|
||||
{
|
||||
CMutex *_object;
|
||||
public:
|
||||
CMutexLock(CMutex &object): _object(&object) { _object->Lock(); }
|
||||
~CMutexLock() { _object->Release(); }
|
||||
};
|
||||
|
||||
#endif // _WIN32
|
||||
*/
|
||||
|
||||
|
||||
class CSemaphore MY_UNCOPYABLE
|
||||
{
|
||||
::CSemaphore _object;
|
||||
public:
|
||||
CSemaphore() { Semaphore_Construct(&_object); }
|
||||
~CSemaphore() { Close(); }
|
||||
WRes Close() { return Semaphore_Close(&_object); }
|
||||
|
||||
#ifdef _WIN32
|
||||
operator HANDLE() { return _object; }
|
||||
#endif
|
||||
|
||||
// bool IsCreated() const { return Semaphore_IsCreated(&_object) != 0; }
|
||||
|
||||
WRes Create(UInt32 initCount, UInt32 maxCount)
|
||||
{
|
||||
return Semaphore_Create(&_object, initCount, maxCount);
|
||||
}
|
||||
WRes OptCreateInit(UInt32 initCount, UInt32 maxCount)
|
||||
{
|
||||
return Semaphore_OptCreateInit(&_object, initCount, maxCount);
|
||||
}
|
||||
WRes Release() { return Semaphore_Release1(&_object); }
|
||||
WRes Release(UInt32 releaseCount) { return Semaphore_ReleaseN(&_object, releaseCount); }
|
||||
WRes Lock() { return Semaphore_Wait(&_object); }
|
||||
};
|
||||
|
||||
class CCriticalSection MY_UNCOPYABLE
|
||||
{
|
||||
::CCriticalSection _object;
|
||||
public:
|
||||
CCriticalSection() { CriticalSection_Init(&_object); }
|
||||
~CCriticalSection() { CriticalSection_Delete(&_object); }
|
||||
void Enter() { CriticalSection_Enter(&_object); }
|
||||
void Leave() { CriticalSection_Leave(&_object); }
|
||||
};
|
||||
|
||||
class CCriticalSectionLock MY_UNCOPYABLE
|
||||
{
|
||||
CCriticalSection *_object;
|
||||
void Unlock() { _object->Leave(); }
|
||||
public:
|
||||
CCriticalSectionLock(CCriticalSection &object): _object(&object) {_object->Enter(); }
|
||||
~CCriticalSectionLock() { Unlock(); }
|
||||
};
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
typedef HANDLE CHandle_WFMO;
|
||||
typedef CSemaphore CSemaphore_WFMO;
|
||||
typedef CAutoResetEvent CAutoResetEvent_WFMO;
|
||||
typedef CManualResetEvent CManualResetEvent_WFMO;
|
||||
|
||||
inline DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles)
|
||||
{
|
||||
return ::WaitForMultipleObjects(count, handles, FALSE, INFINITE);
|
||||
}
|
||||
|
||||
#define SYNC_OBJ_DECL(obj)
|
||||
#define SYNC_WFMO(x)
|
||||
#define SYNC_PARAM(x)
|
||||
#define SYNC_PARAM_DECL(x)
|
||||
|
||||
#else // _WIN32
|
||||
|
||||
// POSIX sync objects for WaitForMultipleObjects
|
||||
|
||||
#define SYNC_WFMO(x) x
|
||||
#define SYNC_PARAM(x) x,
|
||||
#define SYNC_PARAM_DECL(x) NWindows::NSynchronization::CSynchro *x
|
||||
#define SYNC_OBJ_DECL(x) NWindows::NSynchronization::CSynchro x;
|
||||
|
||||
class CSynchro MY_UNCOPYABLE
|
||||
{
|
||||
pthread_mutex_t _mutex;
|
||||
pthread_cond_t _cond;
|
||||
bool _isValid;
|
||||
|
||||
public:
|
||||
CSynchro() { _isValid = false; }
|
||||
~CSynchro()
|
||||
{
|
||||
if (_isValid)
|
||||
{
|
||||
::pthread_mutex_destroy(&_mutex);
|
||||
::pthread_cond_destroy(&_cond);
|
||||
}
|
||||
_isValid = false;
|
||||
}
|
||||
WRes Create()
|
||||
{
|
||||
RINOK(::pthread_mutex_init(&_mutex, NULL))
|
||||
const WRes ret = ::pthread_cond_init(&_cond, NULL);
|
||||
_isValid = 1;
|
||||
return ret;
|
||||
}
|
||||
WRes Enter()
|
||||
{
|
||||
#if defined(Z7_LLVM_CLANG_VERSION) && (__clang_major__ == 13) \
|
||||
&& defined(__FreeBSD__)
|
||||
#pragma GCC diagnostic ignored "-Wthread-safety-negative"
|
||||
#pragma GCC diagnostic ignored "-Wthread-safety-analysis"
|
||||
#endif
|
||||
return ::pthread_mutex_lock(&_mutex);
|
||||
}
|
||||
WRes Leave()
|
||||
{
|
||||
return ::pthread_mutex_unlock(&_mutex);
|
||||
}
|
||||
WRes WaitCond()
|
||||
{
|
||||
return ::pthread_cond_wait(&_cond, &_mutex);
|
||||
}
|
||||
WRes LeaveAndSignal()
|
||||
{
|
||||
const WRes res1 = ::pthread_cond_broadcast(&_cond);
|
||||
const WRes res2 = ::pthread_mutex_unlock(&_mutex);
|
||||
return (res2 ? res2 : res1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct CBaseHandle_WFMO;
|
||||
typedef NWindows::NSynchronization::CBaseHandle_WFMO *CHandle_WFMO;
|
||||
|
||||
// these constants are from Windows
|
||||
#define WAIT_OBJECT_0 0
|
||||
#define WAIT_FAILED ((DWORD)0xFFFFFFFF)
|
||||
|
||||
DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles);
|
||||
|
||||
|
||||
struct CBaseHandle_WFMO MY_UNCOPYABLE
|
||||
{
|
||||
CSynchro *_sync;
|
||||
|
||||
CBaseHandle_WFMO(): _sync(NULL) {}
|
||||
virtual ~CBaseHandle_WFMO();
|
||||
|
||||
operator CHandle_WFMO() { return this; }
|
||||
virtual bool IsSignaledAndUpdate() = 0;
|
||||
};
|
||||
|
||||
|
||||
class CBaseEvent_WFMO : public CBaseHandle_WFMO
|
||||
{
|
||||
bool _manual_reset;
|
||||
bool _state;
|
||||
|
||||
public:
|
||||
|
||||
// bool IsCreated() { return (this->_sync != NULL); }
|
||||
// CBaseEvent_WFMO() { ; }
|
||||
// ~CBaseEvent_WFMO() Z7_override { Close(); }
|
||||
|
||||
WRes Close() { this->_sync = NULL; return 0; }
|
||||
|
||||
WRes Create(
|
||||
CSynchro *sync,
|
||||
bool manualReset, bool initiallyOwn)
|
||||
{
|
||||
this->_sync = sync;
|
||||
this->_manual_reset = manualReset;
|
||||
this->_state = initiallyOwn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Set()
|
||||
{
|
||||
RINOK(this->_sync->Enter())
|
||||
this->_state = true;
|
||||
return this->_sync->LeaveAndSignal();
|
||||
}
|
||||
|
||||
WRes Reset()
|
||||
{
|
||||
RINOK(this->_sync->Enter())
|
||||
this->_state = false;
|
||||
return this->_sync->Leave();
|
||||
}
|
||||
|
||||
virtual bool IsSignaledAndUpdate() Z7_override;
|
||||
};
|
||||
|
||||
|
||||
class CManualResetEvent_WFMO Z7_final: public CBaseEvent_WFMO
|
||||
{
|
||||
public:
|
||||
WRes Create(CSynchro *sync, bool initiallyOwn = false) { return CBaseEvent_WFMO::Create(sync, true, initiallyOwn); }
|
||||
};
|
||||
|
||||
|
||||
class CAutoResetEvent_WFMO Z7_final: public CBaseEvent_WFMO
|
||||
{
|
||||
public:
|
||||
WRes Create(CSynchro *sync) { return CBaseEvent_WFMO::Create(sync, false, false); }
|
||||
WRes CreateIfNotCreated_Reset(CSynchro *sync)
|
||||
{
|
||||
return Create(sync);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CSemaphore_WFMO Z7_final: public CBaseHandle_WFMO
|
||||
{
|
||||
UInt32 _count;
|
||||
UInt32 _maxCount;
|
||||
|
||||
public:
|
||||
CSemaphore_WFMO() : _count(0), _maxCount(0) {}
|
||||
|
||||
WRes Close() { this->_sync = NULL; return 0; }
|
||||
|
||||
WRes Create(CSynchro *sync, UInt32 initCount, UInt32 maxCount)
|
||||
{
|
||||
if (initCount > maxCount || maxCount < 1)
|
||||
return EINVAL;
|
||||
this->_sync = sync;
|
||||
this->_count = initCount;
|
||||
this->_maxCount = maxCount;
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Release(UInt32 releaseCount = 1)
|
||||
{
|
||||
if (releaseCount < 1)
|
||||
return EINVAL;
|
||||
|
||||
RINOK(this->_sync->Enter())
|
||||
UInt32 newCount = this->_count + releaseCount;
|
||||
if (newCount > this->_maxCount)
|
||||
{
|
||||
RINOK(this->_sync->Leave())
|
||||
return ERROR_TOO_MANY_POSTS; // EINVAL
|
||||
}
|
||||
this->_count = newCount;
|
||||
|
||||
return this->_sync->LeaveAndSignal();
|
||||
}
|
||||
|
||||
virtual bool IsSignaledAndUpdate() Z7_override;
|
||||
};
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,423 @@
|
||||
// Windows/System.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#if defined(__APPLE__) || defined(__DragonFly__) \
|
||||
|| defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
|
||||
|| defined(__QNXNTO__)
|
||||
#include <sys/sysctl.h>
|
||||
#else
|
||||
#include <sys/sysinfo.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "../Common/Defs.h"
|
||||
// #include "../Common/MyWindows.h"
|
||||
|
||||
// #include "../../C/CpuArch.h"
|
||||
|
||||
#include "System.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NSystem {
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/*
|
||||
note: returned value in 32-bit version can be limited by value 32.
|
||||
while 64-bit version returns full value.
|
||||
GetMaximumProcessorCount(groupNumber) can return higher value than
|
||||
GetActiveProcessorCount(groupNumber) in some cases, because CPUs can be added.
|
||||
*/
|
||||
// typedef DWORD (WINAPI *Func_GetMaximumProcessorCount)(WORD GroupNumber);
|
||||
typedef DWORD (WINAPI *Func_GetActiveProcessorCount)(WORD GroupNumber);
|
||||
typedef WORD (WINAPI *Func_GetActiveProcessorGroupCount)(VOID);
|
||||
/*
|
||||
#if 0 && defined(ALL_PROCESSOR_GROUPS)
|
||||
#define MY_ALL_PROCESSOR_GROUPS ALL_PROCESSOR_GROUPS
|
||||
#else
|
||||
#define MY_ALL_PROCESSOR_GROUPS 0xffff
|
||||
#endif
|
||||
*/
|
||||
|
||||
Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
|
||||
|
||||
bool CCpuGroups::Load()
|
||||
{
|
||||
NumThreadsTotal = 0;
|
||||
GroupSizes.Clear();
|
||||
const HMODULE hmodule = ::GetModuleHandleA("kernel32.dll");
|
||||
// Is_Win11_Groups = GetProcAddress(hmodule, "SetThreadSelectedCpuSetMasks") != NULL;
|
||||
const
|
||||
Func_GetActiveProcessorGroupCount
|
||||
fn_GetActiveProcessorGroupCount = Z7_GET_PROC_ADDRESS(
|
||||
Func_GetActiveProcessorGroupCount, hmodule,
|
||||
"GetActiveProcessorGroupCount");
|
||||
const
|
||||
Func_GetActiveProcessorCount
|
||||
fn_GetActiveProcessorCount = Z7_GET_PROC_ADDRESS(
|
||||
Func_GetActiveProcessorCount, hmodule,
|
||||
"GetActiveProcessorCount");
|
||||
if (!fn_GetActiveProcessorGroupCount ||
|
||||
!fn_GetActiveProcessorCount)
|
||||
return false;
|
||||
|
||||
const unsigned numGroups = fn_GetActiveProcessorGroupCount();
|
||||
if (numGroups == 0)
|
||||
return false;
|
||||
UInt32 sum = 0;
|
||||
for (unsigned i = 0; i < numGroups; i++)
|
||||
{
|
||||
const UInt32 num = fn_GetActiveProcessorCount((WORD)i);
|
||||
/*
|
||||
if (num == 0)
|
||||
{
|
||||
// it means error
|
||||
// but is it possible that some group is empty by some reason?
|
||||
// GroupSizes.Clear();
|
||||
// return false;
|
||||
}
|
||||
*/
|
||||
sum += num;
|
||||
GroupSizes.Add(num);
|
||||
}
|
||||
NumThreadsTotal = sum;
|
||||
// NumThreadsTotal = fn_GetActiveProcessorCount(MY_ALL_PROCESSOR_GROUPS);
|
||||
return true;
|
||||
}
|
||||
|
||||
UInt32 CountAffinity(DWORD_PTR mask)
|
||||
{
|
||||
UInt32 num = 0;
|
||||
for (unsigned i = 0; i < sizeof(mask) * 8; i++)
|
||||
{
|
||||
num += (UInt32)(mask & 1);
|
||||
mask >>= 1;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
BOOL CProcessAffinity::Get()
|
||||
{
|
||||
IsGroupMode = false;
|
||||
Groups.Load();
|
||||
// SetThreadAffinityMask(GetCurrentThread(), 1);
|
||||
// SetProcessAffinityMask(GetCurrentProcess(), 1);
|
||||
BOOL res = GetProcessAffinityMask(GetCurrentProcess(),
|
||||
&processAffinityMask, &systemAffinityMask);
|
||||
/* DOCs: On a system with more than 64 processors, if the threads
|
||||
of the calling process are in a single processor group, the
|
||||
function sets the variables pointed to by lpProcessAffinityMask
|
||||
and lpSystemAffinityMask to the process affinity mask and the
|
||||
processor mask of active logical processors for that group.
|
||||
If the calling process contains threads in multiple groups,
|
||||
the function returns zero for both affinity masks
|
||||
|
||||
note: tested in Win10: GetProcessAffinityMask() doesn't return 0
|
||||
in (processAffinityMask) and (systemAffinityMask) masks.
|
||||
We need to test it in Win11: how to get mask==0 from GetProcessAffinityMask()?
|
||||
*/
|
||||
if (!res)
|
||||
{
|
||||
processAffinityMask = 0;
|
||||
systemAffinityMask = 0;
|
||||
}
|
||||
if (Groups.GroupSizes.Size() > 1 && Groups.NumThreadsTotal)
|
||||
if (// !res ||
|
||||
processAffinityMask == 0 || // to support case described in DOCs and for (!res) case
|
||||
processAffinityMask == systemAffinityMask) // for default nonchanged affinity
|
||||
{
|
||||
// we set IsGroupMode only if processAffinity is default (not changed).
|
||||
res = TRUE;
|
||||
IsGroupMode = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
UInt32 CProcessAffinity::Load_and_GetNumberOfThreads()
|
||||
{
|
||||
if (Get())
|
||||
{
|
||||
const UInt32 numProcessors = GetNumProcessThreads();
|
||||
if (numProcessors)
|
||||
return numProcessors;
|
||||
}
|
||||
SYSTEM_INFO systemInfo;
|
||||
GetSystemInfo(&systemInfo);
|
||||
// the number of logical processors in the current group
|
||||
return systemInfo.dwNumberOfProcessors;
|
||||
}
|
||||
|
||||
UInt32 GetNumberOfProcessors()
|
||||
{
|
||||
// We need to know how many threads we can use.
|
||||
// By default the process is assigned to one group.
|
||||
CProcessAffinity pa;
|
||||
return pa.Load_and_GetNumberOfThreads();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
|
||||
BOOL CProcessAffinity::Get()
|
||||
{
|
||||
numSysThreads = GetNumberOfProcessors();
|
||||
|
||||
/*
|
||||
numSysThreads = 8;
|
||||
for (unsigned i = 0; i < numSysThreads; i++)
|
||||
CpuSet_Set(&cpu_set, i);
|
||||
return TRUE;
|
||||
*/
|
||||
|
||||
#ifdef Z7_AFFINITY_SUPPORTED
|
||||
|
||||
// numSysThreads = sysconf(_SC_NPROCESSORS_ONLN); // The number of processors currently online
|
||||
if (sched_getaffinity(0, sizeof(cpu_set), &cpu_set) != 0)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
|
||||
#else
|
||||
|
||||
// cpu_set = ((CCpuSet)1 << (numSysThreads)) - 1;
|
||||
return TRUE;
|
||||
// errno = ENOSYS;
|
||||
// return FALSE;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
UInt32 GetNumberOfProcessors()
|
||||
{
|
||||
#ifndef Z7_ST
|
||||
long n = sysconf(_SC_NPROCESSORS_CONF); // The number of processors configured
|
||||
if (n < 1)
|
||||
n = 1;
|
||||
return (UInt32)n;
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifndef UNDER_CE
|
||||
|
||||
#if !defined(_WIN64) && \
|
||||
(defined(__MINGW32_VERSION) || defined(Z7_OLD_WIN_SDK))
|
||||
|
||||
typedef struct {
|
||||
DWORD dwLength;
|
||||
DWORD dwMemoryLoad;
|
||||
DWORDLONG ullTotalPhys;
|
||||
DWORDLONG ullAvailPhys;
|
||||
DWORDLONG ullTotalPageFile;
|
||||
DWORDLONG ullAvailPageFile;
|
||||
DWORDLONG ullTotalVirtual;
|
||||
DWORDLONG ullAvailVirtual;
|
||||
DWORDLONG ullAvailExtendedVirtual;
|
||||
} MY_MEMORYSTATUSEX, *MY_LPMEMORYSTATUSEX;
|
||||
|
||||
#else
|
||||
|
||||
#define MY_MEMORYSTATUSEX MEMORYSTATUSEX
|
||||
#define MY_LPMEMORYSTATUSEX LPMEMORYSTATUSEX
|
||||
|
||||
#endif
|
||||
|
||||
typedef BOOL (WINAPI *Func_GlobalMemoryStatusEx)(MY_LPMEMORYSTATUSEX lpBuffer);
|
||||
|
||||
#endif // !UNDER_CE
|
||||
|
||||
|
||||
bool GetRamSize(size_t &size)
|
||||
{
|
||||
size = (size_t)sizeof(size_t) << 29;
|
||||
|
||||
#ifndef UNDER_CE
|
||||
MY_MEMORYSTATUSEX stat;
|
||||
stat.dwLength = sizeof(stat);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN64
|
||||
|
||||
if (!::GlobalMemoryStatusEx(&stat))
|
||||
return false;
|
||||
size = MyMin(stat.ullTotalVirtual, stat.ullTotalPhys);
|
||||
return true;
|
||||
|
||||
#else
|
||||
|
||||
#ifndef UNDER_CE
|
||||
const
|
||||
Func_GlobalMemoryStatusEx fn = Z7_GET_PROC_ADDRESS(
|
||||
Func_GlobalMemoryStatusEx, ::GetModuleHandleA("kernel32.dll"),
|
||||
"GlobalMemoryStatusEx");
|
||||
if (fn && fn(&stat))
|
||||
{
|
||||
// (MY_MEMORYSTATUSEX::ullTotalVirtual) < 4 GiB in 32-bit mode
|
||||
size_t size2 = (size_t)0 - 1;
|
||||
if (size2 > stat.ullTotalPhys)
|
||||
size2 = (size_t)stat.ullTotalPhys;
|
||||
if (size2 > stat.ullTotalVirtual)
|
||||
size2 = (size_t)stat.ullTotalVirtual;
|
||||
size = size2;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// On computers with more than 4 GB of memory:
|
||||
// new docs : GlobalMemoryStatus can report (-1) value to indicate an overflow.
|
||||
// some old docs : GlobalMemoryStatus can report (modulo 4 GiB) value.
|
||||
// (for example, if 5 GB total memory, it could report 1 GB).
|
||||
// We don't want to get (modulo 4 GiB) value.
|
||||
// So we use GlobalMemoryStatusEx() instead.
|
||||
{
|
||||
MEMORYSTATUS stat2;
|
||||
stat2.dwLength = sizeof(stat2);
|
||||
::GlobalMemoryStatus(&stat2);
|
||||
size = MyMin(stat2.dwTotalVirtual, stat2.dwTotalPhys);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// POSIX
|
||||
// #include <stdio.h>
|
||||
|
||||
bool GetRamSize(size_t &size)
|
||||
{
|
||||
UInt64 size64;
|
||||
size = (size_t)sizeof(size_t) << 29;
|
||||
size64 = size;
|
||||
|
||||
#if defined(__APPLE__) || defined(__DragonFly__) \
|
||||
|| defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
|
||||
|| defined(__QNXNTO__)
|
||||
|
||||
uint64_t val = 0;
|
||||
int mib[2];
|
||||
mib[0] = CTL_HW;
|
||||
|
||||
#ifdef HW_MEMSIZE
|
||||
mib[1] = HW_MEMSIZE;
|
||||
// printf("\n sysctl HW_MEMSIZE");
|
||||
#elif defined(HW_PHYSMEM64)
|
||||
mib[1] = HW_PHYSMEM64;
|
||||
// printf("\n sysctl HW_PHYSMEM64");
|
||||
#else
|
||||
mib[1] = HW_PHYSMEM;
|
||||
// printf("\n sysctl HW_PHYSMEM");
|
||||
#endif
|
||||
|
||||
size_t size_sys = sizeof(val);
|
||||
int res = sysctl(mib, 2, &val, &size_sys, NULL, 0);
|
||||
// printf("\n sysctl res=%d val=%llx size_sys = %d, %d\n", res, (long long int)val, (int)size_sys, errno);
|
||||
// we use strict check (size_sys == sizeof(val)) for returned value
|
||||
// because big-endian encoding is possible:
|
||||
if (res == 0 && size_sys == sizeof(val) && val)
|
||||
size64 = val;
|
||||
else
|
||||
{
|
||||
uint32_t val32 = 0;
|
||||
size_sys = sizeof(val32);
|
||||
res = sysctl(mib, 2, &val32, &size_sys, NULL, 0);
|
||||
// printf("\n sysctl res=%d val=%llx size_sys = %d, %d\n", res, (long long int)val32, (int)size_sys, errno);
|
||||
if (res == 0 && size_sys == sizeof(val32) && val32)
|
||||
size64 = val32;
|
||||
}
|
||||
|
||||
#elif defined(_AIX)
|
||||
#if defined(_SC_AIX_REALMEM) // AIX
|
||||
size64 = (UInt64)sysconf(_SC_AIX_REALMEM) * 1024;
|
||||
#endif
|
||||
#elif 0 || defined(__sun)
|
||||
#if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
|
||||
// FreeBSD, Linux, OpenBSD, and Solaris.
|
||||
{
|
||||
const long phys_pages = sysconf(_SC_PHYS_PAGES);
|
||||
const long page_size = sysconf(_SC_PAGESIZE);
|
||||
// #pragma message("GetRamSize : sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE)")
|
||||
// printf("\n_SC_PHYS_PAGES (hex) = %lx", (unsigned long)phys_pages);
|
||||
// printf("\n_SC_PAGESIZE = %lu\n", (unsigned long)page_size);
|
||||
if (phys_pages != -1 && page_size != -1)
|
||||
size64 = (UInt64)(Int64)phys_pages * (UInt64)(Int64)page_size;
|
||||
}
|
||||
#endif
|
||||
#elif defined(__gnu_hurd__)
|
||||
// fixme
|
||||
#elif defined(__FreeBSD_kernel__) && defined(__GLIBC__)
|
||||
// GNU/kFreeBSD Debian
|
||||
// fixme
|
||||
#else
|
||||
|
||||
struct sysinfo info;
|
||||
if (::sysinfo(&info) != 0)
|
||||
return false;
|
||||
size64 = (UInt64)info.mem_unit * info.totalram;
|
||||
/*
|
||||
printf("\n mem_unit = %lld", (UInt64)info.mem_unit);
|
||||
printf("\n totalram = %lld", (UInt64)info.totalram);
|
||||
printf("\n freeram = %lld", (UInt64)info.freeram);
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
size = (size_t)1 << (sizeof(size_t) * 8 - 1);
|
||||
if (size > size64)
|
||||
size = (size_t)size64;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
unsigned long Get_File_OPEN_MAX()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return (1 << 24) - (1 << 16); // ~16M handles
|
||||
#else
|
||||
// some linux versions have default open file limit for user process of 1024 files.
|
||||
long n = sysconf(_SC_OPEN_MAX);
|
||||
// n = -1; // for debug
|
||||
// n = 9; // for debug
|
||||
if (n < 1)
|
||||
{
|
||||
// n = OPEN_MAX; // ???
|
||||
// n = FOPEN_MAX; // = 16 : <stdio.h>
|
||||
#ifdef _POSIX_OPEN_MAX
|
||||
n = _POSIX_OPEN_MAX; // = 20 : <limits.h>
|
||||
#else
|
||||
n = 30; // our limit
|
||||
#endif
|
||||
}
|
||||
return (unsigned long)n;
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned Get_File_OPEN_MAX_Reduced_for_3_tasks()
|
||||
{
|
||||
unsigned long numFiles_OPEN_MAX = NSystem::Get_File_OPEN_MAX();
|
||||
const unsigned delta = 10; // the reserve for another internal needs of process
|
||||
if (numFiles_OPEN_MAX > delta)
|
||||
numFiles_OPEN_MAX -= delta;
|
||||
else
|
||||
numFiles_OPEN_MAX = 1;
|
||||
numFiles_OPEN_MAX /= 3; // we suppose that we have up to 3 tasks in total for multiple file processing
|
||||
numFiles_OPEN_MAX = MyMax(numFiles_OPEN_MAX, (unsigned long)3);
|
||||
unsigned n = (unsigned)(int)-1;
|
||||
if (n > numFiles_OPEN_MAX)
|
||||
n = (unsigned)numFiles_OPEN_MAX;
|
||||
return n;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,208 @@
|
||||
// Windows/System.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_SYSTEM_H
|
||||
#define ZIP7_INC_WINDOWS_SYSTEM_H
|
||||
|
||||
#ifndef _WIN32
|
||||
// #include <sched.h>
|
||||
#include "../../C/Threads.h"
|
||||
#endif
|
||||
|
||||
#include "../Common/MyTypes.h"
|
||||
#include "../Common/MyVector.h"
|
||||
#include "../Common/MyWindows.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NSystem {
|
||||
|
||||
UInt32 GetNumberOfProcessors();
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
struct CCpuGroups
|
||||
{
|
||||
CRecordVector<UInt32> GroupSizes;
|
||||
UInt32 NumThreadsTotal; // sum of threads in all groups
|
||||
// bool Is_Win11_Groups; // useless
|
||||
|
||||
void Get_GroupSize_Min_Max(UInt32 &minSize, UInt32 &maxSize) const
|
||||
{
|
||||
unsigned num = GroupSizes.Size();
|
||||
UInt32 minSize2 = 0, maxSize2 = 0;
|
||||
if (num)
|
||||
{
|
||||
minSize2 = (UInt32)0 - 1;
|
||||
do
|
||||
{
|
||||
const UInt32 v = GroupSizes[--num];
|
||||
if (minSize2 > v) minSize2 = v;
|
||||
if (maxSize2 < v) maxSize2 = v;
|
||||
}
|
||||
while (num);
|
||||
}
|
||||
minSize = minSize2;
|
||||
maxSize = maxSize2;
|
||||
}
|
||||
bool Load();
|
||||
CCpuGroups(): NumThreadsTotal(0) {}
|
||||
};
|
||||
|
||||
UInt32 CountAffinity(DWORD_PTR mask);
|
||||
|
||||
struct CProcessAffinity
|
||||
{
|
||||
// UInt32 numProcessThreads;
|
||||
// UInt32 numSysThreads;
|
||||
DWORD_PTR processAffinityMask;
|
||||
DWORD_PTR systemAffinityMask;
|
||||
|
||||
CCpuGroups Groups;
|
||||
bool IsGroupMode;
|
||||
/*
|
||||
IsGroupMode == true, if
|
||||
Groups.GroupSizes.Size() > 1) && { dafalt affinity was not changed }
|
||||
IsGroupMode == false, if single group or affinity was changed
|
||||
*/
|
||||
|
||||
UInt32 Load_and_GetNumberOfThreads();
|
||||
|
||||
void InitST()
|
||||
{
|
||||
// numProcessThreads = 1;
|
||||
// numSysThreads = 1;
|
||||
processAffinityMask = 1;
|
||||
systemAffinityMask = 1;
|
||||
IsGroupMode = false;
|
||||
// Groups.NumThreadsTotal = 0;
|
||||
// Groups.Is_Win11_Groups = false;
|
||||
}
|
||||
|
||||
/*
|
||||
void CpuZero()
|
||||
{
|
||||
processAffinityMask = 0;
|
||||
}
|
||||
|
||||
void CpuSet(unsigned cpuIndex)
|
||||
{
|
||||
processAffinityMask |= ((DWORD_PTR)1 << cpuIndex);
|
||||
}
|
||||
*/
|
||||
|
||||
UInt32 GetNumProcessThreads() const
|
||||
{
|
||||
if (IsGroupMode)
|
||||
return Groups.NumThreadsTotal;
|
||||
// IsGroupMode == false
|
||||
// so we don't want to use groups
|
||||
// we return number of threads in default primary group:
|
||||
return CountAffinity(processAffinityMask);
|
||||
}
|
||||
UInt32 GetNumSystemThreads() const
|
||||
{
|
||||
if (Groups.GroupSizes.Size() > 1 && Groups.NumThreadsTotal)
|
||||
return Groups.NumThreadsTotal;
|
||||
return CountAffinity(systemAffinityMask);
|
||||
}
|
||||
|
||||
// it returns normilized number of threads
|
||||
void Get_and_return_NumProcessThreads_and_SysThreads(UInt32 &numProcessThreads, UInt32 &numSysThreads)
|
||||
{
|
||||
UInt32 num1 = 0, num2 = 0;
|
||||
if (Get())
|
||||
{
|
||||
num1 = GetNumProcessThreads();
|
||||
num2 = GetNumSystemThreads();
|
||||
}
|
||||
if (num1 == 0)
|
||||
num1 = NSystem::GetNumberOfProcessors();
|
||||
if (num1 == 0)
|
||||
num1 = 1;
|
||||
if (num2 < num1)
|
||||
num2 = num1;
|
||||
numProcessThreads = num1;
|
||||
numSysThreads = num2;
|
||||
}
|
||||
|
||||
BOOL Get();
|
||||
|
||||
BOOL SetProcAffinity() const
|
||||
{
|
||||
return SetProcessAffinityMask(GetCurrentProcess(), processAffinityMask);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#else // WIN32
|
||||
|
||||
struct CProcessAffinity
|
||||
{
|
||||
UInt32 numSysThreads;
|
||||
|
||||
UInt32 GetNumSystemThreads() const { return (UInt32)numSysThreads; }
|
||||
BOOL Get();
|
||||
|
||||
#ifdef Z7_AFFINITY_SUPPORTED
|
||||
|
||||
CCpuSet cpu_set;
|
||||
|
||||
void InitST()
|
||||
{
|
||||
numSysThreads = 1;
|
||||
CpuSet_Zero(&cpu_set);
|
||||
CpuSet_Set(&cpu_set, 0);
|
||||
}
|
||||
|
||||
UInt32 GetNumProcessThreads() const { return (UInt32)CPU_COUNT(&cpu_set); }
|
||||
void CpuZero() { CpuSet_Zero(&cpu_set); }
|
||||
void CpuSet(unsigned cpuIndex) { CpuSet_Set(&cpu_set, cpuIndex); }
|
||||
int IsCpuSet(unsigned cpuIndex) const { return CpuSet_IsSet(&cpu_set, cpuIndex); }
|
||||
// void CpuClr(int cpuIndex) { CPU_CLR(cpuIndex, &cpu_set); }
|
||||
|
||||
BOOL SetProcAffinity() const
|
||||
{
|
||||
return sched_setaffinity(0, sizeof(cpu_set), &cpu_set) == 0;
|
||||
}
|
||||
|
||||
#else // Z7_AFFINITY_SUPPORTED
|
||||
|
||||
void InitST()
|
||||
{
|
||||
numSysThreads = 1;
|
||||
}
|
||||
|
||||
UInt32 GetNumProcessThreads() const
|
||||
{
|
||||
return numSysThreads;
|
||||
/*
|
||||
UInt32 num = 0;
|
||||
for (unsigned i = 0; i < sizeof(cpu_set) * 8; i++)
|
||||
num += (UInt32)((cpu_set >> i) & 1);
|
||||
return num;
|
||||
*/
|
||||
}
|
||||
|
||||
void CpuZero() { }
|
||||
void CpuSet(unsigned /* cpuIndex */) { /* UNUSED_VAR(cpuIndex) */ }
|
||||
int IsCpuSet(unsigned cpuIndex) const { return (cpuIndex < numSysThreads) ? 1 : 0; }
|
||||
|
||||
BOOL SetProcAffinity() const
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif // Z7_AFFINITY_SUPPORTED
|
||||
};
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
bool GetRamSize(size_t &size); // returns false, if unknown ram size
|
||||
|
||||
unsigned long Get_File_OPEN_MAX();
|
||||
unsigned Get_File_OPEN_MAX_Reduced_for_3_tasks();
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,19 @@
|
||||
// Windows/SystemInfo.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_SYSTEM_INFO_H
|
||||
#define ZIP7_INC_WINDOWS_SYSTEM_INFO_H
|
||||
|
||||
#include "../Common/MyString.h"
|
||||
|
||||
|
||||
void GetCpuName_MultiLine(AString &s, AString ®isters);
|
||||
|
||||
void GetOsInfoText(AString &sRes);
|
||||
void GetSystemInfoText(AString &s);
|
||||
void PrintSize_KMGT_Or_Hex(AString &s, UInt64 v);
|
||||
void Add_LargePages_String(AString &s);
|
||||
|
||||
void GetCompiler(AString &s);
|
||||
void GetVirtCpuid(AString &s);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
// Windows/Thread.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_THREAD_H
|
||||
#define ZIP7_INC_WINDOWS_THREAD_H
|
||||
|
||||
#include "../../C/Threads.h"
|
||||
|
||||
#include "Defs.h"
|
||||
|
||||
namespace NWindows {
|
||||
|
||||
class CThread MY_UNCOPYABLE
|
||||
{
|
||||
::CThread thread;
|
||||
public:
|
||||
CThread() { Thread_CONSTRUCT(&thread) }
|
||||
~CThread() { Close(); }
|
||||
bool IsCreated() { return Thread_WasCreated(&thread) != 0; }
|
||||
WRes Close() { return Thread_Close(&thread); }
|
||||
// WRes Wait() { return Thread_Wait(&thread); }
|
||||
WRes Wait_Close() { return Thread_Wait_Close(&thread); }
|
||||
|
||||
WRes Create(THREAD_FUNC_TYPE startAddress, LPVOID param)
|
||||
{ return Thread_Create(&thread, startAddress, param); }
|
||||
WRes Create_With_Affinity(THREAD_FUNC_TYPE startAddress, LPVOID param, CAffinityMask affinity)
|
||||
{ return Thread_Create_With_Affinity(&thread, startAddress, param, affinity); }
|
||||
WRes Create_With_CpuSet(THREAD_FUNC_TYPE startAddress, LPVOID param, const CCpuSet *cpuSet)
|
||||
{ return Thread_Create_With_CpuSet(&thread, startAddress, param, cpuSet); }
|
||||
|
||||
#ifdef _WIN32
|
||||
WRes Create_With_Group(THREAD_FUNC_TYPE startAddress, LPVOID param, unsigned group, CAffinityMask affinity = 0)
|
||||
{ return Thread_Create_With_Group(&thread, startAddress, param, group, affinity); }
|
||||
operator HANDLE() { return thread; }
|
||||
void Attach(HANDLE handle) { thread = handle; }
|
||||
HANDLE Detach() { HANDLE h = thread; thread = NULL; return h; }
|
||||
DWORD Resume() { return ::ResumeThread(thread); }
|
||||
DWORD Suspend() { return ::SuspendThread(thread); }
|
||||
bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread, exitCode)); }
|
||||
int GetPriority() { return ::GetThreadPriority(thread); }
|
||||
bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread, priority)); }
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,467 @@
|
||||
// Windows/TimeUtils.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#include "Defs.h"
|
||||
#include "TimeUtils.h"
|
||||
|
||||
namespace NWindows {
|
||||
namespace NTime {
|
||||
|
||||
static const UInt32 kNumTimeQuantumsInSecond = 10000000;
|
||||
static const unsigned kFileTimeStartYear = 1601;
|
||||
#if !defined(_WIN32) || defined(UNDER_CE)
|
||||
static const unsigned kDosTimeStartYear = 1980;
|
||||
#endif
|
||||
static const unsigned kUnixTimeStartYear = 1970;
|
||||
static const UInt64 kUnixTimeOffset =
|
||||
(UInt64)60 * 60 * 24 * (89 + 365 * (UInt32)(kUnixTimeStartYear - kFileTimeStartYear));
|
||||
static const UInt64 kNumSecondsInFileTime = (UInt64)(Int64)-1 / kNumTimeQuantumsInSecond;
|
||||
|
||||
bool DosTime_To_FileTime(UInt32 dosTime, FILETIME &ft) throw()
|
||||
{
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
return BOOLToBool(::DosDateTimeToFileTime((UInt16)(dosTime >> 16), (UInt16)(dosTime & 0xFFFF), &ft));
|
||||
#else
|
||||
ft.dwLowDateTime = 0;
|
||||
ft.dwHighDateTime = 0;
|
||||
UInt64 res;
|
||||
if (!GetSecondsSince1601(
|
||||
kDosTimeStartYear + (unsigned)(dosTime >> 25),
|
||||
(unsigned)((dosTime >> 21) & 0xF),
|
||||
(unsigned)((dosTime >> 16) & 0x1F),
|
||||
(unsigned)((dosTime >> 11) & 0x1F),
|
||||
(unsigned)((dosTime >> 5) & 0x3F),
|
||||
(unsigned)((dosTime & 0x1F)) * 2,
|
||||
res))
|
||||
return false;
|
||||
res *= kNumTimeQuantumsInSecond;
|
||||
ft.dwLowDateTime = (UInt32)res;
|
||||
ft.dwHighDateTime = (UInt32)(res >> 32);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const UInt32 kHighDosTime = 0xFF9FBF7D;
|
||||
static const UInt32 kLowDosTime = 0x210000;
|
||||
|
||||
bool FileTime_To_DosTime(const FILETIME &ft, UInt32 &dosTime) throw()
|
||||
{
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
|
||||
WORD datePart, timePart;
|
||||
if (!::FileTimeToDosDateTime(&ft, &datePart, &timePart))
|
||||
{
|
||||
dosTime = (ft.dwHighDateTime >= 0x01C00000) ? kHighDosTime : kLowDosTime;
|
||||
return false;
|
||||
}
|
||||
dosTime = (((UInt32)datePart) << 16) + timePart;
|
||||
|
||||
#else
|
||||
|
||||
#define PERIOD_4 (4 * 365 + 1)
|
||||
#define PERIOD_100 (PERIOD_4 * 25 - 1)
|
||||
#define PERIOD_400 (PERIOD_100 * 4 + 1)
|
||||
|
||||
unsigned year, mon, day, hour, min, sec;
|
||||
UInt64 v64 = ft.dwLowDateTime | ((UInt64)ft.dwHighDateTime << 32);
|
||||
Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
unsigned temp;
|
||||
UInt32 v;
|
||||
v64 += (kNumTimeQuantumsInSecond * 2 - 1);
|
||||
v64 /= kNumTimeQuantumsInSecond;
|
||||
sec = (unsigned)(v64 % 60);
|
||||
v64 /= 60;
|
||||
min = (unsigned)(v64 % 60);
|
||||
v64 /= 60;
|
||||
hour = (unsigned)(v64 % 24);
|
||||
v64 /= 24;
|
||||
|
||||
v = (UInt32)v64;
|
||||
|
||||
year = kFileTimeStartYear + (unsigned)(v / PERIOD_400 * 400);
|
||||
v %= PERIOD_400;
|
||||
|
||||
temp = (unsigned)(v / PERIOD_100);
|
||||
if (temp == 4)
|
||||
temp = 3;
|
||||
year += temp * 100;
|
||||
v -= temp * PERIOD_100;
|
||||
|
||||
temp = v / PERIOD_4;
|
||||
if (temp == 25)
|
||||
temp = 24;
|
||||
year += temp * 4;
|
||||
v -= temp * PERIOD_4;
|
||||
|
||||
temp = v / 365;
|
||||
if (temp == 4)
|
||||
temp = 3;
|
||||
year += temp;
|
||||
v -= temp * 365;
|
||||
|
||||
if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
|
||||
ms[1] = 29;
|
||||
for (mon = 1; mon <= 12; mon++)
|
||||
{
|
||||
unsigned s = ms[mon - 1];
|
||||
if (v < s)
|
||||
break;
|
||||
v -= s;
|
||||
}
|
||||
day = (unsigned)v + 1;
|
||||
|
||||
dosTime = kLowDosTime;
|
||||
if (year < kDosTimeStartYear)
|
||||
return false;
|
||||
year -= kDosTimeStartYear;
|
||||
dosTime = kHighDosTime;
|
||||
if (year >= 128)
|
||||
return false;
|
||||
dosTime =
|
||||
((UInt32)year << 25)
|
||||
| ((UInt32)mon << 21)
|
||||
| ((UInt32)day << 16)
|
||||
| ((UInt32)hour << 11)
|
||||
| ((UInt32)min << 5)
|
||||
| ((UInt32)sec >> 1);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool UtcFileTime_To_LocalDosTime(const FILETIME &utc, UInt32 &dosTime) throw()
|
||||
{
|
||||
FILETIME loc = { 0, 0 };
|
||||
const UInt64 u1 = FILETIME_To_UInt64(utc);
|
||||
const UInt64 kDelta = ((UInt64)1 << 41); // it's larger than quantums in 1 sec.
|
||||
if (u1 >= kDelta)
|
||||
{
|
||||
if (!FileTimeToLocalFileTime(&utc, &loc))
|
||||
loc = utc;
|
||||
else
|
||||
{
|
||||
const UInt64 u2 = FILETIME_To_UInt64(loc);
|
||||
const UInt64 delta = u1 < u2 ? (u2 - u1) : (u1 - u2);
|
||||
if (delta > kDelta) // if FileTimeToLocalFileTime() overflow, we use UTC time
|
||||
loc = utc;
|
||||
}
|
||||
}
|
||||
return FileTime_To_DosTime(loc, dosTime);
|
||||
}
|
||||
|
||||
UInt64 UnixTime_To_FileTime64(UInt32 unixTime) throw()
|
||||
{
|
||||
return (kUnixTimeOffset + (UInt64)unixTime) * kNumTimeQuantumsInSecond;
|
||||
}
|
||||
|
||||
void UnixTime_To_FileTime(UInt32 unixTime, FILETIME &ft) throw()
|
||||
{
|
||||
const UInt64 v = UnixTime_To_FileTime64(unixTime);
|
||||
ft.dwLowDateTime = (DWORD)v;
|
||||
ft.dwHighDateTime = (DWORD)(v >> 32);
|
||||
}
|
||||
|
||||
UInt64 UnixTime64_To_FileTime64(Int64 unixTime) throw()
|
||||
{
|
||||
return (UInt64)((Int64)kUnixTimeOffset + unixTime) * kNumTimeQuantumsInSecond;
|
||||
}
|
||||
|
||||
|
||||
bool UnixTime64_To_FileTime64(Int64 unixTime, UInt64 &fileTime) throw()
|
||||
{
|
||||
if (unixTime > (Int64)(kNumSecondsInFileTime - kUnixTimeOffset))
|
||||
{
|
||||
fileTime = (UInt64)(Int64)-1;
|
||||
return false;
|
||||
}
|
||||
if (unixTime < -(Int64)kUnixTimeOffset)
|
||||
{
|
||||
fileTime = 0;
|
||||
return false;
|
||||
}
|
||||
fileTime = UnixTime64_To_FileTime64(unixTime);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool UnixTime64_To_FileTime(Int64 unixTime, FILETIME &ft) throw()
|
||||
{
|
||||
UInt64 v;
|
||||
const bool res = UnixTime64_To_FileTime64(unixTime, v);
|
||||
ft.dwLowDateTime = (DWORD)v;
|
||||
ft.dwHighDateTime = (DWORD)(v >> 32);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
Int64 FileTime_To_UnixTime64(const FILETIME &ft) throw()
|
||||
{
|
||||
const UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
|
||||
return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset;
|
||||
}
|
||||
|
||||
Int64 FileTime_To_UnixTime64_and_Quantums(const FILETIME &ft, UInt32 &quantums) throw()
|
||||
{
|
||||
const UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
|
||||
quantums = (UInt32)(winTime % kNumTimeQuantumsInSecond);
|
||||
return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset;
|
||||
}
|
||||
|
||||
bool FileTime_To_UnixTime(const FILETIME &ft, UInt32 &unixTime) throw()
|
||||
{
|
||||
UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
|
||||
winTime /= kNumTimeQuantumsInSecond;
|
||||
if (winTime < kUnixTimeOffset)
|
||||
{
|
||||
unixTime = 0;
|
||||
return false;
|
||||
}
|
||||
winTime -= kUnixTimeOffset;
|
||||
if (winTime > (UInt32)0xFFFFFFFF)
|
||||
{
|
||||
unixTime = (UInt32)0xFFFFFFFF;
|
||||
return false;
|
||||
}
|
||||
unixTime = (UInt32)winTime;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day,
|
||||
unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw()
|
||||
{
|
||||
resSeconds = 0;
|
||||
if (year < kFileTimeStartYear || year >= 10000 || month < 1 || month > 12 ||
|
||||
day < 1 || day > 31 || hour > 23 || min > 59 || sec > 59)
|
||||
return false;
|
||||
const unsigned numYears = year - kFileTimeStartYear;
|
||||
UInt32 numDays = (UInt32)((UInt32)numYears * 365 + numYears / 4 - numYears / 100 + numYears / 400);
|
||||
Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
|
||||
ms[1] = 29;
|
||||
month--;
|
||||
for (unsigned i = 0; i < month; i++)
|
||||
numDays += ms[i];
|
||||
numDays += (UInt32)(day - 1);
|
||||
resSeconds = ((UInt64)(numDays * 24 + hour) * 60 + min) * 60 + sec;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* docs: TIME_UTC is not defined on many platforms:
|
||||
glibc 2.15, macOS 10.13
|
||||
FreeBSD 11.0, NetBSD 7.1, OpenBSD 6.0,
|
||||
Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, Solaris 11.3,
|
||||
Cygwin 2.9, mingw, MSVC 14, Android 9.0.
|
||||
Android NDK defines TIME_UTC but doesn't have the timespec_get().
|
||||
*/
|
||||
#if defined(TIME_UTC) && !defined(__ANDROID__)
|
||||
#define ZIP7_USE_timespec_get
|
||||
// #pragma message("ZIP7_USE_timespec_get")
|
||||
#elif defined(CLOCK_REALTIME)
|
||||
#define ZIP7_USE_clock_gettime
|
||||
// #pragma message("ZIP7_USE_clock_gettime")
|
||||
#endif
|
||||
|
||||
void GetCurUtc_FiTime(CFiTime &ft) throw()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
// Both variants provide same low resolution on WinXP: about 15 ms.
|
||||
// But GetSystemTimeAsFileTime is much faster.
|
||||
#ifdef UNDER_CE
|
||||
SYSTEMTIME st;
|
||||
GetSystemTime(&st);
|
||||
SystemTimeToFileTime(&st, &ft);
|
||||
#else
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
FiTime_Clear(ft);
|
||||
#ifdef ZIP7_USE_timespec_get
|
||||
timespec_get(&ft, TIME_UTC);
|
||||
#elif defined ZIP7_USE_clock_gettime
|
||||
|
||||
#if defined(_AIX)
|
||||
{
|
||||
timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
ft.tv_sec = ts.tv_sec;
|
||||
ft.tv_nsec = ts.tv_nsec;
|
||||
}
|
||||
#else
|
||||
clock_gettime(CLOCK_REALTIME, &ft);
|
||||
#endif
|
||||
|
||||
#else
|
||||
struct timeval now;
|
||||
if (gettimeofday(&now, NULL) == 0)
|
||||
{
|
||||
ft.tv_sec = now.tv_sec;
|
||||
// timeval::tv_usec can be 64-bit signed in some cases
|
||||
// timespec::tv_nsec can be 32-bit signed in some cases
|
||||
ft.tv_nsec =
|
||||
(Int32) // to eliminate compiler conversion error
|
||||
(now.tv_usec * 1000);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
void GetCurUtcFileTime(FILETIME &ft) throw()
|
||||
{
|
||||
UInt64 v = 0;
|
||||
#if defined(ZIP7_USE_timespec_get) || \
|
||||
defined(ZIP7_USE_clock_gettime)
|
||||
timespec ts;
|
||||
#if defined(ZIP7_USE_timespec_get)
|
||||
if (timespec_get(&ts, TIME_UTC))
|
||||
#else
|
||||
if (clock_gettime(CLOCK_REALTIME, &ts) == 0)
|
||||
#endif
|
||||
{
|
||||
v = ((UInt64)ts.tv_sec + kUnixTimeOffset) *
|
||||
kNumTimeQuantumsInSecond + (UInt64)ts.tv_nsec / 100;
|
||||
}
|
||||
#else
|
||||
struct timeval now;
|
||||
if (gettimeofday(&now, NULL) == 0)
|
||||
{
|
||||
v = ((UInt64)now.tv_sec + kUnixTimeOffset) *
|
||||
kNumTimeQuantumsInSecond + (UInt64)now.tv_usec * 10;
|
||||
}
|
||||
#endif
|
||||
ft.dwLowDateTime = (DWORD)v;
|
||||
ft.dwHighDateTime = (DWORD)(v >> 32);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
}}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/*
|
||||
void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec)
|
||||
{
|
||||
if (prec == k_PropVar_TimePrec_0
|
||||
|| prec == k_PropVar_TimePrec_HighPrec
|
||||
|| prec >= k_PropVar_TimePrec_100ns)
|
||||
return;
|
||||
UInt64 v = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
|
||||
|
||||
int numDigits = (int)prec - (int)k_PropVar_TimePrec_Base;
|
||||
UInt32 d;
|
||||
if (prec == k_PropVar_TimePrec_DOS)
|
||||
{
|
||||
// we round up as windows DosDateTimeToFileTime()
|
||||
v += NWindows::NTime::kNumTimeQuantumsInSecond * 2 - 1;
|
||||
d = NWindows::NTime::kNumTimeQuantumsInSecond * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prec == k_PropVar_TimePrec_Unix)
|
||||
numDigits = 0;
|
||||
else if (numDigits < 0)
|
||||
return;
|
||||
d = 1;
|
||||
for (unsigned k = numDigits; k < 7; k++)
|
||||
d *= 10;
|
||||
}
|
||||
v /= d;
|
||||
v *= d;
|
||||
ft.dwLowDateTime = (DWORD)v;
|
||||
ft.dwHighDateTime = (DWORD)(v >> 32);
|
||||
}
|
||||
*/
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec)
|
||||
{
|
||||
if (prec >= k_PropVar_TimePrec_1ns
|
||||
|| prec == k_PropVar_TimePrec_HighPrec)
|
||||
return;
|
||||
|
||||
int numDigits = (int)prec - (int)k_PropVar_TimePrec_Base;
|
||||
UInt32 d;
|
||||
if (prec == k_PropVar_TimePrec_Unix ||
|
||||
prec == (int)k_PropVar_TimePrec_Base)
|
||||
{
|
||||
ft.tv_nsec = 0;
|
||||
return;
|
||||
}
|
||||
if (prec == k_PropVar_TimePrec_DOS)
|
||||
{
|
||||
// we round up as windows DosDateTimeToFileTime()
|
||||
const unsigned sec1 = (ft.tv_sec & 1);
|
||||
if (ft.tv_nsec == 0 && sec1 == 0)
|
||||
return;
|
||||
ft.tv_nsec = 0;
|
||||
ft.tv_sec += 2 - sec1;
|
||||
return;
|
||||
}
|
||||
{
|
||||
if (prec == k_PropVar_TimePrec_0
|
||||
|| numDigits < 0)
|
||||
numDigits = 7;
|
||||
d = 1;
|
||||
for (unsigned k = numDigits; k < 9; k++)
|
||||
d *= 10;
|
||||
ft.tv_nsec /= d;
|
||||
ft.tv_nsec *= d;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
int Compare_FiTime(const CFiTime *a1, const CFiTime *a2)
|
||||
{
|
||||
if (a1->tv_sec < a2->tv_sec) return -1;
|
||||
if (a1->tv_sec > a2->tv_sec) return 1;
|
||||
if (a1->tv_nsec < a2->tv_nsec) return -1;
|
||||
if (a1->tv_nsec > a2->tv_nsec) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool FILETIME_To_timespec(const FILETIME &ft, CFiTime &ts)
|
||||
{
|
||||
UInt32 quantums;
|
||||
const Int64 sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(ft, quantums);
|
||||
// time_t is long
|
||||
const time_t sec2 = (time_t)sec;
|
||||
if (sec2 == sec)
|
||||
{
|
||||
ts.tv_sec = sec2;
|
||||
ts.tv_nsec = (Int32)(quantums * 100);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FiTime_To_FILETIME_ns100(const CFiTime &ts, FILETIME &ft, unsigned &ns100)
|
||||
{
|
||||
const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100);
|
||||
ns100 = (unsigned)((UInt64)ts.tv_nsec % 100);
|
||||
ft.dwLowDateTime = (DWORD)v;
|
||||
ft.dwHighDateTime = (DWORD)(v >> 32);
|
||||
}
|
||||
|
||||
void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft)
|
||||
{
|
||||
const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100);
|
||||
ft.dwLowDateTime = (DWORD)v;
|
||||
ft.dwHighDateTime = (DWORD)(v >> 32);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,154 @@
|
||||
// Windows/TimeUtils.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_TIME_UTILS_H
|
||||
#define ZIP7_INC_WINDOWS_TIME_UTILS_H
|
||||
|
||||
#include "../Common/MyTypes.h"
|
||||
#include "../Common/MyWindows.h"
|
||||
#include "PropVariant.h"
|
||||
|
||||
inline UInt64 FILETIME_To_UInt64(const FILETIME &ft)
|
||||
{
|
||||
return (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
|
||||
}
|
||||
|
||||
inline void FILETIME_Clear(FILETIME &ft)
|
||||
{
|
||||
ft.dwLowDateTime = 0;
|
||||
ft.dwHighDateTime = 0;
|
||||
}
|
||||
|
||||
inline bool FILETIME_IsZero(const FILETIME &ft)
|
||||
{
|
||||
return (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define CFiTime FILETIME
|
||||
#define Compare_FiTime ::CompareFileTime
|
||||
inline void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft)
|
||||
{
|
||||
ft = ts;
|
||||
}
|
||||
/*
|
||||
inline void FILETIME_To_FiTime(const FILETIME &ft, CFiTime &ts)
|
||||
{
|
||||
ts = ft;
|
||||
}
|
||||
*/
|
||||
inline void FiTime_Clear(CFiTime &ft)
|
||||
{
|
||||
ft.dwLowDateTime = 0;
|
||||
ft.dwHighDateTime = 0;
|
||||
}
|
||||
#else
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined(_AIX)
|
||||
#define CFiTime st_timespec
|
||||
#else
|
||||
#define CFiTime timespec
|
||||
#endif
|
||||
int Compare_FiTime(const CFiTime *a1, const CFiTime *a2);
|
||||
bool FILETIME_To_timespec(const FILETIME &ft, CFiTime &ts);
|
||||
void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft);
|
||||
void FiTime_To_FILETIME_ns100(const CFiTime &ts, FILETIME &ft, unsigned &ns100);
|
||||
inline void FiTime_Clear(CFiTime &ft)
|
||||
{
|
||||
ft.tv_sec = 0;
|
||||
ft.tv_nsec = 0;
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define ST_MTIME(st) st.st_mtimespec
|
||||
#define ST_ATIME(st) st.st_atimespec
|
||||
#define ST_CTIME(st) st.st_ctimespec
|
||||
#elif defined(__QNXNTO__) && defined(__ARM__) && !defined(__aarch64__)
|
||||
// QNX armv7le (32-bit) for "struct stat" timestamps uses time_t instead of timespec
|
||||
inline CFiTime ST_MTIME(const struct stat &st)
|
||||
{ timespec ts; ts.tv_sec = st.st_mtime; ts.tv_nsec = 0; return ts; }
|
||||
inline CFiTime ST_ATIME(const struct stat &st)
|
||||
{ timespec ts; ts.tv_sec = st.st_atime; ts.tv_nsec = 0; return ts; }
|
||||
inline CFiTime ST_CTIME(const struct stat &st)
|
||||
{ timespec ts; ts.tv_sec = st.st_ctime; ts.tv_nsec = 0; return ts; }
|
||||
#else
|
||||
#define ST_MTIME(st) st.st_mtim
|
||||
#define ST_ATIME(st) st.st_atim
|
||||
#define ST_CTIME(st) st.st_ctim
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec);
|
||||
|
||||
namespace NWindows {
|
||||
namespace NTime {
|
||||
|
||||
bool DosTime_To_FileTime(UInt32 dosTime, FILETIME &fileTime) throw();
|
||||
bool UtcFileTime_To_LocalDosTime(const FILETIME &utc, UInt32 &dosTime) throw();
|
||||
bool FileTime_To_DosTime(const FILETIME &fileTime, UInt32 &dosTime) throw();
|
||||
|
||||
// UInt32 Unix Time : for dates 1970-2106
|
||||
UInt64 UnixTime_To_FileTime64(UInt32 unixTime) throw();
|
||||
void UnixTime_To_FileTime(UInt32 unixTime, FILETIME &fileTime) throw();
|
||||
|
||||
// Int64 Unix Time : negative values for dates before 1970
|
||||
UInt64 UnixTime64_To_FileTime64(Int64 unixTime) throw(); // no check
|
||||
bool UnixTime64_To_FileTime64(Int64 unixTime, UInt64 &fileTime) throw();
|
||||
bool UnixTime64_To_FileTime(Int64 unixTime, FILETIME &fileTime) throw();
|
||||
|
||||
Int64 FileTime64_To_UnixTime64(UInt64 ft64) throw();
|
||||
bool FileTime_To_UnixTime(const FILETIME &fileTime, UInt32 &unixTime) throw();
|
||||
Int64 FileTime_To_UnixTime64(const FILETIME &ft) throw();
|
||||
Int64 FileTime_To_UnixTime64_and_Quantums(const FILETIME &ft, UInt32 &quantums) throw();
|
||||
|
||||
bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day,
|
||||
unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw();
|
||||
|
||||
void GetCurUtc_FiTime(CFiTime &ft) throw();
|
||||
#ifdef _WIN32
|
||||
#define GetCurUtcFileTime GetCurUtc_FiTime
|
||||
#else
|
||||
void GetCurUtcFileTime(FILETIME &ft) throw();
|
||||
#endif
|
||||
|
||||
}}
|
||||
|
||||
inline void PropVariant_SetFrom_UnixTime(NWindows::NCOM::CPropVariant &prop, UInt32 unixTime)
|
||||
{
|
||||
FILETIME ft;
|
||||
NWindows::NTime::UnixTime_To_FileTime(unixTime, ft);
|
||||
prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Unix);
|
||||
}
|
||||
|
||||
inline void PropVariant_SetFrom_NtfsTime(NWindows::NCOM::CPropVariant &prop, const FILETIME &ft)
|
||||
{
|
||||
prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_100ns);
|
||||
}
|
||||
|
||||
inline void PropVariant_SetFrom_FiTime(NWindows::NCOM::CPropVariant &prop, const CFiTime &fts)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
PropVariant_SetFrom_NtfsTime(prop, fts);
|
||||
#else
|
||||
unsigned ns100;
|
||||
FILETIME ft;
|
||||
FiTime_To_FILETIME_ns100(fts, ft, ns100);
|
||||
prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, ns100);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool PropVariant_SetFrom_DosTime(NWindows::NCOM::CPropVariant &prop, UInt32 dosTime)
|
||||
{
|
||||
FILETIME localFileTime, utc;
|
||||
if (!NWindows::NTime::DosTime_To_FileTime(dosTime, localFileTime))
|
||||
return false;
|
||||
if (!LocalFileTimeToFileTime(&localFileTime, &utc))
|
||||
return false;
|
||||
prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_DOS);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,179 @@
|
||||
// Windows/Window.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
#include "../Common/StringConvert.h"
|
||||
#endif
|
||||
#include "Window.h"
|
||||
|
||||
#ifndef _UNICODE
|
||||
extern bool g_IsNT;
|
||||
#endif
|
||||
|
||||
namespace NWindows {
|
||||
|
||||
#ifndef _UNICODE
|
||||
ATOM MyRegisterClass(CONST WNDCLASSW *wndClass)
|
||||
{
|
||||
if (g_IsNT)
|
||||
return RegisterClassW(wndClass);
|
||||
WNDCLASSA wndClassA;
|
||||
wndClassA.style = wndClass->style;
|
||||
wndClassA.lpfnWndProc = wndClass->lpfnWndProc;
|
||||
wndClassA.cbClsExtra = wndClass->cbClsExtra;
|
||||
wndClassA.cbWndExtra = wndClass->cbWndExtra;
|
||||
wndClassA.hInstance = wndClass->hInstance;
|
||||
wndClassA.hIcon = wndClass->hIcon;
|
||||
wndClassA.hCursor = wndClass->hCursor;
|
||||
wndClassA.hbrBackground = wndClass->hbrBackground;
|
||||
AString menuName;
|
||||
AString className;
|
||||
if (IS_INTRESOURCE(wndClass->lpszMenuName))
|
||||
wndClassA.lpszMenuName = (LPCSTR)wndClass->lpszMenuName;
|
||||
else
|
||||
{
|
||||
menuName = GetSystemString(wndClass->lpszMenuName);
|
||||
wndClassA.lpszMenuName = menuName;
|
||||
}
|
||||
if (IS_INTRESOURCE(wndClass->lpszClassName))
|
||||
wndClassA.lpszClassName = (LPCSTR)wndClass->lpszClassName;
|
||||
else
|
||||
{
|
||||
className = GetSystemString(wndClass->lpszClassName);
|
||||
wndClassA.lpszClassName = className;
|
||||
}
|
||||
return RegisterClassA(&wndClassA);
|
||||
}
|
||||
|
||||
bool CWindow::Create(LPCWSTR className,
|
||||
LPCWSTR windowName, DWORD style,
|
||||
int x, int y, int width, int height,
|
||||
HWND parentWindow, HMENU idOrHMenu,
|
||||
HINSTANCE instance, LPVOID createParam)
|
||||
{
|
||||
if (g_IsNT)
|
||||
{
|
||||
_window = ::CreateWindowW(className, windowName,
|
||||
style, x, y, width, height, parentWindow,
|
||||
idOrHMenu, instance, createParam);
|
||||
return (_window != NULL);
|
||||
}
|
||||
return Create(GetSystemString(className), GetSystemString(windowName),
|
||||
style, x, y, width, height, parentWindow,
|
||||
idOrHMenu, instance, createParam);
|
||||
}
|
||||
|
||||
bool CWindow::CreateEx(DWORD exStyle, LPCWSTR className,
|
||||
LPCWSTR windowName, DWORD style,
|
||||
int x, int y, int width, int height,
|
||||
HWND parentWindow, HMENU idOrHMenu,
|
||||
HINSTANCE instance, LPVOID createParam)
|
||||
{
|
||||
if (g_IsNT)
|
||||
{
|
||||
_window = ::CreateWindowExW(exStyle, className, windowName,
|
||||
style, x, y, width, height, parentWindow,
|
||||
idOrHMenu, instance, createParam);
|
||||
return (_window != NULL);
|
||||
}
|
||||
AString classNameA;
|
||||
LPCSTR classNameP;
|
||||
if (IS_INTRESOURCE(className))
|
||||
classNameP = (LPCSTR)className;
|
||||
else
|
||||
{
|
||||
classNameA = GetSystemString(className);
|
||||
classNameP = classNameA;
|
||||
}
|
||||
AString windowNameA;
|
||||
LPCSTR windowNameP;
|
||||
if (IS_INTRESOURCE(windowName))
|
||||
windowNameP = (LPCSTR)windowName;
|
||||
else
|
||||
{
|
||||
windowNameA = GetSystemString(windowName);
|
||||
windowNameP = windowNameA;
|
||||
}
|
||||
return CreateEx(exStyle, classNameP, windowNameP,
|
||||
style, x, y, width, height, parentWindow,
|
||||
idOrHMenu, instance, createParam);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef _UNICODE
|
||||
bool MySetWindowText(HWND wnd, LPCWSTR s)
|
||||
{
|
||||
if (g_IsNT)
|
||||
return BOOLToBool(::SetWindowTextW(wnd, s));
|
||||
return BOOLToBool(::SetWindowTextA(wnd, UnicodeStringToMultiByte(s)));
|
||||
}
|
||||
#endif
|
||||
|
||||
bool CWindow::GetText(CSysString &s) const
|
||||
{
|
||||
s.Empty();
|
||||
unsigned len = (unsigned)GetTextLength();
|
||||
if (len == 0)
|
||||
return (::GetLastError() == ERROR_SUCCESS);
|
||||
TCHAR *p = s.GetBuf(len);
|
||||
{
|
||||
const unsigned len2 = (unsigned)GetText(p, (int)(len + 1));
|
||||
if (len > len2)
|
||||
len = len2;
|
||||
}
|
||||
s.ReleaseBuf_CalcLen(len);
|
||||
if (len == 0)
|
||||
return (::GetLastError() == ERROR_SUCCESS);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
bool CWindow::GetText(UString &s) const
|
||||
{
|
||||
if (g_IsNT)
|
||||
{
|
||||
s.Empty();
|
||||
unsigned len = (unsigned)GetWindowTextLengthW(_window);
|
||||
if (len == 0)
|
||||
return (::GetLastError() == ERROR_SUCCESS);
|
||||
wchar_t *p = s.GetBuf(len);
|
||||
{
|
||||
const unsigned len2 = (unsigned)GetWindowTextW(_window, p, (int)(len + 1));
|
||||
if (len > len2)
|
||||
len = len2;
|
||||
}
|
||||
s.ReleaseBuf_CalcLen(len);
|
||||
if (len == 0)
|
||||
return (::GetLastError() == ERROR_SUCCESS);
|
||||
return true;
|
||||
}
|
||||
CSysString sysString;
|
||||
const bool result = GetText(sysString);
|
||||
MultiByteToUnicodeString2(s, sysString);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
bool CWindow::ModifyStyleBase(int styleOffset,
|
||||
DWORD remove, DWORD add, UINT flags)
|
||||
{
|
||||
DWORD style = GetWindowLong(styleOffset);
|
||||
DWORD newStyle = (style & ~remove) | add;
|
||||
if (style == newStyle)
|
||||
return false; // it is not good
|
||||
|
||||
SetWindowLong(styleOffset, newStyle);
|
||||
if (flags != 0)
|
||||
{
|
||||
::SetWindowPos(_window, NULL, 0, 0, 0, 0,
|
||||
SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | flags);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
@@ -0,0 +1,363 @@
|
||||
// Windows/Window.h
|
||||
|
||||
#ifndef ZIP7_INC_WINDOWS_WINDOW_H
|
||||
#define ZIP7_INC_WINDOWS_WINDOW_H
|
||||
|
||||
#include "../Common/MyWindows.h"
|
||||
#include "../Common/MyString.h"
|
||||
|
||||
#include "Defs.h"
|
||||
|
||||
#ifndef UNDER_CE
|
||||
#ifdef WM_CHANGEUISTATE
|
||||
#define Z7_WIN_WM_CHANGEUISTATE WM_CHANGEUISTATE
|
||||
#define Z7_WIN_WM_UPDATEUISTATE WM_UPDATEUISTATE
|
||||
#define Z7_WIN_WM_QUERYUISTATE WM_QUERYUISTATE
|
||||
#else
|
||||
// these are defined for (_WIN32_WINNT >= 0x0500):
|
||||
#define Z7_WIN_WM_CHANGEUISTATE 0x0127
|
||||
#define Z7_WIN_WM_UPDATEUISTATE 0x0128
|
||||
#define Z7_WIN_WM_QUERYUISTATE 0x0129
|
||||
#endif
|
||||
|
||||
#ifdef UIS_SET
|
||||
|
||||
#define Z7_WIN_UIS_SET UIS_SET
|
||||
#define Z7_WIN_UIS_CLEAR UIS_CLEAR
|
||||
#define Z7_WIN_UIS_INITIALIZE UIS_INITIALIZE
|
||||
|
||||
#define Z7_WIN_UISF_HIDEFOCUS UISF_HIDEFOCUS
|
||||
#define Z7_WIN_UISF_HIDEACCEL UISF_HIDEACCEL
|
||||
|
||||
#else
|
||||
// these are defined for (_WIN32_WINNT >= 0x0500):
|
||||
// LOWORD(wParam) values in WM_*UISTATE
|
||||
#define Z7_WIN_UIS_SET 1
|
||||
#define Z7_WIN_UIS_CLEAR 2
|
||||
#define Z7_WIN_UIS_INITIALIZE 3
|
||||
|
||||
// HIWORD(wParam) values in WM_*UISTATE
|
||||
#define Z7_WIN_UISF_HIDEFOCUS 0x1
|
||||
#define Z7_WIN_UISF_HIDEACCEL 0x2
|
||||
// defined for for (_WIN32_WINNT >= 0x0501):
|
||||
// #define Z7_WIN_UISF_ACTIVE 0x4
|
||||
|
||||
#endif
|
||||
|
||||
#endif // UNDER_CE
|
||||
|
||||
|
||||
#ifdef Z7_OLD_WIN_SDK
|
||||
|
||||
// #define VK_OEM_1 0xBA // ';:' for US
|
||||
#define VK_OEM_PLUS 0xBB // '+' any country
|
||||
// #define VK_OEM_COMMA 0xBC // ',' any country
|
||||
#define VK_OEM_MINUS 0xBD // '-' any country
|
||||
// #define VK_OEM_PERIOD 0xBE // '.' any country
|
||||
// #define VK_OEM_2 0xBF // '/?' for US
|
||||
// #define VK_OEM_3 0xC0 // '`~' for US
|
||||
|
||||
// #ifndef GWLP_USERDATA
|
||||
#define GWLP_WNDPROC (-4)
|
||||
#define GWLP_USERDATA (-21)
|
||||
// #endif
|
||||
#define DWLP_MSGRESULT 0
|
||||
// #define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT)
|
||||
// #define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC)
|
||||
|
||||
#define BTNS_BUTTON TBSTYLE_BUTTON // 0x0000
|
||||
|
||||
/*
|
||||
vc6 defines INT_PTR via long:
|
||||
typedef long INT_PTR, *PINT_PTR;
|
||||
typedef unsigned long UINT_PTR, *PUINT_PTR;
|
||||
but newer sdk (sdk2003+) defines INT_PTR via int:
|
||||
typedef _W64 int INT_PTR, *PINT_PTR;
|
||||
typedef _W64 unsigned int UINT_PTR, *PUINT_PTR;
|
||||
*/
|
||||
|
||||
#define IS_INTRESOURCE(_r) (((ULONG_PTR)(_r) >> 16) == 0)
|
||||
|
||||
#define GetWindowLongPtrA GetWindowLongA
|
||||
#define GetWindowLongPtrW GetWindowLongW
|
||||
#ifdef UNICODE
|
||||
#define GetWindowLongPtr GetWindowLongPtrW
|
||||
#else
|
||||
#define GetWindowLongPtr GetWindowLongPtrA
|
||||
#endif // !UNICODE
|
||||
|
||||
#define SetWindowLongPtrA SetWindowLongA
|
||||
#define SetWindowLongPtrW SetWindowLongW
|
||||
#ifdef UNICODE
|
||||
#define SetWindowLongPtr SetWindowLongPtrW
|
||||
#else
|
||||
#define SetWindowLongPtr SetWindowLongPtrA
|
||||
#endif // !UNICODE
|
||||
|
||||
#define ListView_SetCheckState(hwndLV, i, fCheck) \
|
||||
ListView_SetItemState(hwndLV, i, INDEXTOSTATEIMAGEMASK((fCheck)?2:1), LVIS_STATEIMAGEMASK)
|
||||
|
||||
#endif // Z7_OLD_WIN_SDK
|
||||
|
||||
inline bool LRESULTToBool(LRESULT v) { return (v != FALSE); }
|
||||
|
||||
#define MY_int_TO_WPARAM(i) ((WPARAM)(INT_PTR)(i))
|
||||
|
||||
namespace NWindows {
|
||||
|
||||
inline ATOM MyRegisterClass(CONST WNDCLASS *wndClass)
|
||||
{ return ::RegisterClass(wndClass); }
|
||||
|
||||
#ifndef _UNICODE
|
||||
ATOM MyRegisterClass(CONST WNDCLASSW *wndClass);
|
||||
#endif
|
||||
|
||||
#ifdef _UNICODE
|
||||
inline bool MySetWindowText(HWND wnd, LPCWSTR s) { return BOOLToBool(::SetWindowText(wnd, s)); }
|
||||
#else
|
||||
bool MySetWindowText(HWND wnd, LPCWSTR s);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef UNDER_CE
|
||||
#define GWLP_USERDATA GWL_USERDATA
|
||||
#define GWLP_WNDPROC GWL_WNDPROC
|
||||
#define BTNS_BUTTON TBSTYLE_BUTTON
|
||||
#define WC_COMBOBOXW L"ComboBox"
|
||||
#define DWLP_MSGRESULT DWL_MSGRESULT
|
||||
#endif
|
||||
|
||||
class CWindow
|
||||
{
|
||||
Z7_CLASS_NO_COPY(CWindow)
|
||||
private:
|
||||
// bool ModifyStyleBase(int styleOffset, DWORD remove, DWORD add, UINT flags);
|
||||
protected:
|
||||
HWND _window;
|
||||
public:
|
||||
CWindow(HWND newWindow = NULL): _window(newWindow) {}
|
||||
CWindow& operator=(HWND newWindow)
|
||||
{
|
||||
_window = newWindow;
|
||||
return *this;
|
||||
}
|
||||
operator HWND() const { return _window; }
|
||||
void Attach(HWND newWindow) { _window = newWindow; }
|
||||
HWND Detach()
|
||||
{
|
||||
HWND window = _window;
|
||||
_window = NULL;
|
||||
return window;
|
||||
}
|
||||
|
||||
bool Foreground() { return BOOLToBool(::SetForegroundWindow(_window)); }
|
||||
|
||||
HWND GetParent() const { return ::GetParent(_window); }
|
||||
bool GetWindowRect(LPRECT rect) const { return BOOLToBool(::GetWindowRect(_window,rect)); }
|
||||
#ifndef UNDER_CE
|
||||
bool IsZoomed() const { return BOOLToBool(::IsZoomed(_window)); }
|
||||
#endif
|
||||
bool ClientToScreen(LPPOINT point) const { return BOOLToBool(::ClientToScreen(_window, point)); }
|
||||
bool ScreenToClient(LPPOINT point) const { return BOOLToBool(::ScreenToClient(_window, point)); }
|
||||
|
||||
bool CreateEx(DWORD exStyle, LPCTSTR className,
|
||||
LPCTSTR windowName, DWORD style,
|
||||
int x, int y, int width, int height,
|
||||
HWND parentWindow, HMENU idOrHMenu,
|
||||
HINSTANCE instance, LPVOID createParam)
|
||||
{
|
||||
_window = ::CreateWindowEx(exStyle, className, windowName,
|
||||
style, x, y, width, height, parentWindow,
|
||||
idOrHMenu, instance, createParam);
|
||||
return (_window != NULL);
|
||||
}
|
||||
|
||||
bool Create(LPCTSTR className,
|
||||
LPCTSTR windowName, DWORD style,
|
||||
int x, int y, int width, int height,
|
||||
HWND parentWindow, HMENU idOrHMenu,
|
||||
HINSTANCE instance, LPVOID createParam)
|
||||
{
|
||||
_window = ::CreateWindow(className, windowName,
|
||||
style, x, y, width, height, parentWindow,
|
||||
idOrHMenu, instance, createParam);
|
||||
return (_window != NULL);
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
bool Create(LPCWSTR className,
|
||||
LPCWSTR windowName, DWORD style,
|
||||
int x, int y, int width, int height,
|
||||
HWND parentWindow, HMENU idOrHMenu,
|
||||
HINSTANCE instance, LPVOID createParam);
|
||||
bool CreateEx(DWORD exStyle, LPCWSTR className,
|
||||
LPCWSTR windowName, DWORD style,
|
||||
int x, int y, int width, int height,
|
||||
HWND parentWindow, HMENU idOrHMenu,
|
||||
HINSTANCE instance, LPVOID createParam);
|
||||
#endif
|
||||
|
||||
|
||||
bool Destroy()
|
||||
{
|
||||
if (_window == NULL)
|
||||
return true;
|
||||
bool result = BOOLToBool(::DestroyWindow(_window));
|
||||
if (result)
|
||||
_window = NULL;
|
||||
return result;
|
||||
}
|
||||
bool IsWindow() { return BOOLToBool(::IsWindow(_window)); }
|
||||
bool Move(int x, int y, int width, int height, bool repaint = true)
|
||||
{ return BOOLToBool(::MoveWindow(_window, x, y, width, height, BoolToBOOL(repaint))); }
|
||||
|
||||
bool ChangeSubWindowSizeX(HWND hwnd, int xSize)
|
||||
{
|
||||
RECT rect;
|
||||
::GetWindowRect(hwnd, &rect);
|
||||
POINT p1;
|
||||
p1.x = rect.left;
|
||||
p1.y = rect.top;
|
||||
ScreenToClient(&p1);
|
||||
return BOOLToBool(::MoveWindow(hwnd, p1.x, p1.y, xSize, rect.bottom - rect.top, TRUE));
|
||||
}
|
||||
|
||||
void ScreenToClient(RECT *rect)
|
||||
{
|
||||
POINT p1, p2;
|
||||
p1.x = rect->left;
|
||||
p1.y = rect->top;
|
||||
p2.x = rect->right;
|
||||
p2.y = rect->bottom;
|
||||
ScreenToClient(&p1);
|
||||
ScreenToClient(&p2);
|
||||
|
||||
rect->left = p1.x;
|
||||
rect->top = p1.y;
|
||||
rect->right = p2.x;
|
||||
rect->bottom = p2.y;
|
||||
}
|
||||
|
||||
bool GetClientRect(LPRECT rect) { return BOOLToBool(::GetClientRect(_window, rect)); }
|
||||
bool Show(int cmdShow) { return BOOLToBool(::ShowWindow(_window, cmdShow)); }
|
||||
bool Show_Bool(bool show) { return Show(show ? SW_SHOW: SW_HIDE); }
|
||||
|
||||
#ifndef UNDER_CE
|
||||
bool SetPlacement(CONST WINDOWPLACEMENT *placement) { return BOOLToBool(::SetWindowPlacement(_window, placement)); }
|
||||
bool GetPlacement(WINDOWPLACEMENT *placement) { return BOOLToBool(::GetWindowPlacement(_window, placement)); }
|
||||
#endif
|
||||
bool Update() { return BOOLToBool(::UpdateWindow(_window)); }
|
||||
bool InvalidateRect(LPCRECT rect, bool backgroundErase = true)
|
||||
{ return BOOLToBool(::InvalidateRect(_window, rect, BoolToBOOL(backgroundErase))); }
|
||||
void SetRedraw(bool redraw = true) { SendMsg(WM_SETREDRAW, (WPARAM)BoolToBOOL(redraw), 0); }
|
||||
|
||||
LONG_PTR SetStyle(LONG_PTR style) { return SetLongPtr(GWL_STYLE, style); }
|
||||
// LONG_PTR SetStyle(DWORD style) { return SetLongPtr(GWL_STYLE, (LONG_PTR)style); }
|
||||
LONG_PTR GetStyle() const { return GetLongPtr(GWL_STYLE); }
|
||||
// bool MyIsMaximized() const { return ((GetStyle() & WS_MAXIMIZE) != 0); }
|
||||
|
||||
LONG_PTR SetLong(int index, LONG newLongPtr) { return ::SetWindowLong(_window, index, newLongPtr); }
|
||||
LONG_PTR GetLong(int index) const { return ::GetWindowLong(_window, index); }
|
||||
LONG_PTR SetUserDataLong(LONG newLongPtr) { return SetLong(GWLP_USERDATA, newLongPtr); }
|
||||
LONG_PTR GetUserDataLong() const { return GetLong(GWLP_USERDATA); }
|
||||
|
||||
|
||||
#ifdef UNDER_CE
|
||||
|
||||
LONG_PTR SetLongPtr(int index, LONG_PTR newLongPtr) { return SetLong(index, newLongPtr); }
|
||||
LONG_PTR GetLongPtr(int index) const { return GetLong(index); }
|
||||
|
||||
LONG_PTR SetUserDataLongPtr(LONG_PTR newLongPtr) { return SetUserDataLong(newLongPtr); }
|
||||
LONG_PTR GetUserDataLongPtr() const { return GetUserDataLong(); }
|
||||
|
||||
#else
|
||||
|
||||
LONG_PTR SetLongPtr(int index, LONG_PTR newLongPtr)
|
||||
{ return ::SetWindowLongPtr(_window, index,
|
||||
#ifndef _WIN64
|
||||
(LONG)
|
||||
#endif
|
||||
newLongPtr); }
|
||||
#ifndef _UNICODE
|
||||
LONG_PTR SetLongPtrW(int index, LONG_PTR newLongPtr)
|
||||
{ return ::SetWindowLongPtrW(_window, index,
|
||||
#ifndef _WIN64
|
||||
(LONG)
|
||||
#endif
|
||||
newLongPtr); }
|
||||
#endif
|
||||
|
||||
LONG_PTR GetLongPtr(int index) const { return ::GetWindowLongPtr(_window, index); }
|
||||
LONG_PTR SetUserDataLongPtr(LONG_PTR newLongPtr) { return SetLongPtr(GWLP_USERDATA, newLongPtr); }
|
||||
LONG_PTR GetUserDataLongPtr() const { return GetLongPtr(GWLP_USERDATA); }
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
bool ModifyStyle(HWND hWnd, DWORD remove, DWORD add, UINT flags = 0)
|
||||
{ return ModifyStyleBase(GWL_STYLE, remove, add, flags); }
|
||||
bool ModifyStyleEx(HWND hWnd, DWORD remove, DWORD add, UINT flags = 0)
|
||||
{ return ModifyStyleBase(GWL_EXSTYLE, remove, add, flags); }
|
||||
*/
|
||||
|
||||
HWND SetFocus() { return ::SetFocus(_window); }
|
||||
|
||||
LRESULT SendMsg(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
|
||||
{ return ::SendMessage(_window, message, wParam, lParam); }
|
||||
#ifndef _UNICODE
|
||||
LRESULT SendMsgW(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
|
||||
{ return ::SendMessageW(_window, message, wParam, lParam); }
|
||||
#endif
|
||||
|
||||
bool PostMsg(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
|
||||
{ return BOOLToBool(::PostMessage(_window, message, wParam, lParam)); }
|
||||
#ifndef _UNICODE
|
||||
bool PostMsgW(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
|
||||
{ return BOOLToBool(::PostMessageW(_window, message, wParam, lParam)); }
|
||||
#endif
|
||||
|
||||
bool SetText(LPCTSTR s) { return BOOLToBool(::SetWindowText(_window, s)); }
|
||||
#ifndef _UNICODE
|
||||
bool SetText(LPCWSTR s) { return MySetWindowText(_window, s); }
|
||||
#endif
|
||||
|
||||
int GetTextLength() const
|
||||
{ return GetWindowTextLength(_window); }
|
||||
int GetText(LPTSTR string, int maxCount) const
|
||||
{ return GetWindowText(_window, string, maxCount); }
|
||||
bool GetText(CSysString &s) const;
|
||||
#ifndef _UNICODE
|
||||
/*
|
||||
UINT GetText(LPWSTR string, int maxCount) const
|
||||
{ return GetWindowTextW(_window, string, maxCount); }
|
||||
*/
|
||||
bool GetText(UString &s) const;
|
||||
#endif
|
||||
|
||||
bool Enable(bool enable)
|
||||
{ return BOOLToBool(::EnableWindow(_window, BoolToBOOL(enable))); }
|
||||
|
||||
bool IsEnabled() const
|
||||
{ return BOOLToBool(::IsWindowEnabled(_window)); }
|
||||
|
||||
#ifndef UNDER_CE
|
||||
HMENU GetSystemMenu(bool revert)
|
||||
{ return ::GetSystemMenu(_window, BoolToBOOL(revert)); }
|
||||
#endif
|
||||
|
||||
UINT_PTR SetTimer(UINT_PTR idEvent, UINT elapse, TIMERPROC timerFunc = NULL)
|
||||
{ return ::SetTimer(_window, idEvent, elapse, timerFunc); }
|
||||
bool KillTimer(UINT_PTR idEvent)
|
||||
{return BOOLToBool(::KillTimer(_window, idEvent)); }
|
||||
|
||||
HICON SetIcon(WPARAM sizeType, HICON icon) { return (HICON)SendMsg(WM_SETICON, sizeType, (LPARAM)icon); }
|
||||
};
|
||||
|
||||
#define RECT_SIZE_X(r) ((r).right - (r).left)
|
||||
#define RECT_SIZE_Y(r) ((r).bottom - (r).top)
|
||||
|
||||
inline bool IsKeyDown(int virtKey) { return (::GetKeyState(virtKey) & 0x8000) != 0; }
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user