Figure 1   LV2Clip

LV2Clip.cpp


/******************************************************************************
Module name: LV2Clip.cpp
Written by:  Jeffrey Richter
Purpose:     Utilty to copy ListView control strings to the clipboard.
******************************************************************************/

#define STRICT
#define UNICODE
#define _UNICODE
#include <Windows.h>
#include <WindowsX.h>
#include <commctrl.h>
#include <tchar.h>
#include <stdio.h>
#include "Resource.h"

///////////////////////////////////////////////////////////////////////////////
// For message box captions
TCHAR g_szAppName[] = __TEXT("ListView to Clipboard");

///////////////////////////////////////////////////////////////////////////////
// Returns HWND of ListView control under a screen coordinate
HWND LV2Clip_GetLVFromPoint(HWND hwnd, int x, int y) {
   POINT pt = { x, y };

   // Convert the (x, y) from client to screen coordinates
   ClientToScreen(hwnd, &pt);

   // Get the top-level window that is under the mouse cursor
   HWND hwndLV = WindowFromPoint(pt);

   // Convert (x, y) from screen to parent window's client coordinates
   ScreenToClient(hwndLV, &pt);

   // Determine which child window (if any) is under the mouse cursor
   hwndLV = ChildWindowFromPoint(hwndLV, pt); 

   if (hwndLV != NULL) {
      // Check to see if the child window is a ListView control
      TCHAR sz[100];
      GetClassName(hwndLV, sz, 100);
      if (lstrcmpi(sz, WC_LISTVIEW) != 0) 
         hwndLV = NULL; // Not a ListView control
   }

   // Update the finder tool's status to indicate whether the cursor
   // is over a ListView control or not.
   SetDlgItemText(hwnd, IDC_FINDERSTATUS, 
                  (hwndLV != NULL) ? 
                  __TEXT("The Finder is over a ListView control") : 
                  __TEXT("The Finder is NOT over a ListView control"));

   return(hwndLV);   // Returns NULL if not a ListView control
}

///////////////////////////////////////////////////////////////////////////////

void LV2Clip_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags) {

   // If we didn't have capture set, we have nothing to do.
   if (GetCapture() == hwnd) {
      // Update the Finder Tool's status
      LV2Clip_GetLVFromPoint(hwnd, x, y);
   }
}

///////////////////////////////////////////////////////////////////////////////

void LV2Clip_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags) {

   // If we didn't have capture set, we have nothing to do.
   if (GetCapture() != hwnd) return;

   ReleaseCapture();

   // Restore the Finder Tool icon
   Static_SetIcon(GetDlgItem(hwnd, IDC_FINDERTOOL), 
      LoadIcon(GetWindowInstance(hwnd), MAKEINTRESOURCE(IDI_DOCKEDFINDER)));

   // Get the HWND of the ListView under the mouse cursor
   HWND hwndLV = LV2Clip_GetLVFromPoint(hwnd, x, y);

   // If the window under the cursor isn't a ListView, we have nothing to do.
   if (hwndLV == NULL) return;

   // Get the count of items in the ListView control
   int nCount = ListView_GetItemCount(hwndLV);

   // Open a handle to the remote process's kernel object
   DWORD dwProcessId;
   GetWindowThreadProcessId(hwndLV, &dwProcessId);
   HANDLE hProcess = OpenProcess(
      PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, 
      FALSE, dwProcessId);

   if (hProcess == NULL) {
      MessageBox(hwnd, __TEXT("Could not communicate with process"), 
         g_szAppName, MB_OK | MB_ICONWARNING);
      return;
   }

   // Prepare a buffer to hold the ListView's data.
   // Note: Hardcoded maximum of 10240 chars for clipboard data.
   // Note: Clipboard only accepts data that is in a block allocated with 
   //       GlobalAlloc using the GMEM_MOVEABLE and GMEM_DDESHARE flags.
   HGLOBAL hClipData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, 
      sizeof(TCHAR) * 10240);
   LPTSTR pClipData = (LPTSTR) GlobalLock(hClipData);
   pClipData[0] = 0;

   // Allocate memory in the remote process's address space
   LV_ITEM* plvi = (LV_ITEM*) VirtualAllocEx(hProcess, 
      NULL, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

   // Get each ListView item's text data
   for (int nIndex = 0; nIndex < nCount; nIndex++) {

      // Initialize a local LV_ITEM structure
      LV_ITEM lvi;
      lvi.mask = LVIF_TEXT;
      lvi.iItem = nIndex;
      lvi.iSubItem = 0; 
      // NOTE: The text data immediately follows the LV_ITEM structure
      //       in the memory block allocated in the remote process.
      lvi.pszText = (LPTSTR) (plvi + 1); 
      lvi.cchTextMax = 100; 

      // Write the local LV_ITEM structure to the remote memory block
      WriteProcessMemory(hProcess, plvi, &lvi, sizeof(lvi), NULL);

      // Tell the ListView control to fill the remote LV_ITEM structure
      ListView_GetItem(hwndLV, plvi);

      // If this is not the first item, add a carriage-return/linefeed
      if (nIndex > 0) lstrcat(pClipData, __TEXT("\r\n"));

      // Read the remote text string into the end of our clipboard buffer
      ReadProcessMemory(hProcess, plvi + 1, 
         &pClipData[lstrlen(pClipData)], 1024, NULL);
   }

   // Free the memory in the remote process's address space
   VirtualFreeEx(hProcess, plvi, 0, MEM_RELEASE);

   // Cleanup and put our results on the clipboard
   CloseHandle(hProcess);
   OpenClipboard(hwnd);
   EmptyClipboard();
#ifdef UNICODE
   BOOL fOk = (SetClipboardData(CF_UNICODETEXT, hClipData) == hClipData);
#else
   BOOL fOk = (SetClipboardData(CF_TEXT, hClipData) == hClipData);
#endif
   CloseClipboard();
   if (!fOk) {
      GlobalFree(hClipData);
      MessageBox(hwnd, __TEXT("Error putting text on the clipboard"), 
	       g_szAppName, MB_OK | MB_ICONINFORMATION);
   }
}

