Skip to content

Commit

Permalink
stdClipboard and stdDate changes
Browse files Browse the repository at this point in the history
  • Loading branch information
sancarn committed Sep 8, 2024
1 parent fade4da commit ea2849f
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 22 deletions.
6 changes: 5 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,4 +315,8 @@ Before `08/07/2021` a change log was not kept. We have retrospectively gone back
- 2024-07-22 `stdAcc` FIX - Remove unused variable `minStackSize`.
- 2024-07-22 `stdWindow` FIX - Remove enforced `LongLong` in `stdWindow::Create`.
- 2024-07-23 `stdQuadTree` FEATURE - Added `stdQuadTree` datastructure.
- 2024-08-24 `stdLambda` FIX - Fixed "key already exists in dictionary" error from using `obj.add` instead of `set obj(...) = args(0)`
- 2024-08-24 `stdLambda` FIX - Fixed "key already exists in dictionary" error from using `obj.add` instead of `set obj(...) = args(0)`
- 2024-08-30 `stdDate` FEATURE - Added `CreateFromMSDOSDateTime()`, `AsMSDOSDate()` and `AsMSDOSTime()`.
- 2024-09-05 `stdClipboard` FEATURE - Added `FormatSize` property.
- 2024-09-06 `stdClipboard` FEATURE - Added `ClipboardID` which can be used to help track and detect changes in the clipboard.
- 2024-09-08 `stdClipboard` FIX - `IsFormatAvailable` will check if bytes present in buffer. Only buffers > 0 are classified as "available". `CF_BITMAP`, `CF_ENHMETAFILE` and `CF_METAFILEPICT` are classified as always available, because they have no size at the buffer and instead return handles to the system struct.
41 changes: 41 additions & 0 deletions src/WIP/stdDate.cls
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,28 @@ Public Function CreateFromUnits(Optional ByVal year As Integer = 0, Optional ByV
end if
End Function

'Get date from MSDOS Date and Time
'@param inDate - MSDOS Date
'@param inTime - MSDOS Time
'@returns - date object
'@remark - This format is used in some data formats from the MS-DOS era, for example: Zip / RAR / vfat / lzh / cab.
'@docs - https://learn.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-dosdatetimetovarianttime#remarks
Public Function CreateFromMSDOSDateTime(Optional ByVal inDate as long = 0, Optional ByVal inTime as long = 0) as stdDate
Const maskTimeH As Long = &HF800&
Const maskTimeM As Long = &H7E0&
Const maskTimeS As Long = &H1F&
Const maskDateY As Long = &HFE00&
Const maskDateM As Long = &H1E0&
Const maskDateD As Long = &H1F&
Dim timeH As Long: timeH = (inTime And maskTimeH) \ 2 ^ 11
Dim timeM As Long: timeM = (inTime And maskTimeM) \ 2 ^ 5
Dim timeS As Long: timeS = (inTime And maskTimeS) * 2
Dim dateY As Long: dateY = (inDate And maskDateY) \ 2 ^ 9 + 1980
Dim dateM As Long: dateM = (inDate And maskDateM) \ 2 ^ 5
Dim dateD As Long: dateD = (inDate And maskDateD)
set CreateFromMSDOSDateTime = CreateFromUnits(dateY, dateM, dateD, timeH, timeM, timeS)
End Function

'Tries to emulate: https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
'EEE = Mon|Tue|Wd|Thu|Fri
'E = Monday|Tuesday|Wednesday|Thursday|Friday
Expand Down Expand Up @@ -331,6 +353,25 @@ Public Property Let Country(s as string)
end select
End Property

'Obtain the MSDOS Date for this datetime
'@docs - https://learn.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-dosdatetimetovarianttime#remarks
Public Property Get asMSDOSDate() as Long
if VBA.Year(pValue) < 1980 then Err.Raise 1, "stdDate#asMSDOSDate", "Cannot create date value"
Dim y as long: y = (VBA.Year(pValue) - 1980) * 2 ^ 9
Dim m as long: m = VBA.Month(pValue) * 2 ^ 5
Dim d as long: d = VBA.Day(pValue)
asMSDOSDate = y or m or d
End Property

'Obtain the MSDOS Time for this datetime
'@docs - https://learn.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-dosdatetimetovarianttime#remarks
Public Property Get asMSDOSTime() as Long
Dim h as long: h = VBA.Hour(pValue) * 2 ^ 11
Dim m as long: m = VBA.Minute(pValue) * 2 ^ 5
Dim s as long: s = VBA.Second(pValue) \ 2
asMSDOSTime = h or m or s
End Property

Public Function ToString()
If pInitialised then
ToString = VBA.Format(pValue,"yyyymmddhhmmss")
Expand Down
100 changes: 79 additions & 21 deletions src/stdClipboard.cls
Original file line number Diff line number Diff line change
Expand Up @@ -38,32 +38,33 @@ Attribute VB_Exposed = False

Public Enum CLIPFORMAT
CF_NOFORMAT = 0
CF_TEXT = 1
CF_BITMAP = 2
CF_DIB = 8
CF_DIBV5 = 17
CF_DIF = 5
CF_DSPBITMAP = &H82
CF_DSPENHMETAFILE = &H8E
CF_DSPMETAFILEPICT = &H83
CF_DSPTEXT = &H81
CF_ENHMETAFILE = &H14
CF_GDIOBJFIRST = &H300
CF_GDIOBJLAST = &H3FF
CF_HDROP = 15
CF_LOCALE = 16
CF_METAFILEPICT = 3
CF_SYLK = 4
CF_DIF = 5
CF_TIFF = 6
CF_OEMTEXT = 7
CF_OWNERDISPLAY = &H80
CF_DIB = 8
CF_PALETTE = 9
CF_PENDATA = 10
CF_PRIVATEFIRST = &H200
CF_PRIVATELAST = &H2FF
CF_RIFF = 11
CF_SYLK = 4
CF_TEXT = 1
CF_TIFF = 6
CF_UNICODETEXT = 13
CF_WAVE = 12
CF_UNICODETEXT = 13
CF_ENHMETAFILE = 14
CF_HDROP = 15
CF_LOCALE = 16
CF_DIBV5 = 17

CF_OWNERDISPLAY = &H80
CF_DSPTEXT = &H81
CF_DSPBITMAP = &H82
CF_DSPMETAFILEPICT = &H83
CF_DSPENHMETAFILE = &H8E
CF_PRIVATEFIRST = &H200
CF_PRIVATELAST = &H2FF
CF_GDIOBJFIRST = &H300
CF_GDIOBJLAST = &H3FF
End Enum

'API Declarations:
Expand Down Expand Up @@ -104,6 +105,7 @@ End Enum
Private Declare PtrSafe Function lstrlenA Lib "kernel32.dll" (ByVal lpString As LongPtr) As Long
Private Declare PtrSafe Function GetTickCount Lib "kernel32" () As Long
Private Declare PtrSafe Function RegisterClipboardFormatA Lib "kernel32" (ByVal lpString As String) As Long
Private Declare PtrSafe Function GetClipboardSequenceNumber Lib "user32" () as Long
#Else
Private Type PICTDESC
size As Long
Expand Down Expand Up @@ -138,6 +140,7 @@ End Enum
Private Declare Function lstrlenA Lib "kernel32.dll" (ByVal lpString As Long) As Long
Private Declare Function GetTickCount Lib "kernel32" () As Long
Private Declare Function RegisterClipboardFormatA Lib "kernel32" (ByVal lpString As String) As Long
Private Declare Function GetClipboardSequenceNumber Lib "user32" () as Long
#End If


Expand Down Expand Up @@ -186,6 +189,13 @@ End Type
'* PUBLIC INTERFACE
'************************************************************************************************

'Get the ID of the current clipboard value
'@returns - The latest clipboard ID / sequence number
'@remark - This is incremented every time the clipboard changes. It can be used to track and identify when the clipboard has changed.
Public Property Get ClipboardID() as Long
ClipboardID = GetClipboardSequenceNumber()
End Property

'Get or set the value of the current
'@param iFormat - The format to get/set the value of
'@returns Variant - The value stored in the clipboard
Expand Down Expand Up @@ -308,9 +318,32 @@ End Property
'Check whether a given format is available based on the clipboards current data.
'@param iFormat - The format to check support for.
'@returns - `True` if the format is allowed, `false` otherwise
'@remark - Formats which are technically "available" but have 0 bytes in size will return false.
Public Function IsFormatAvailable(ByVal iFormat As CLIPFORMAT) As Boolean
Call OpenClipboardTimeout(Application.hwnd)
IsFormatAvailable = IsClipboardFormatAvailable(iFormat)
If IsClipboardFormatAvailable(iFormat) Then
select case iFormat
case CF_BITMAP, CF_ENHMETAFILE, CF_METAFILEPICT
IsFormatAvailable = true
case else
'Ensure data exists in clipboard for format
IsFormatAvailable = GetFormatSize(iFormat) > 0
end select
End If
Call CloseClipboard
End Function

'Get the size in bytes of a particular format
'@param format - The format to retrieve
'@returns - The number of bytes being the size of the format.
'@remark - CF_BITMAP and CF_ENHMETAFILE may be different due to the nature of obtaining their value via stdPicture
Public Function FormatSize(ByVal format as CLIPFORMAT) as Long
Call OpenClipboardTimeout(Application.hwnd)
if IsClipboardFormatAvailable(format) then
FormatSize = GetFormatSize(format)
else
FormatSize = -1
end if
Call CloseClipboard
End Function

Expand Down Expand Up @@ -371,7 +404,7 @@ Public Property Get formatIDs() As Collection
Dim ret As Collection: Set ret = New Collection
'Loop over all formats and add to collection
Call OpenClipboardTimeout(Application.hwnd)
Do
Do
iFormat = EnumClipboardFormats(iFormat)
If CBool(iFormat) Then
ret.Add iFormat, GetClipboardFormatName(iFormat)
Expand Down Expand Up @@ -600,6 +633,31 @@ End Function
'* HELPERS
'******************************************************************

'Get the size of the data stored at the pointer location (not necessarily the size of the file!)
'@private
'@param iFormat - Format to get size of
'@returns - Number of bytes
'@remark - CF_BITMAP, CF_ENHMETAFILE and CF_METAFILEPICT will sometimes crash on `GlobalSize()`. The size of these is `0` though.
'The data is not stored in memory under the handle. Instead the handle returned by `GetClipboardData()` returns a handle
'(HBITMAP or HENHMETAFILE) which internally have very different structures and handling mechanisms.
Private Function GetFormatSize(ByRef iFormat as CLIPFORMAT) as Long
select case iFormat
case CF_BITMAP, CF_ENHMETAFILE, CF_METAFILEPICT
GetFormatSize = 0
case else
#If VBA7 Then
Dim hClipMemory As LongPtr
#Else
Dim hClipMemory As Long
#End If
hClipMemory = GetClipboardData(iFormat)
If CBool(hClipMemory) Then
'Ensure data exists in clipboard for format
GetFormatSize = GlobalSize(hClipMemory)
End If
end select
End Function

'Raises an error in stdError if available, else it will be raised in Err
'@private
'@param sFuncName - The name of the function raising the error
Expand Down

0 comments on commit ea2849f

Please sign in to comment.