Log in

View Full Version : Copy clipboard value into an AviSynth variable


Forensic
29th May 2016, 18:47
I have a resource that copies a text string into the Windows clipboard. What I need is an AviSynth script or DLL that can retrieve the Windows clipboard into a variable for use by my script. Any suggestions on how to finish the line below?

clipboardContents =

StainlessS
29th May 2016, 22:11
Here you go, only tested once (~26KB) :- EDIT: LINK REMOVED.


ClipBoard_GetText()

Returns:-
Int,
-1: ANSI text not available on ClipBoard
-2: Cannot Open Clipboard
-3: Cannot get ClipBoard data
-4: Lock ClipBoard memory failed

Else, ANSI TEXT String from ClipBoard.



/*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/


#include <windows.h>
//#include <stdio.h>
#include "avisynth.h" // Avisynth VERSION 3 HEADER (Avisynth v2.58)

AVSValue __cdecl Clipboard_GetText(AVSValue args, void* user_data, IScriptEnvironment* env) {
AVSValue Ret = -1; // Preset "ANSI text not available on ClipBoard"
// BOOL IsClipboardFormatAvailable(UINT format); // format = clipboard format
if(IsClipboardFormatAvailable(CF_TEXT) != 0) {
Ret = -2; // Preset "Cannot Open Clipboard"
// BOOL OpenClipboard(HWND hWndNewOwner) // hWndNewOwner = handle to window, NULL = the current task
if(OpenClipboard(NULL) != 0) {
Ret = -3; // Preset "Cannot get ClipBoard data"
// Obtain the handle to the global memory block that is referencing the text.
// HANDLE GetClipboardData(UINT uFormat); // uFormat = clipboard format
HANDLE hData = GetClipboardData(CF_TEXT);
if(hData != NULL) {
Ret = -4; // Preset, Lock ClipBoard memory failed.
// Lock Clipboard memory so you can reference the actual data string.
// LPVOID GlobalLock(HGLOBAL hMem); // hMem = handle to global memory object.
LPVOID lpClip = GlobalLock(hData);
if(lpClip != NULL) {
Ret = env->SaveString((char*)lpClip); // Save String and return as AVSValue to Avisynth (SUCCESS).
// BOOL GlobalUnlock(HGLOBAL hMem); // hMem = handle to global memory object
GlobalUnlock(hData); // return 0 on FAIL (???)
}
}
CloseClipboard(); // 0 = FAIL (???)
}
}
return Ret;
}

extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env) {
env->AddFunction("Clipboard_GetText", "",Clipboard_GetText, 0);
return "`Clipboard' Clipboard plugin";
}


EDIT: ANSI text ONLY.

EDIT: Test script (Copy entire script to clipboard before execute: EDIT: CTRL/A then CTRL/C)

S=ClipBoard_GetText()

RT_DebugF("%s",String(S),name="ClipBoard TEST: ")

Return MessageClip("OK")


Result in DebugView

00000004 22:19:36 ClipBoard TEST: S=ClipBoard_GetText()
00000005 22:19:36 ClipBoard TEST:
00000006 22:19:36 ClipBoard TEST: RT_DebugF("%s",String(S),name="ClipBoard TEST: ")
00000007 22:19:36 ClipBoard TEST:
00000008 22:19:36 ClipBoard TEST: Return MessageClip("OK")
00000009 22:19:36 ClipBoard TEST:


EDIT: Would ClipBoard_PutText() And/Or ClipBoard_ClearText() be of use ?

StainlessS
30th May 2016, 04:23
ClipBoard(), v0.01, LINK REMOVED


ClipBoard() v0.01, by StainlessS, http://forum.doom9.org/showthread.php?t=173538

ClipBoard_GetText() : Get text from ClipBoard.
Returns:-
Int,
0 : ANSI text not available on ClipBoard
-1: Cannot Open Clipboard
-2: Cannot get ClipBoard data
-3: Lock ClipBoard memory failed
String,
ANSI TEXT String from ClipBoard.

###

ClipBoard_Clear() : Clear everything from ClipBoard [TAKE CARE, should only really be done by the USER].
Int Returns:-
0 : SUCCESS
-1: Cannot Open Clipboard
-2: Cannot CLEAR ClipBoard

###

ClipBoard_PutText(String s) : Clear ClipBoard and then set string s as ANSI Text on ClipBoard [Error alert if s==""].
[TAKE CARE, only USER should set ClipBoard data].
Returns:-
Int,
0 : SUCCESS
-1: Cannot Open Clipboard
-2: Cannot CLEAR ClipBoard
-3: Cannot SET ClipBoard Text
-4: Cannot Allocate system GLOBAL memory

###

ClipBoard_GetLastError() : Get system error code as Int for previous call to ClipBoard functions. (Error Code cleared on entry to ClipBoard functions)

Returns:-
0 : No Error
Else Some system Error Code.

###

ClipBoard_GetLastErrorString() : Get system error as String, for previous call to ClipBoard functions. (Error Code cleared on entry to ClipBoard functions)

Returns:- Error String describing error code.

###


Source

/*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <windows.h>
#include <stdio.h> // sprintf(), dprintf(), OutputDebugString()
#include "avisynth.h" // Avisynth VERSION 3 HEADER (Avisynth v2.58)

/*
int __cdecl dprintf(char* fmt, ...) {
char printString[2048]="";
char *p=printString;
va_list argp;
va_start(argp, fmt);
vsprintf(p, fmt, argp);
va_end(argp);
for(;*p++;);
--p; // @ null term
if(printString == p || p[-1] != '\n') {
p[0]='\n'; // append n/l if not there already
p[1]='\0';
}
OutputDebugString(printString);
return p-printString; // strlen printString
}
*/

