Jump to content

Anyone solved this problem?


Recommended Posts

Yes.. but its not pretty. I made a C++ function in a DLL to do it.

// given the hwnd for a listbox, put the contents into a pipe delimited string. however, if there are multiple versions of the same string, append a $$X occurance to the end of each one
const char EXPORT *ExtractListContents(HWND hwnd)
{
    static char results[4096];

    *results = '\0';

    long count = SendMessage(hwnd, LB_GETCOUNT, 0, 0);
    map<string, int> SeenList;

    for (long i = 0; i < count; ++i)
    {
        char item[256] = "";
        SendMessage(hwnd, LB_GETTEXT, i, (long) item);

        int cnt = 0;
        map<string, int>::iterator itr = SeenList.find(string(item));
        if (itr == SeenList.end())
        {
            SeenList.insert(make_pair(string(item), 1));
        } else {
            cnt = ++(*itr).second;
        }
        if (i != 0)
            strcat(results, "|");
        strcat(results, item);
        if (cnt >= 2)
        {
            char tmp[32];
            sprintf(tmp, "$$%d", cnt);
            strcat(results, tmp);
        }
    }
    return results;
}

Then some AutoIt wrapper functions for getting to the hwnd for the list:

; return the hwnd for the *active* control in the given window
Func GetActiveControl($title)
   WinActivate($title)
   return ControlGetHandle($title, "", ControlGetFocus($title))
Endfunc

Func ExtractListContents($hwnd)
    Local $foo = DllCall($g_socdll, "str", "ExtractListContents", "hwnd", $hwnd)
    If @error Then
        MsgBox(0, "Debug", "Error with DllCall(ExtractListContents)")
    Endif
    Return $foo[0]
Endfunc

I'm still working on the equivalent for a SysTreeView control...

Link to comment
Share on other sites

Hmm, wouldn't it be pretty easy to include in AutoIt so we can use it? i mean, alot of people are waiting for this to be fixed, including me... im on a large program, and have two parts of the program witch really need it, and i can't finish it because of this bug :)

Link to comment
Share on other sites

Ooops. I included the code for reading from a regular list box. To read from a ListView32 is just a *teensy* bit harder, since you cannot just grab memory across from one process to another. To work around this minor inconvience, I had to whip out the mega coding kungfu!! You have to actually attach yourself to the other process, so you can allocate memory in its process space to work with. Joy! This version put the contents in the clipboard instead of actually returning the string.

And no, sorry, I can't just give you my DLL I'm using! AutoIt Team: feel free to include this whever you like.

Example C++ code:

int EXPORT CopyListViewToClipboard(HWND hwnd, HWND hwndLV)
{
    //fprintf(stderr, "CopyListViewToClipboard(%p, %pd) called\n", hwnd, hwndLV);
    // If the window under the cursor isn't a ListView, we have nothing to do.
   if (hwndLV == NULL) return 0;


   // 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"), 
         "CopyListViewToClipboard", MB_OK | MB_ICONWARNING);
      return 0;
   }

   // 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"), 
           "CopyListViewToClipboard", MB_OK | MB_ICONINFORMATION);
   }
   return (fOk) ? 1 : 0;
}
Link to comment
Share on other sites

What are you trying to retreive from the ListView ?

<{POST_SNAPBACK}>

Okay, i have two GUI's, Main GUI and Second GUI. The Listview is created in the second GUI, so i would like to have a msgbox telling me what thay Listviewitem im clicking on contains.

Like:

If $Button Then

Msgbox(0,"Test",$GuiCtrlRead($Listview)) ; from the second GUI

EndIf

Link to comment
Share on other sites

Here is a quick example on how to get the Items from a First and second GUI with ControlListview

#include <GUIConstants.au3>

$GUI_1 = GUICreate("listview items",220,250, 0,0,-1,$WS_EX_ACCEPTFILES)
GUISetBkColor (0x00E0FFFF) ; will change background color

$listviewGUI1 = GuiCtrlCreateListView ("col1  |col2  |col3  ",10,10,200,150);,$LVS_SORTDESCENDING)
$button1 = GuiCtrlCreateButton ("GUI1GetAllItems",10,170,100,20)
$button2 = GuiCtrlCreateButton ("GUI2GetAllItems",110,170,100,20)
$item1=GuiCtrlCreateListViewItem("GUI1item1|GUI1item2|GUI1item3",$listviewGUI1)
$item2=GuiCtrlCreateListViewItem("GUI1item2_1|GUI1item2_2|GUI1item2_3",$listviewGUI1)
$item3=GuiCtrlCreateListViewItem("GUI1item3_1|GUI1item3_2|GUI1item3_3",$listviewGUI1)
GuiSetState()

