/* * $Id: toclip.c,v 1.3 2004/01/05 03:30:55 mitch Exp $ * * DESCRIPTION * * toclip: copy arguments or stdin to Windows clipboard * * See the g_pUsage variable for documentation of usage. * Detailed information is available at http://www.fullspan.com. * * LICENSE * * OSI Certified Open Source Software (see www.opensource.org for details) * Licensed under the BSD license: * * Copyright (c) 2003-2004, FullSpan Software (www.fullspan.com) * All rights reserved * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of FullSpan Software nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #define CLIPBOARD_TEXT_DELIM "\r\n" #define CLIPBOARD_TEXT_DELIM_LEN 2 #define MAX_CLIPBOARD_TEXT_LEN 64000 #define MAX_ERR_MSG_LEN 600 #define MAX_SYSTEM_ERR_MSG_LEN 512 #define SRC_ARGS 10 #define SRC_STDIN 20 #define UNC_BUFSIZE 1024 void copyArgsToBuffer(char *pText, int argc, char **argv, int firstDataArgIndex); void copyStdinToBuffer(char *pText); void errorExit(char *msg); void errorExitLastError(char *msg); void getUNCName(char *pLocalFilename, void *pUNCBuf, DWORD *pUNCBufSize); void processCmdLine(int argc, char **argv, int *pDataSource, int *pFirstDataArgIndex); int g_makeUNCNames = FALSE; const char *g_pUsage = "ToClip v1.4\n\n" "Usage:\n\n" "toclip -a [-u] arg1 [arg2] [...argN]\n\n" " to send the command-line arguments to the clipboard. If there are multiple\n" " arguments, they will be separated by carriage return/linefeed pairs.\n" " Use the -u switch to expand mapped drive letters to UNC paths (e.g.,\n" " from x:\\mydir\\myfile.txt to \\\\myserver\\myshare\\mydir\\myfile.txt).\n\n" "toclip\n\n" " to send the contents of STDIN to the clipboard. This is\n" " only designed to be used for text data, not binary data."; int main(int argc, char** argv) { int dataSource = SRC_STDIN; int firstDataArgIndex = 2; processCmdLine(argc, argv, &dataSource, &firstDataArgIndex); if (!OpenClipboard(NULL)) { errorExitLastError("Cannot open clipboard"); } if (!EmptyClipboard()) { errorExitLastError("Cannot clear clipboard"); } HANDLE hText = LocalAlloc(LPTR, MAX_CLIPBOARD_TEXT_LEN + 1); char *pText = hText; if (dataSource == SRC_ARGS) { copyArgsToBuffer(pText, argc, argv, firstDataArgIndex); } else { copyStdinToBuffer(pText); } HANDLE hClip = SetClipboardData(CF_TEXT, pText); if (hClip == NULL) { errorExitLastError("Cannot set clipboard data"); } if (!CloseClipboard()) { errorExitLastError("Cannot close clipboard"); } #ifdef DEBUG // Display the text from the clipboard for debugging OpenClipboard(NULL); HANDLE hGetClip = GetClipboardData(CF_TEXT); char *pGetClip = hGetClip; MessageBox(NULL, pGetClip, "Text", MB_OK); CloseClipboard(); #endif return 0; } void errorExit(char *msg) { MessageBox(NULL, msg, "Error", MB_OK | MB_ICONEXCLAMATION); exit(1); } void errorExitLastError(char *msg) { char fullMsg[MAX_ERR_MSG_LEN]; char systemMsg[MAX_SYSTEM_ERR_MSG_LEN]; DWORD lastError = GetLastError(); FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, // dwFlags NULL, // lpSource lastError, // dwMessageId 0, // dwLanguageId (LPTSTR) &systemMsg, // lpBuffer MAX_SYSTEM_ERR_MSG_LEN, // nSize NULL); // Arguments sprintf(fullMsg, "%s: %lu: %s", msg, lastError, systemMsg); errorExit(fullMsg); } void processCmdLine(int argc, char **argv, int *pDataSource, int *pFirstDataArgIndex) { // The following forms are accepted: // // toclip -a [args...] // // toclip -a -u [args...] // // toclip // // Any other form will show the usage message, so the usage message can // be shown (for example) by running: // // toclip -h // int unprocessedArgCount = argc - 1; // we ignore argv[0] *pFirstDataArgIndex = 1; if (argc >= 2 && strncmp(argv[1], "-a", 2) == 0) { *pDataSource = SRC_ARGS; (*pFirstDataArgIndex)++; unprocessedArgCount--; } if (argc >= 3 && *pDataSource == SRC_ARGS && strncmp(argv[2], "-u", 2) == 0) { g_makeUNCNames = TRUE; (*pFirstDataArgIndex)++; unprocessedArgCount--; } if (*pDataSource != SRC_ARGS && unprocessedArgCount > 0) { MessageBox(NULL, g_pUsage, "Using ToClip", MB_OK); exit(0); } } void copyArgsToBuffer(char *pText, int argc, char **argv, int firstDataArgIndex) { int i = 1; int itemLen = 0; char *pFilename = NULL; int totalLen = 0; char uncBuf[UNC_BUFSIZE]; DWORD uncBufsize = UNC_BUFSIZE; for (i = firstDataArgIndex; i < argc; i++) { pFilename = argv[i]; if (g_makeUNCNames) { uncBufsize = UNC_BUFSIZE; getUNCName(pFilename, uncBuf, &uncBufsize); strcpy(pFilename, uncBuf); } itemLen = strlen(pFilename); if (i > firstDataArgIndex) { // Account for length of delimiter we will append itemLen += CLIPBOARD_TEXT_DELIM_LEN; } if (totalLen + itemLen > MAX_CLIPBOARD_TEXT_LEN) { errorExit("Too much data for clipboard"); } if (i > firstDataArgIndex) { strcat(pText, CLIPBOARD_TEXT_DELIM); } strcat(pText, pFilename); totalLen += itemLen; } } void copyStdinToBuffer(char *pText) { int ch; int index = 0; while ((ch = getchar()) != EOF) { pText[index++] = ch; } } void getUNCName(char *pLocalFilename, void *pUNCBuf, DWORD *pUNCBufSize) { int getUNC = TRUE; // Already a UNC name if (strncmp(pLocalFilename, "\\\\", 2) == 0) { getUNC = FALSE; } // Not a local drive letter if (strlen(pLocalFilename) < 2 || pLocalFilename[1] != ':') { getUNC = FALSE; } DWORD ret = NO_ERROR; if (getUNC) { ret = WNetGetUniversalName(pLocalFilename, UNIVERSAL_NAME_INFO_LEVEL, pUNCBuf, pUNCBufSize); } // Error codes are currently ignored - if we got an error we just return // the original filename if (getUNC && ret == NO_ERROR) { UNIVERSAL_NAME_INFO *pNameInfo = pUNCBuf; char *pUNCName = pNameInfo->lpUniversalName; strcpy(pUNCBuf, pUNCName); } else { strcpy(pUNCBuf, pLocalFilename); return; } }