char * __cdecl GetErrorString(DWORD dwLastError = GetLastError()) {
// The arg is OPTIONAL
// Ownership of returned string is passed to client and MUST be deleted by them.
DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM ;

HMODULE hModule = NULL; // default to system source
LPSTR MessageBuffer;
DWORD dwBufferLength;
char * str = NULL;
//
// Call FormatMessage() to allow for message text to be acquired from the system
if(dwBufferLength = FormatMessageA(
dwFormatFlags,
hModule, // module to get message from (NULL == system)
dwLastError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
(LPSTR) &MessageBuffer,
0,
NULL
)) {
int len = strlen(MessageBuffer);
str = new char[len+16];
if(str!=NULL) {
char c,*s=MessageBuffer,*d=str;
while(c=*s) {
if(c=='\r' || c=='\n')
break;
*d++=c;
++s;
}
sprintf(d," (0x%08X)",dwLastError);
}
// Free the buffer allocated by the system.
//
LocalFree(MessageBuffer);
} else {
str=new char [128];
if(str) {
sprintf(str,"Unknown Error (0x%08X)",dwLastError);
}
}
return str;
}


AVSValue __cdecl ClipBoard_GetLastErrorString(AVSValue args, void*, IScriptEnvironment* env) {
char *e=GetErrorString();
if(e==NULL) env->ThrowError("ClipBoard_GetLastErrorString: Cannot Allocate Memory");
AVSValue ret = env->SaveString(e);
delete [] e;
return ret;
}

AVSValue __cdecl ClipBoard_GetLastError(AVSValue args, void*, IScriptEnvironment* env) {
return (int)(GetLastError());
}


AVSValue __cdecl Clipboard_GetText(AVSValue args, void* user_data, IScriptEnvironment* env) {
AVSValue Ret = 0; // Preset "ANSI text not available on ClipBoard"
SetLastError(0); // Clear system Error
// BOOL IsClipboardFormatAvailable(UINT format); // format = clipboard format
if(IsClipboardFormatAvailable(CF_TEXT) != 0) {
Ret = -1; // Preset "Cannot Open Clipboard"
// BOOL OpenClipboard(HWND hWndNewOwner) // hWndNewOwner = handle to window, NULL = the current task
if(OpenClipboard(NULL) != 0) {
Ret = -2; // Preset "Cannot GET ClipBoard data"
// Obtain the handle to the global memory block that is referencing the text.
// HANDLE GetClipboardData(UINT uFormat); // uFormat = clipboard format
HANDLE hData = GetClipboardData(CF_TEXT);
if(hData != NULL) {
Ret = -3; // Preset, Lock ClipBoard memory failed.
// Lock Clipboard memory so you can reference the actual data string.
// LPVOID GlobalLock(HGLOBAL hMem); // hMem = handle to global memory object.
LPVOID lpClip = GlobalLock(hData);
if(lpClip != NULL) {
Ret = env->SaveString((char*)lpClip); // Save String and return as AVSValue to Avisynth (SUCCESS).
// BOOL GlobalUnlock(HGLOBAL hMem); // hMem = handle to global memory object
GlobalUnlock(hData); // return 0 on FAIL (???)
}
}
CloseClipboard(); // 0 = FAIL (???)
}
}
return Ret;
}

