Clip2txt: a Windows utility that writes the clipboard to a file


An "invisible" Windows utility that writes the clipboard contents to a text file

Clip2txt.exe (download here) is a Windows command-line utility that writes the contents of the Windows to a text file, optionally in a user-specified codepage for use in MS-DOS applications or other applications that rely on codepages for rendering non-ASCII characters.

To run the program, simply run Clip2txt (or call it from another application). It will write the clipboard contents to a file named #clip.txt in the same folder with Clip2txt.exe. The file will be a text file using the default Windows codepage (typically 1252).

Command-line parameters: You may add a code page number (e.g. 437, 850, 1256, etc.) or a filename (e.g. clipboard.txt) or a full pathname (e.g. C:\Users\Roscoe\Desktop\output.txt) or both (in any order) to the command line.

If you specify a codepage, the program will try to convert the clipboard text to the specified codepage. If the specified codepage is invalid under your copy of Windows, the default codepage will be used instead. If the specified file cannot be created, the program will try to create a log file named #log.txt in the same folder with the application.


Source code (amateurish and needs work)

This is my first attempt at writing a program in C, and the result is an amateurish mix of conventions that will make any competent programmer burst into contemptuous laughter. But the program at least seems to work.

If you want to modify this project for yourself, use Microsoft Visual Studio 2010 or later; create a Win32 Application named Clip2txt, and replace the contents of Clip2txt.cpp with the code below.

If you are expert and generous enough to suggest changes in the code, please get in touch with me at the address in the footer of this page.

Here is the text of Clip2txt.cpp:

// Clip2txt.cpp 

#include "stdafx.h"
#include <Windows.h>
#include <shellapi.h>
#include <iostream>
#include <fstream>
#include <codecvt> // for wstring_convert
#include <locale>   // for codecvt_byname
#include <sstream>
using namespace std;

// helper gets path to this application
string ExePath() {
    char buffer[MAX_PATH];
    GetModuleFileNameA( NULL, buffer, MAX_PATH );
    string::size_type pos = string( buffer ).find_last_of( "\\/" );
    return string( buffer ).substr( 0, pos);
    //return std::string( buffer ).substr( 0, pos);
}

// set variable for command-line arguments
char **argv = NULL;
// helper to get command-line arguments
int ParseCommandLine() {
    int	argc, BuffSize, i;
    WCHAR	*wcCommandLine;
    LPWSTR	*argw;

    wcCommandLine = GetCommandLineW();
    argw = CommandLineToArgvW( wcCommandLine, &argc);

    argv = (char **)GlobalAlloc( LPTR, argc + 1);

    for( i=0; i < argc; i++) {
        BuffSize = WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK, argw[i], -1, NULL, 0, NULL, NULL );
        argv[i] = (char *)GlobalAlloc( LPTR, BuffSize );
        WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK, argw[i], BuffSize * sizeof( WCHAR ),argv[i], BuffSize, NULL, NULL );
    }
    return argc;
}

int CALLBACK WinMain(
    _In_ HINSTANCE hInstance,
    _In_ HINSTANCE hPrevInstance,
    _In_ LPSTR	lpCmdLine,
    _In_ int	nCmdShow)

{
    // for logging in case of error
    int writelog = 0;
    string logtext = ""; 

    // create output filename
    string filename = ExePath() + "\\#clip.txt"; 

    //  get default codepage from Windows, typically 1252
    int iCP=GetACP();
    string sCP;
    ostringstream convert;
    convert << iCP;
    sCP = convert.str();

    // construct string to use for conversion routines (e.g. ".1252")
    string sDefaultCP = "."+sCP;
    string sOutputCP = "."+sCP;

    // read command line for alternate codepage and/or filename
    int i, argc; 
    argc = ParseCommandLine( );

 	if (argc > 1) {
		bool bFilenameSet = false;
		bool bCodepageSet = false;
		int cpint = -1;

		for ( i = 1; i < argc && i<3; i++ ) {
			std::string argstr = argv[i];

			//if string has only digits, use as codepage;
			for (size_t n = 0; n > cpint) || !argss.eof()) {
							argstr = argv[i];
							logtext = logtext + "Requested codepage (if any): " + argstr + "\n";
							//cout is visible only if piped to "more" or similar
							cout << "Requested codepage (if any): " << argstr << endl;
							// check if codepage is valid; if so, use it
							if (IsValidCodePage(cpint)) {
								sCP = argstr;
								sOutputCP = "."+argstr;
							}
							bCodepageSet = true;
						}
					}
				}
			}
		}
	}


    cout << "Codepage used: " + sCP << endl;

    // get clipboard text
    string cliptext = "";

    if (OpenClipboard(NULL)) {
        if(IsClipboardFormatAvailable(CF_TEXT)) {
            HGLOBAL hglb = GetClipboardData(CF_TEXT);
            if (hglb != NULL) {
                LPSTR lptstr = (LPSTR)GlobalLock(hglb);
                if (lptstr != NULL) {
                    // read the contents of lptstr
                    cliptext = (char*)hglb;
                    // release the lock 
                    GlobalUnlock(hglb);
                }
            }
        }
        CloseClipboard();
    }
    // create conversion routines
    typedef std::codecvt_byname codecvt;
    std::wstring_convert cp1252(new codecvt(sDefaultCP));
    std::wstring_convert outpage(new codecvt(sOutputCP));
    ofstream OutStream;  // open an output stream
    OutStream.open(filename, std::ios_base::binary | ios::out | ios::trunc);
    // make sure file is successfully opened
    if(!OutStream) {
        writelog = 1;
        logtext = logtext + "Error opening file " + filename + " for writing.\n";
        //return 1;
    } else {
        // convert to DOS/Win codepage number in "outpage"
        OutStream << outpage.to_bytes(cp1252.from_bytes(cliptext)).c_str();
        OutStream.close(); // close output stream
        if (writelog == 1) {
            logtext = logtext + "Output file: " + filename + "\n";
        }
    }

    if (writelog == 1) {
        logtext = logtext + "Codepage used: " + sCP + "\n";
        string LogFile = ExePath() + "\\#log.txt"; 
        ofstream LogStream;
        LogStream.open(LogFile, ios::out | ios::trunc);
        if(!LogStream) {
            cout << "Error opening file " << LogFile << " for writing.\n";
            return 1;
        }
        LogStream << logtext;
        LogStream.close(); // close output stream
    }
    return 0;
} 


Edward Mendelson (em thirty-six [at] columbia [dot] edu, but with two initials and two numerals before the [at] sign, not spelled out as shown here).