Тема: AHK: UWP, Clipboard Class
Решил тоже немного попробовать в UWP.
Частичная имплементация класса Clipboard из Windows Runtime API.
Класс ClipboardHistory реализует возможности:
узнавать, включена ли история буфера обмена в Windows 10
узнавать количество элементов в истории
стирать историю буфера обмена
получать текст элемента истории по индексу
помещать в Clipboard элемент из истории по индексу
а так же демонстрирует принципы использования классов и интерфейсов Windows Runtime в AHK.
; помещает в Clipboard второй элемент из истории буфера обмена Windows 10 и возвращает статус успеха
MsgBox, % (new ClipboardHistory).PutHistoryItemIntoClipboard(2)
; получаем текст элементов истории буфера обмена по индексу
ClipHist := new ClipboardHistory
Loop % ClipHist.Count
MsgBox,, Item %A_Index%, % ClipHist.GetHistoryItemText(A_Index), .7
class ClipboardHistory
{
; https://is.gd/bYyogJ ; Clipboard Class (MSDN)
; https://is.gd/2z2Y9G ; Windows.ApplicationModel.DataTransfer.0.h (GitHub)
; https://is.gd/T4Lb7b ; asyncinfo.h (GitHub)
__New() {
static IID_IClipboardStatics2 := "{D2AC1B6A-D29F-554B-B303-F0452345FE02}"
if (A_OSVersion ~= "^\D") {
MsgBox, This class requires Windows 10 or later!
Return
}
WrtStr := new WrtString("Windows.ApplicationModel.DataTransfer.Clipboard")
riid := CLSIDFromString(IID_IClipboardStatics2, _)
WrtStr.CreateInterface(riid, pIClipboardStatics2)
this.ClipboardStatics2 := new IClipboardStatics2( pIClipboardStatics2 )
}
__Delete() {
this.ClipboardStatics2 := ""
}
IsHistoryEnabled[] {
get {
Return this.ClipboardStatics2.IsHistoryEnabled
}
}
Count[] {
get {
Return this._GetClipboardHistoryItems()
}
}
ClearHistory() {
Return this.ClipboardStatics2.ClearHistory()
}
GetHistoryItemText(index) { ; 1 based
if !pIClipboardHistoryItem := this._GetClipboardHistoryItemByIndex(index)
Return
ClipboardHistoryItem := new IClipboardHistoryItem( pIClipboardHistoryItem )
pIDataPackageView := ClipboardHistoryItem.Content
DataPackageView := new IDataPackageView( pIDataPackageView )
pIReadOnlyList := DataPackageView.AvailableFormats
ReadOnlyList := new IReadOnlyList( pIReadOnlyList )
Loop % ReadOnlyList.Count
pString := ReadOnlyList.Item[A_Index - 1]
until (new WrtString(pString, true)).GetText() = "Text" && textFound := true
if !textFound
Return
DataPackageView.GetTextAsync(pIAsyncOperation)
pString := this._AsyncOperationGetResults(pIAsyncOperation)
Return (new WrtString(pString, true)).GetText()
}
PutHistoryItemIntoClipboard(index) { ; 1 based
static SetHistoryItemAsContentStatus := ["Success", "AccessDenied", "ItemDeleted"]
if !pIClipboardHistoryItem := this._GetClipboardHistoryItemByIndex(index)
Return
ClipboardHistoryItem := new IClipboardHistoryItem( pIClipboardHistoryItem )
status := this.ClipboardStatics2.SetHistoryItemAsContent( pIClipboardHistoryItem )
Return SetHistoryItemAsContentStatus[ status + 1 ]
}
_GetClipboardHistoryItemByIndex(index) { ; 1 based
count := this._GetClipboardHistoryItems(ReadOnlyList)
if (count < index) {
MsgBox, 48, % " ", Index "%index%" exceeds items count!
Return
}
Return pIClipboardHistoryItem := ReadOnlyList.Item[index - 1]
}
_GetClipboardHistoryItems(ByRef ReadOnlyList := "") {
this.ClipboardStatics2.GetHistoryItemsAsync( pIAsyncOperation )
pIClipboardHistoryItemsResult := this._AsyncOperationGetResults(pIAsyncOperation)
ClipboardHistoryItemsResult := new IClipboardHistoryItemsResult( pIClipboardHistoryItemsResult )
pIReadOnlyList := ClipboardHistoryItemsResult.Items
ReadOnlyList := new IReadOnlyList( pIReadOnlyList )
Return ReadOnlyList.Count
}
_AsyncOperationGetResults(pIAsyncOperation) {
static AsyncStatus := ["Started", "Completed", "Canceled", "Error"]
AsyncOperation := new IAsyncOperation( pIAsyncOperation )
AsyncOperation.QueryIAsyncInfo(pIAsyncInfo)
AsyncInfo := new IAsyncInfo( pIAsyncInfo )
Loop {
Sleep, 10
status := AsyncStatus[ AsyncInfo.Status + 1 ]
} until status != "Started"
if (status != "Completed")
throw "AsyncInfo error, status: """ . status . """"
AsyncOperation.GetResults( pResult )
Return pResult
}
}
class IClipboardStatics2 extends _InterfaceBase
{
GetHistoryItemsAsync(ByRef pIAsyncOperation) {
hr := DllCall(this.VTable(6), "Ptr", this.ptr, "UIntP", pIAsyncOperation)
this.IsError(A_ThisFunc, hr)
}
ClearHistory() {
hr := DllCall(this.VTable(7), "Ptr", this.ptr, "UIntP", res)
this.IsError(A_ThisFunc, hr)
Return res
}
SetHistoryItemAsContent(pIClipboardHistoryItem) {
hr := DllCall(this.VTable(9), "Ptr", this.ptr, "Ptr", pIClipboardHistoryItem, "UIntP", res)
this.IsError(A_ThisFunc, hr)
Return res
}
IsHistoryEnabled[] {
get {
hr := DllCall(this.VTable(10), "Ptr", this.ptr, "UIntP", res)
this.IsError(A_ThisFunc, hr)
Return res
}
}
}
class IClipboardHistoryItemsResult extends _InterfaceBase
{
Items[] {
get {
hr := DllCall(this.VTable(7), "Ptr", this.ptr, "PtrP", pIReadOnlyList)
this.IsError(A_ThisFunc, hr)
Return pIReadOnlyList
}
}
}
class IClipboardHistoryItem extends _InterfaceBase
{
Content[] {
get {
hr := DllCall(this.VTable(8), "Ptr", this.ptr, "PtrP", pIDataPackageView)
this.IsError(A_ThisFunc, hr)
Return pIDataPackageView
}
}
}
class IDataPackageView extends _InterfaceBase
{
AvailableFormats[] {
get {
hr := DllCall(this.VTable(9), "Ptr", this.ptr, "PtrP", pIReadOnlyList)
this.IsError(A_ThisFunc, hr)
Return pIReadOnlyList
}
}
GetTextAsync(ByRef pIAsyncOperation) {
hr := DllCall(this.VTable(12), "Ptr", this.ptr, "UIntP", pIAsyncOperation)
this.IsError(A_ThisFunc, hr)
}
}
class IReadOnlyList extends _InterfaceBase
{
Item[index] {
get {
hr := DllCall(this.VTable(6), "Ptr", this.ptr, "Int", index, "PtrP", pItem)
this.IsError(A_ThisFunc, hr)
Return pItem
}
}
Count[] {
get {
hr := DllCall(this.VTable(7), "Ptr", this.ptr, "UIntP", count)
this.IsError(A_ThisFunc, hr)
Return count
}
}
}
class IAsyncOperation extends _InterfaceBase
{
QueryIAsyncInfo(ByRef pIAsyncInfo) {
static IID_IAsyncInfo := "{00000036-0000-0000-C000-000000000046}"
pIAsyncInfo := ComObjQuery(this.ptr, IID_IAsyncInfo)
}
GetResults(ByRef pResult) {
hr := DllCall(this.VTable(8), "Ptr", this.ptr, "PtrP", pResult)
this.IsError(A_ThisFunc, hr)
}
}
class IAsyncInfo extends _InterfaceBase
{
Status[] {
get {
hr := DllCall(this.VTable(7), "Ptr", this.ptr, "UIntP", status)
this.IsError(A_ThisFunc, hr)
Return status
}
}
}
class _InterfaceBase {
__New(ptr) {
this.ptr := ptr
}
__Delete() {
ObjRelease(this.ptr)
}
VTable(idx) {
Return NumGet(NumGet(this.ptr + 0) + A_PtrSize*idx)
}
IsError(method, result, exc := true) {
if (result = 0)
Return 0
error := StrReplace(method, ".", "::") . " failed.`nResult: "
. ( result = "" ? "No result" : SysError(Format("{:#x}", result & 0xFFFFFFFF)) )
. "`nErrorLevel: " . ErrorLevel
if !exc
Return error
throw error
}
}
class WrtString {
__New(string, isHandle := false) {
if isHandle
this.hString := string
else {
DllCall("Combase\WindowsCreateString", "WStr", string, "UInt", StrLen(string), "PtrP", hString)
this.hString := hString
}
}
__Delete() {
DllCall("Combase\WindowsDeleteString", "Ptr", this.hString)
}
GetText() {
pBuff := DllCall("Combase\WindowsGetStringRawBuffer", "Ptr", this.hString, "UIntP", len, "Ptr")
Return StrGet(pBuff, len, "UTF-16")
}
CreateInterface(riid, ByRef pInterface) {
hr := DllCall("Combase\RoGetActivationFactory", "Ptr", this.hString, "Ptr", riid, "PtrP", pInterface)
if (hr != 0)
throw SysError(hr)
}
}
CLSIDFromString(IID, ByRef CLSID) {
VarSetCapacity(CLSID, 16, 0)
if hr := DllCall("ole32\CLSIDFromString", "WStr", IID, "Ptr", &CLSID, "UInt")
throw "CLSIDFromString failed. Error: " . Format("{:#x}", hr)
Return &CLSID
}
SysError(ErrorNum = "")
{
static flag := (FORMAT_MESSAGE_ALLOCATE_BUFFER := 0x100) | (FORMAT_MESSAGE_FROM_SYSTEM := 0x1000)
(ErrorNum = "" && ErrorNum := A_LastError)
DllCall("FormatMessage", "UInt", flag, "UInt", 0, "UInt", ErrorNum, "UInt", 0, "PtrP", pBuff, "UInt", 512, "Str", "")
Return (str := StrGet(pBuff)) ? str : ErrorNum
}