AVSValue __cdecl Clipboard_Clear(AVSValue args, void* user_data, IScriptEnvironment* env) {
AVSValue Ret = -1; // Preset "Cannot Open Clipboard"
SetLastError(0); // Clear system Error
if(OpenClipboard(NULL) != 0) {
Ret = -2; // Preset "Cannot EMPTY ClipBoard data"
// If the application specifies a NULL window handle when opening the clipboard,
// EmptyClipboard succeeds but sets the clipboard owner to NULL.
// Note that this would cause SetClipboardData to fail [WHAT!!!, NO IT DOES NOT, we do that in PutText].
if(EmptyClipboard() != 0) {
Ret = 0; // SUCCESS
}
CloseClipboard();
}
return Ret;
}

AVSValue __cdecl Clipboard_PutText(AVSValue args, void* user_data, IScriptEnvironment* env) {
const char *s = args[0].AsString();
const int len = strlen(s);
if(len==0) env->ThrowError("Clipboard_PutText: Cannot Put empty string ('') on ClipBoard");
SetLastError(0); // Clear system Error
HGLOBAL hMem;
AVSValue Ret = -4; // Preset "Cannot Allocate system GLOBAL memory"
if((hMem = GlobalAlloc(GMEM_MOVEABLE , len + 1)) != NULL) {
Ret = -1; // Preset "Cannot Open Clipboard"
strcpy((char*)GlobalLock(hMem),s);
GlobalUnlock(hMem);
if(OpenClipboard(NULL) != 0) {
Ret = -2; // Preset "Cannot EMPTY ClipBoard"
if(EmptyClipboard() != 0) {
Ret = -3; // Preset "Cannot SET ClipBoard data"
if(SetClipboardData(CF_TEXT,hMem) != NULL) {
// System NOW OWNS hMem
Ret = 0;
} else {
GlobalFree(hMem);
}
}
CloseClipboard(); // 0 = FAIL (???)
} else {
GlobalFree(hMem);
}
}
return Ret;
}

extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env) {
env->AddFunction("Clipboard_GetText", "",Clipboard_GetText, 0);
env->AddFunction("Clipboard_Clear", "",Clipboard_Clear, 0);
env->AddFunction("Clipboard_PutText", "s",Clipboard_PutText, 0);
env->AddFunction("ClipBoard_GetLastError", "",ClipBoard_GetLastError, 0);
env->AddFunction("ClipBoard_GetLastErrorString","",ClipBoard_GetLastErrorString, 0);
return "`Clipboard' Clipboard plugin";
}


GetText.avs

# Copy entire script to clipboard before play script [CTRL/A then CTRL/C]

S=ClipBoard_GetText()

RT_DebugF("%s",String(S),name="ClipBoard_GetText: ")

Return MessageClip("OK")


GetText.avs DebugView

00000008 04:05:03 ClipBoard_GetText: # Copy entire script to clipboard before play script [CTRL/A then CTRL/C]
00000009 04:05:03 ClipBoard_GetText:
00000010 04:05:03 ClipBoard_GetText: S=ClipBoard_GetText()
00000011 04:05:03 ClipBoard_GetText:
00000012 04:05:03 ClipBoard_GetText: RT_DebugF("%s",String(S),name="ClipBoard_GetText: ")
00000013 04:05:03 ClipBoard_GetText:
00000014 04:05:03 ClipBoard_GetText: Return MessageClip("OK")
00000015 04:05:03 ClipBoard_GetText:


ClearText.avs

# Copy entire script to clipboard before play script [CTRL/A then CTRL/C]

S=ClipBoard_Clear()

RT_DebugF("%s",String(S),name="ClipBoard_ClearText: ")

Return MessageClip("OK")


ClearText.avs DebugView

00000004 04:05:30 ClipBoard_ClearText: 0


PutText.avs

PPP="""
Some Demo text
And some more.
"""

E=ClipBoard_PutText(PPP)
S=ClipBoard_GetText()

