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:
Simone
2026-04-29 14:07:51 +02:00
commit d074cc7c07
3848 changed files with 1076682 additions and 0 deletions
+41
View File
@@ -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);
}
}}
*/
+86
View File
@@ -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
+130
View File
@@ -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;
}
}
+28
View File
@@ -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
+269
View File
@@ -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;
}
}
}
}
+43
View File
@@ -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
+10
View File
@@ -0,0 +1,10 @@
// Windows/Console.cpp
#include "StdAfx.h"
#include "Console.h"
namespace NWindows{
namespace NConsole{
}}
+52
View File
@@ -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,66 @@
// 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
}}
@@ -0,0 +1,77 @@
// 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
/* 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
}}
+213
View File
@@ -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
+19
View File
@@ -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 &param) 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 &param) 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
+178
View File
@@ -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
+103
View File
@@ -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
+17
View File
@@ -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
+133
View File
@@ -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;
}
}}
+16
View File
@@ -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
+172
View File
@@ -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
+347
View File
@@ -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)
Byte Type;
#endif
FString Name;
/*
#if !defined(_AIX) && !defined(__sun)
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)
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
+954
View File
@@ -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
+467
View File
@@ -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
+697
View File
@@ -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 {
}}}
+66
View File
@@ -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
+911
View File
@@ -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);
}
}}}
+142
View File
@@ -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
+187
View File
@@ -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
+31
View File
@@ -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
+39
View File
@@ -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;
}
}}
+55
View File
@@ -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
+127
View File
@@ -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
}}
+40
View File
@@ -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
+265
View File
@@ -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
}
+170
View File
@@ -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);
}
}}}
+20
View File
@@ -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
+398
View File
@@ -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
}}
+87
View File
@@ -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
+58
View File
@@ -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
+102
View File
@@ -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 &params, 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 &params)
{
CProcess process;
return process.Create(imageName, params, NULL);
}
}
+138
View File
@@ -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 &params, LPCWSTR curDir);
DWORD Wait() { return ::WaitForSingleObject(_handle, INFINITE); }
};
WRes MyCreateProcess(LPCWSTR imageName, const UString &params);
}
#endif
+393
View File
@@ -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;
}
}
}}
+173
View File
@@ -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
+474
View File
@@ -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;
}
}}
+96
View File
@@ -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;
}
}}
+150
View File
@@ -0,0 +1,150 @@
// Windows/SecurityUtils.h
#ifndef ZIP7_INC_WINDOWS_SECURITY_UTILS_H
#define ZIP7_INC_WINDOWS_SECURITY_UTILS_H
#include <NTSecAPI.h>
#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
+839
View File
@@ -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
}}
+129
View File
@@ -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
+11
View File
@@ -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
+421
View File
@@ -0,0 +1,421 @@
// 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__)
#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__)
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;
}
}}
+189
View File
@@ -0,0 +1,189 @@
// 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 {
#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);
}
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
UInt32 GetNumberOfProcessors();
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
+19
View File
@@ -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 &registers);
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
+46
View File
@@ -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
+467
View File
@@ -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
+146
View File
@@ -0,0 +1,146 @@
// 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
#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
+179
View File
@@ -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;
}
*/
}
+363
View File
@@ -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