$GUI_2 = GUICreate("listview items",220,250, 300,0,-1,$WS_EX_ACCEPTFILES)
GUISetBkColor (0x00E0FFFF) ; will change background color

$listviewGUI2 = GuiCtrlCreateListView ("col1  |col2  |col3  ",10,10,200,150);,$LVS_SORTDESCENDING)
GuiCtrlCreateListViewItem("GUI2item1|GUI2item2|GUI2item3",$listviewGUI2)
GuiCtrlCreateListViewItem("GUI2item2_1|GUI2item2_2|GUI2item2_3",$listviewGUI2)
GuiCtrlCreateListViewItem("GUI2item3_1|GUI2item3_2|GUI2item3_3",$listviewGUI2)
GuiSetState()

Do
  $msg = GuiGetMsg ()    
   Select
      Case $msg = $button1
         $ItemCount = ControlListView ( $GUI_1, "", "SysListView321","GetItemCount")
         For $i = 0 To $ItemCount -1
            MsgBox(0,"",ControlListView ( $GUI_1, "", "SysListView321","GetText", $i))
         Next
      Case $msg = $button2
         $ItemCount = ControlListView ( $GUI_2, "", "SysListView321","GetItemCount")
         For $i = 0 To $ItemCount -1
            MsgBox(0,"",ControlListView ( $GUI_2, "", "SysListView321","GetText", $i))
         Next
   EndSelect
Until $msg = $GUI_EVENT_CLOSE
Link to comment
Share on other sites

Try this:

#include <GUIConstants.au3>

$GUI_1 = GUICreate("listview items",220,250, 0,0,-1,$WS_EX_ACCEPTFILES)
GUISetBkColor (0x00E0FFFF) ; will change background color

$listviewGUI1 = GuiCtrlCreateListView ("col1  |col2  |col3  ",10,10,200,150);,$LVS_SORTDESCENDING)
$button1 = GuiCtrlCreateButton ("GUI1GetSelected",10,170,100,20)
$button2 = GuiCtrlCreateButton ("GUI2GetSelected",110,170,100,20)
GuiCtrlCreateListViewItem("GUI1item1|GUI1item2|GUI1item3",$listviewGUI1)
GuiCtrlCreateListViewItem("GUI1item2_1|GUI1item2_2|GUI1item2_3",$listviewGUI1)
GuiCtrlCreateListViewItem("GUI1item3_1|GUI1item3_2|GUI1item3_3",$listviewGUI1)
GuiSetState()

$GUI_2 = GUICreate("listview items",220,250, 300,0,-1,$WS_EX_ACCEPTFILES)
GUISetBkColor (0x00E0FFFF) ; will change background color

$listviewGUI2 = GuiCtrlCreateListView ("col1  |col2  |col3  ",10,10,200,150);,$LVS_SORTDESCENDING)
GuiCtrlCreateListViewItem("GUI2item1|GUI2item2|GUI2item3",$listviewGUI2)
GuiCtrlCreateListViewItem("GUI2item2_1|GUI2item2_2|GUI2item2_3",$listviewGUI2)
GuiCtrlCreateListViewItem("GUI2item3_1|GUI2item3_2|GUI2item3_3",$listviewGUI2)
GuiSetState()

Do
    $msg = GuiGetMsg ()
    Select
        Case $msg = $button1
            If ControlListView ( $GUI_1, "", "SysListView321","GetSelectedCount") > 0 Then
                MsgBox(0,"",ControlListView ( $GUI_1, "", "SysListView321","GetText", ControlListView ( $GUI_1, "", "SysListView321","GetSelected")))
            EndIf
        Case $msg = $button2
            If ControlListView ( $GUI_2, "", "SysListView321","GetSelectedCount") > 0 Then
                MsgBox(0,"",ControlListView ( $GUI_2, "", "SysListView321","GetText", ControlListView ( $GUI_2, "", "SysListView321","GetSelected")))
            EndIf
    EndSelect
Until $msg = $GUI_EVENT_CLOSE
Link to comment
Share on other sites

  • 3 months later...

all i do is save the data added to the list into an array, then i read from the array and not the list.

works for me.

Valik Note Added 19 October 2006 - 08:38 AMAdded to warn level I just plain don't like you.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...