Source file: /~heha/hs/ToClipboard.zip/src/ToClipboard.c

/* ToClipboard:
   -f
   Moves the content of a file to clipboard, dependent of file type (magic header).
   Should support WMF, EMF, BMP, JPG, PNG, WAV, CLP.
   For not recognized files, the text of the file will be loaded (ANSI, OEM, UTF-16 or UTF-8).
   -t
   Does the remainder of command line as text to clipboard
   -l
   Does the given file name as shell link to clipboard (no support yet)

   If no option given, the program defaults to -f if argument exists as file name,
   otherwise, it defaults to -t.

+080929	written
+081019	BMP added, Unicode support (even for Win98SE, requires KernelEx package installed)

Currently not supported:
- Any codepage support for text files
- JPG,PNG,WAV,CLP
- Shell links
 */
#include <windows.h>
#include <shlwapi.h>
#define elemof(x) (sizeof(x)/sizeof(*(x)))
#define nobreak
typedef enum {false, true} bool;
#undef RtlMoveMemory
VOID WINAPI RtlMoveMemory (void*, const void*, size_t);

// convenient message boxing
int vMBox(UINT id, va_list va) {
 TCHAR buf[1024], format[256];
 if (!LoadString(0,id,format,elemof(format))) {
#ifdef UNICODE
  char buf[256];
  LoadStringA(0,id,buf,elemof(buf));
  MultiByteToWideChar(CP_ACP,0,buf,-1,format,elemof(format));
#endif
 }
 wvnsprintf(buf,elemof(buf),format,va);
 return MessageBox(0,buf,NULL,0);
}

int _cdecl MBox(UINT id, ...) {
 return vMBox(id,(va_list)(&id+1));
}

// Put arbitrary data from memory to clipboard
void SetClip(UINT fmt, const void*data, size_t len, size_t append) {
 HGLOBAL mem=GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,len+append);
 if (!mem) return;
 RtlMoveMemory(GlobalLock(mem),data,len);
 GlobalUnlock(mem);
 SetClipboardData(fmt,mem);
}

// Put text to clipboard (encoding of text ???)
void HandleTextFile(const void *p, size_t len) {
 SetClip(CF_TEXT,p,len,1);
}

// This file type is almost unused!
void HandleWmfFile(const void *p, size_t len) {
 METAFILEPICT mf;
 mf.mm=MM_ANISOTROPIC;
 mf.xExt=0;
 mf.yExt=0;
 mf.hMF=SetMetaFileBitsEx(len,(const BYTE*)p);
 SetClip(CF_METAFILEPICT,&mf,sizeof(mf),0);
}

#pragma pack(push,2)
typedef struct{
 DWORD id;
 WORD  handle;
 short left;
 short top;
 short right;
 short bottom;
 short inch;
 DWORD reserved;
 WORD  checksum;
}PLACEABLE_HEADER;
#pragma pack(pop)

// This handles the widely used Aldus Placeable Metafiles
void HandlePlaceableWmfFile(const void *p, size_t len) {
 METAFILEPICT mf;
 const PLACEABLE_HEADER *pmh=p;
 HMETAFILE meta;
 HDC dc;
// don't know why and how much clipboard and MS office shrink the clipping rect
 int w=pmh->right-pmh->left+4;		// width in "units";
 int h=pmh->bottom-pmh->top+4;		// height in "units"
 mf.mm=MM_ANISOTROPIC;
// For standard SCH2WMF boards, pmh->inch contains 1000, meaning one WMF unit is 1 mil (25.4µm).
 mf.xExt=MulDiv(w,2540,pmh->inch);	// extent in MM_HIMETRIC (10µm) units
 mf.yExt=MulDiv(h,2540,pmh->inch);
 dc=CreateMetaFile(NULL);
#ifdef UNICODE
 if (!dc) dc=CreateMetaFileA(NULL);
#endif
 SetWindowOrgEx(dc,pmh->left,pmh->top,NULL);
 SetWindowExtEx(dc,w,h,NULL);		// Set this records in front of file data
 meta=SetMetaFileBitsEx(len-22,(const BYTE*)p+22);
 PlayMetaFile(dc,meta);			// Copy file data behind these records
 DeleteMetaFile(meta);
 mf.hMF=CloseMetaFile(dc);		// Put this newly created metafile to clipboard
 SetClip(CF_METAFILEPICT,&mf,sizeof(mf),0);
}