RT_DebugF("PutError=%s\nGetText='%s'",String(E),String(S),name="ClipBoard_PutText: ")

Return MessageClip("OK")


PutText.avs DebugView

00000004 04:10:57 ClipBoard_PutText: PutError=0
00000005 04:10:57 ClipBoard_PutText: GetText='
00000006 04:10:57 ClipBoard_PutText: Some Demo text
00000007 04:10:57 ClipBoard_PutText: And some more.
00000008 04:10:57 ClipBoard_PutText: '


GetLastError.avs

# Just to show error code 0

ClipBoard_Clear() # No Text Available on ClipBoard
S = ClipBoard_GetText() # No text is Available on ClipBoard [Error code == 0, not an error]
E = ClipBoard_GetLastError() # == 0
ES= ClipBoard_GetLastErrorString()
RT_DebugF("ClipBoard_GetText()=%s\nERROR CODE = %d ($%08X) ['%s']",String(S),E,E,ES,name="ClipBoard_GetLastError: ")
Return MessageClip("OK")


GetLastError.avs DebugView

00000004 04:11:37 ClipBoard_GetLastError: ClipBoard_GetText()=0
00000005 04:11:37 ClipBoard_GetLastError: ERROR CODE = 0 ($00000000) ['The operation completed successfully. (0x00000000)']


EDIT: Error returns for ClipBoard_GetText(), changed slightly.
EDIT: Clipboard_Clear() and ClipBoard_PutText() could cause user confusion !!!

Forensic
30th May 2016, 05:45
You are a coding genius. I will test it later this week, but thank you for this. I hope this helps others as well since the clipboard can serve as the bridge between Python code and Avisynth.

StainlessS
30th May 2016, 05:49
clipboard can serve as the bridge between Python code and Avisynth.

Handy to know, thank you :)

raffriff42
31st May 2016, 04:28
Awesome coding StainlessS! Here's a ScriptClip (http://avisynth.nl/index.php/ScriptClip) wrapper: it lets you watch the clipboard contents update in near real time
#Last=...
ScriptClip(Last, """
S=ClipBoard_GetText()
IsString(S)
\ ? Subtitle(RT_StrReplace(S, Chr(13), "\n"), lsp=0, align=7)
\ : S==0 ? Subtitle("ClipBoard_GetText error: text not available", align=7)
\ : S==-1 ? Subtitle("ClipBoard_GetText error: cannot open clipboard", align=7)
\ : S==-2 ? Subtitle("ClipBoard_GetText error: cannot get clipboard data", align=7)
\ : S==-3 ? Subtitle("ClipBoard_GetText error: cannot lock clipboard memory", align=7)
\ : Subtitle("ClipBoard_GetText error: unknown", align=7)

##Optional: log to file
#WriteFileStart("clipboard.txt", "String(S)", append=true)
""")