///////////////////////////////////////////////////////////////////////////////

void LV2Clip_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) {
   switch (id) {
   case IDCANCEL: 
      EndDialog(hwnd, 0); 
      break;

   case IDC_FINDERTOOL:
      switch (codeNotify) {
      case STN_CLICKED:
         SetCapture(hwnd);
         Static_SetIcon(hwndCtl, LoadIcon(GetWindowInstance(hwnd), 
                        MAKEINTRESOURCE(IDI_FLOATINGFINDER)));
         SetCursor(LoadCursor(GetWindowInstance(hwnd), 
                   MAKEINTRESOURCE(IDC_FINDER)));
         break;
      }
      break;
   }
}

///////////////////////////////////////////////////////////////////////////////

BOOL WINAPI LV2Clip_WndProc(HWND hwnd, UINT uMsg, 
   WPARAM wParam, LPARAM lParam) {

   switch (uMsg) {
      HANDLE_MSG(hwnd, WM_COMMAND,    LV2Clip_OnCommand);
      HANDLE_MSG(hwnd, WM_MOUSEMOVE,  LV2Clip_OnMouseMove);
      HANDLE_MSG(hwnd, WM_LBUTTONUP,  LV2Clip_OnLButtonUp);
   }
   return(FALSE);
}

///////////////////////////////////////////////////////////////////////////////

int WINAPI WinMain(HINSTANCE hinstExe, 
   HINSTANCE hinstExePrev, LPSTR pszCmdLine, int nCmdLine) {
   return(DialogBox(hinstExe, MAKEINTRESOURCE(IDD_LV2CLIP), 
                    NULL, LV2Clip_WndProc));
}

///////////////////////////////// End of File /////////////////////////////////

Figure 2   MyApp Exception


 int WINAPI WinMain(HINSTANCE hinstExe, HINSTANCE hinstExePrev, 
                    LPSTR pszCmdLine, int nCmdShow) {
 
    HRSRC hrsrc = FindResource(hinstExe, MAKEINTRESOURCE(IDB_SOMEBITMAP), 
                               RT_BITMAP);
    HGLOBAL hglbl = LoadResource(hinstExe, hrsrc);
    PBYTE pb = (PBYTE) GlobalLock(hglbl);
    BYTE b = *pb;  // This does not generate an access violation
    *pb = 5;       // This does generate an access violation
    return(0);
 }