// For EMF files, handling is easy. Should include EMF+ files.
void HandleEmfFile(const void *p, size_t len) {
 SetClipboardData(CF_ENHMETAFILE,SetEnhMetaFileBits(len,p));
}

// For BMP files, parse file content
void HandleBmpFile(const void *p, size_t len) {
 SetClip(CF_DIB,((BITMAPFILEHEADER*)p)+1,len-sizeof(BITMAPFILEHEADER),0);
}

void CALLBACK WinMainCRTStartup(void) {
 PTSTR CmdLine;
 char option=0;		// default to guess mode

 CmdLine=PathGetArgs(GetCommandLine());
 switch (*CmdLine) {
  case '-':
  case '/': {		// option given, parse for known option
   option=(char)*++CmdLine;
   switch (*++CmdLine) {
    case ' ':
    case '\t': break;
    default: MBox(1); ExitProcess(1);
   }
   CmdLine++;
  }break;
 }
 if (*CmdLine=='"') {
  PathUnquoteSpaces(CmdLine);
 }
// If no option given, check whether argument exists as file
// Surprisingly, on Win98SE, CreateFileW exists and works as expected.
// Sorry, this is only true when "Kernel Extensions" are installed.
// But this is incompatible to "Foxit Reader".
 if (!option) {
  HANDLE f=CreateFile(CmdLine,0,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,0);
  if (f==INVALID_HANDLE_VALUE) f=0;
  if (f) {
   CloseHandle(f);
   option='f';
  }else{
   option='t';
  }
 }
// Now we have the text or filename portion in CmdLine
 switch (option) {
  case 'F':
  case 'f': {
   const void *p;
   DWORD filesize;
   HANDLE fm;
   HANDLE f=CreateFile(CmdLine,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,0);
   if (f==INVALID_HANDLE_VALUE) f=0;
   if (!f) {
    DWORD code=GetLastError();
    MBox(4,CmdLine,code);
    ExitProcess(code);
   }
   filesize=GetFileSize(f,NULL);
   if (filesize<32) ExitProcess(1);
   fm=CreateFileMapping(f,NULL,PAGE_READONLY,0,0,NULL);
   if (!fm) ExitProcess(GetLastError());
   p=MapViewOfFile(fm,FILE_MAP_READ,0,0,0);
   if (!p) ExitProcess(GetLastError());

   if (OpenClipboard(0)) {
    EmptyClipboard();
    switch (*(PDWORD)p) {
     case 0x9AC6CDD7: HandlePlaceableWmfFile(p,filesize); break;
     case 0x00090001:
     case 0x00090002: HandleWmfFile(p,filesize); break;
     case 0x00000001: if (((PDWORD)p)[10]==ENHMETA_SIGNATURE) {
      HandleEmfFile(p,filesize);
      break;
     }nobreak;
     default:
      if (*(PWORD)p=='MB') {
       HandleBmpFile(p,filesize);
       break;
      }
      HandleTextFile(p,filesize); break;
    }
    CloseClipboard();
   }else MBox(5);
   CloseHandle(fm);
   CloseHandle(f);
  }break;

  case 'T':
  case 't': {
   if (OpenClipboard(0)) {
    EmptyClipboard();
#ifdef UNICODE    
    SetClip(CF_UNICODETEXT,CmdLine,lstrlen(CmdLine)*2,2);
#else
    SetClip(CF_TEXT,CmdLine,lstrlen(CmdLine),1);
#endif
    CloseClipboard();
   }else MBox(5);
  }break;

  case 'L':
  case 'l': {
   MBox(3,option);
  }break;
  default: MBox(2,option); ExitProcess(1);
 }
 ExitProcess(0);
}
Detected encoding: ANSI (CP1252)4
Wrong umlauts? - Assume file is ANSI (CP1252) encoded