RT_StrReplace above is only needed for multi-line subtitles; it can be found as part of RT_Stats here (http://forum.doom9.org/showthread.php?t=165479).

StainlessS
31st May 2016, 05:45
Oooh, you crazy mixed up individual http://www.cosgan.de/images/smilie/figuren/n025.gif

Could not help but make a few mods, here:-


Last=Colorbars.killaudio

ClipFile = "clipboard.txt"
RT_FileDelete(ClipFile)

CLEARCLIPB = True # Start with ClipBoard empty
RT_SUBS = True
WR_CLIPFILE = False

CBES=RT_String("Text not available\nCannot open clipboard\nCannot get clipboard data\nCannot lock clipboard memory\nError: unknown\n")

(CLEARCLIPB) ? ClipBoard_Clear() : NOP

SSS = """
S=ClipBoard_GetText()
# If ClipBoard Text, Strip all Chr(13) - We Want Chr(10) instead (Will I think usually be Chr(13),Chr(10) PAIRS [Not Necessary for RT_Subtitle])
S=IsString(S)
\ ? RT_String("%d ]\n%s",current_frame,RT_StrReplace(S,Chr(13),""))
\ : RT_String("%d ] ClipBoard_GetText error=%d :- '%s'",current_frame,S,RT_TxtGetLine(CBES,((Abs(S)<=3)?S:4)))
(RT_SUBS)?RT_Subtitle("%s",S,Align=5):NOP
Subtitle(RT_StrReplace(S,Chr(10),"\n"), lsp=0, align=7)
(WR_CLIPFILE) ? RT_WriteFile(ClipFile,"%s\n#########################",S, append=true) : NOP
Return Last
"""

ScriptClip(Last, SSS)

StainlessS
31st May 2016, 18:54
Here, sample C source for CLI command that copies current directory to clipboard:- http://stackoverflow.com/questions/1264137/how-to-copy-string-to-clipboard-in-c

Could be modified to send something else to clipboard (if modded to take string, then anything else to clipboard).
(not bullet proof error processing, need a bit more work but reasonable template).

EDIT: 2nd last post.

EDIT: Uses UNICODE, easily modded to ANSI (Change CF_UNICODETEXT to CF_TEXT and change WCHAR stuff).

StainlessS
15th January 2019, 15:49
Another thread on ClipBoard use:- https://forum.doom9.org/showthread.php?t=147812

StainlessS
15th January 2019, 15:58
ClipBoard(), v0.02,

dll's for v2.58, v2.6/+ x86 & x64.
Req VS2008 CPP runtimes.


ClipBoard() v0.02, by StainlessS, http://forum.doom9.org/showthread.php?t=173538

ClipBoard_GetText() : Get text from ClipBoard.
Returns:-
Int,
0 : ANSI text not available on ClipBoard
-1: Cannot Open Clipboard
-2: Cannot get ClipBoard data
-3: Lock ClipBoard memory failed
String,
ANSI TEXT String from ClipBoard.

###

ClipBoard_Clear() : Clear everything from ClipBoard [TAKE CARE, should only really be done by the USER].
Int Returns:-
0 : SUCCESS
-1: Cannot Open Clipboard
-2: Cannot CLEAR ClipBoard

###

ClipBoard_PutText(String s) : Clear ClipBoard and then set string s as ANSI Text on ClipBoard [Error alert if s==""].
[TAKE CARE, only USER should set ClipBoard data].
Returns:-
Int,
0 : SUCCESS
-1: Cannot Open Clipboard
-2: Cannot CLEAR ClipBoard
-3: Cannot SET ClipBoard Text
-4: Cannot Allocate system GLOBAL memory

###

ClipBoard_GetLastError() : Get system error code as Int for previous call to ClipBoard functions. (Error Code cleared on entry to ClipBoard functions)

Returns:-
0 : No Error
Else Some system Error Code.

###

ClipBoard_GetLastErrorString() : Get system error as String, for previous call to ClipBoard functions. (Error Code cleared on entry to ClipBoard functions)

Returns:- Error String describing error code.

###


See MediaFire in sig below this post.
Zip incl 3 dll's, 2.58, 2.60/+ x86 & x64, + full VS2008 project files for easy rebuild. (~70KB)

EDIT:
Clear_Text.avs

# Need DebugView (Google)

# Copy entire script to clipboard before play script [CTRL/A then CTRL/C]

S=ClipBoard_Clear()

RT_DebugF("%s",String(S),name="ClipBoard_ClearText: ")

Return MessageClip("OK")


PutText.avs

# Need DebugView (Google)

PPP="""
Some Demo text
And some more.
"""

E=ClipBoard_PutText(PPP)
S=ClipBoard_GetText()

RT_DebugF("PutError=%s\nGetText='%s'",String(E),String(S),name="ClipBoard_PutText: ")

Return MessageClip("OK")


GetText.avs

# Need DebugView (Google)

# Copy entire script to clipboard before play script [CTRL/A then CTRL/C]

S=ClipBoard_GetText()

RT_DebugF("%s",String(S),name="ClipBoard_GetText: ")

Return MessageClip("OK")


GetLastError.avs

# Need DebugView (Google)

# Just to show error code 0

ClipBoard_Clear() # No Text Available on ClipBoard
S = ClipBoard_GetText() # No text is Available on ClipBoard [Error code == 0, not an error]
E = ClipBoard_GetLastError() # == 0
ES= ClipBoard_GetLastErrorString()
RT_DebugF("ClipBoard_GetText()=%s\nERROR CODE = %d ($%08X) ['%s']",String(S),E,E,ES,name="ClipBoard_GetLastError: ")
Return MessageClip("OK")


EDIT: Opened Clipboard thread here:- https://forum.doom9.org/showthread.php?t=176145