Clip2txt.exe (download here) is a Windows command-line utility that writes the contents of the Windows clipboard 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, 1252, 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.
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 2019 or later; create a Win32 project named Clip2txt; replace the contents of Clip2txt.cpp with the code below; then, in the Properties panel, change the Linker->System->Subsystem from a Windows app to a console app. Since this procedure may be tricky or unreliable, it's probably best to start with this complete VS2019 build environment.
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 <argstr.length(); n++) { if (!isdigit( argstr[ n ]) ) { if (!bFilenameSet) { filename = argv[i]; bFilenameSet = true; } } else { // convert codepage string to integer if (!bCodepageSet) { std::stringstream argss(argv[i]); if( (argss >> 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 is visible only if piped to "more" or similar cout << "Codepage: " + 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<wchar_t,char,std::mbstate_t> codecvt; std::wstring_convert<codecvt> cp1252(new codecvt(sDefaultCP)); std::wstring_convert<codecvt> 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) { // stdout only visible if output is piped to "more" or elsewhere cout << "Error opening file " << LogFile << " for writing.\n"; return 1; } LogStream << logtext; LogStream.close(); // close output stream } return 0; }
Edward Mendelson (edward [dot] mendelson [at] columbia [dot] edu)