Introduction
I did some Windows Script Host programming recently, and I was pleasantly surprised by its power, features, and flexibility. One thing that I couldn't accomplish was accessing the clipboard from WSH. Digging the Internet, I found some solutions like this one based on Internet Explorer Automation. There are several problems with this approach as you can read in my article about Internet Explorer Automation: What's wrong with Internet Explorer Automation?
Using the code
The solution for scripting the clipboard content in WSH is a regular COM object created with VC++ and ATL. To install the COM object, run register.bat.
Here is a simple example of using the component from WSH:
var clipboardHelper = null;
try
{
clipboardHelper = WScript.CreateObject("ClipboardHelper.ClipBoard");
}
catch (ex)
{
WScript.Echo(ex.message + "\n\nClipboardHelper library is not properly registered!");
WScript.Quit(1);
}
var msg = "Some text";
clipboardHelper.SetClipboardText(msg);
var text = clipboardHelper.GetClipboardText();
WScript.Echo(text);
Points of interest
The implementation is just regular ATL/COM code. Win32 API functions are used to get access to clipboard text (OpenClipboard
, IsClipboardFormatAvailable
, GetClipboardData
, SetClipboardData
, CloseClipboard
, GlobalAlloc
, GlobalLock
, GlobalFree
).
Here is the implementation of the method that retrieves the text from clipboard (CF_TEXT
and CF_UNICODETEXT
formats supported):
STDMETHODIMP CClipBoard::GetClipboardText(BSTR* pBstrClipboardText)
{
if (NULL == pBstrClipboardText)
{
return E_INVALIDARG;
}
CComBSTR bstrResult = L"";
if (::OpenClipboard(NULL))
{
if (::IsClipboardFormatAvailable(CF_TEXT) ||
::IsClipboardFormatAvailable(CF_UNICODETEXT))
{
BOOL bUnicode = TRUE;
HANDLE hClipboard = ::GetClipboardData(CF_UNICODETEXT);
if (NULL == hClipboard)
{
bUnicode = FALSE;
hClipboard = ::GetClipboardData(CF_TEXT);
}
if (hClipboard != NULL)
{
LPCSTR szClipboardData = (LPCSTR)::GlobalLock(hClipboard);
if (szClipboardData != NULL)
{
if (bUnicode)
{
LPCWSTR szClipboardWText = (LPCWSTR)szClipboardData;
bstrResult = szClipboardWText;
szClipboardWText = NULL;
}
else
{
LPCSTR szClipboardText = (LPCSTR)szClipboardData;
bstrResult = szClipboardText;
szClipboardText = NULL;
}
::GlobalUnlock(hClipboard);
*pBstrClipboardText = bstrResult.Detach();
hClipboard = NULL;
}
else
{
ATLTRACE("GlobalLock failed in CClipBoard::GetClipboardText\n");
}
}
else
{
ATLTRACE("GetClipboardData failed in CClipBoard::GetClipboardText\n");
}
hClipboard = NULL;
}
else
{
ATLTRACE("CF_TEXT NOT available in CClipBoard::GetClipboardText\n");
}
BOOL bRes = ::CloseClipboard();
ATLASSERT(bRes);
}
else
{
ATLTRACE("Can NOT OpenClipboard in CClipBoard::GetClipboardText\n");
}
return S_OK;
}