CB_SETITEMDATA
От: Maks1509 Россия http://mv-software.narod.ru
Дата: 01.12.10 11:34
Оценка:
Использую ComboboxEx и добавляю текст в каждый элемент списка в стековый массив pszData в WM_INITDIALOG.


//
var
  pszData: Array of WideString;
//
          SetLength(pszData, iItem + 1);
          pszData[iItem] := hData.cFileName;
          SendMessageW(GetDlgItem(hWnd, IDC_LANG_LIST), CB_SETITEMDATA, iItem,
            LPARAM(pszData[iItem]));


На семёрке этот код возвращает ересь в WM_CLOSE:

var
  dwRet  : Integer;
  pszText: WideString;
//
          dwRet := SendMessageW(GetDlgItem(hWnd, IDC_LANG_LIST), CB_GETCURSEL,
            0, 0);
          if (dwRet <> CB_ERR) then
          begin

            pszText := LPWSTR(SendMessageW(GetDlgItem(hWnd, IDC_LANG_LIST),
              CB_GETITEMDATA, dwRet, 0));

          end;


Неужто надо объявить этот массив глобальным? Не хочу лишних глобальных переменных, тем более под 2000 и XP корректно извлекается текст с каждого элемента. Рассматриваю как вариант SetWindowLongPtrW + GWL_USERDATA для массива, должно сработать. Что можно придумать?
Re: CB_SETITEMDATA
От: fuyant  
Дата: 01.12.10 12:24
Оценка:
Здравствуйте, Maks1509, Вы писали:

M>Использую ComboboxEx и добавляю текст в каждый элемент списка в стековый массив pszData в WM_INITDIALOG.


M>
M>//
M>var
M>  pszData: Array of WideString;
M>//
M>          SetLength(pszData, iItem + 1);
M>          pszData[iItem] := hData.cFileName;
M>          SendMessageW(GetDlgItem(hWnd, IDC_LANG_LIST), CB_SETITEMDATA, iItem,
M>            LPARAM(pszData[iItem]));
M>


Ээээ.... ты ожидаешь, что CB_SETITEMDATA скопирует твою строку в какой-то свой внутренний буфер?
Re[2]: CB_SETITEMDATA
От: Maks1509 Россия http://mv-software.narod.ru
Дата: 01.12.10 12:37
Оценка:
Здравствуйте, fuyant, Вы писали:

F>Ээээ.... ты ожидаешь, что CB_SETITEMDATA скопирует твою строку в какой-то свой внутренний буфер?


Ну конечно же. Правда глупо ожидать такого если в MSDN чётко указано DWORD значение. Есть ли вариант попроще? Хочу хранить дополнительно строку в каждом элементе.
А всё же интересно, почему на XP x64, виртуальных 2000 и XP строка "достаётся" корректно?
Re[3]: CB_SETITEMDATA
От: fuyant  
Дата: 01.12.10 12:57
Оценка:
Здравствуйте, Maks1509, Вы писали:

M>Здравствуйте, fuyant, Вы писали:


F>>Ээээ.... ты ожидаешь, что CB_SETITEMDATA скопирует твою строку в какой-то свой внутренний буфер?


M>Ну конечно же. Правда глупо ожидать такого если в MSDN чётко указано DWORD значение.


во-во, совсем глупо

M>Есть ли вариант попроще? Хочу хранить дополнительно строку в каждом элементе.


два варианта:
1. хранить свой массив, например, где-нить полем класса, и подсовывать указатели на эти строки в CB_SETITEMDATA
2. создавать строки в куче и в CB_SETITEMDATA запихивать указатели на эти строки. При этом перед разрушением комбобокса обязательно пройтись по всем элементам комбобокса и удалить созданные строки. И не забывать очищать также и перед удалением айтемов из комбобокса.

M>А всё же интересно, почему на XP x64, виртуальных 2000 и XP строка "достаётся" корректно?


Тупо везение. Вообще то это UB
Re[4]: CB_SETITEMDATA
От: fuyant  
Дата: 01.12.10 13:00
Оценка:
Здравствуйте, fuyant, Вы писали:

F>Тупо везение. Вообще то это UB


Неправильно выразился. Никакой тут не UB — это четкий крэш. А не падает потому что тупо везет. Может из-за дебаг-версии, может из-за виртуалки.
Re[5]: CB_SETITEMDATA
От: Maks1509 Россия http://mv-software.narod.ru
Дата: 01.12.10 14:36
Оценка:
Здравствуйте, fuyant, Вы писали:

F>Здравствуйте, fuyant, Вы писали:


F>>Тупо везение. Вообще то это UB


F>Неправильно выразился. Никакой тут не UB — это четкий крэш. А не падает потому что тупо везет. Может из-за дебаг-версии, может из-за виртуалки.


Да мне самому очень интересно, я некоторым тестерам скидывал приложение, всё отлично работало (на семёрке никто не тестировал из них). Это не отладочная сборка точно. Соответсвенно для меня было удивлением такое поведение программы.

Код в инициализации диалога:
var
  pszData: Array of Array [0..MAX_PATH-1] of WideChar;
  // заполняем здесь массив.
  SetWindowLongPtrW(GetDlgItem(hWnd, IDC_LANG_LIST), GWL_USERDATA, Longint(pszData));


Код при завершении диалога:
  pszData := Pointer(GetWindowLongPtrW(GetDlgItem(hWnd, IDC_LANG_LIST), GWL_USERDATA));
  if (pszData <> nil) then
  begin
    SetLength(pszData, 0);
    SetWindowLongPtrW(GetDlgItem(hWnd, IDC_LANG_LIST), GWL_USERDATA, 0);
  end;


Вроде отлично работает.
Re[6]: CB_SETITEMDATA
От: fuyant  
Дата: 01.12.10 22:50
Оценка:
Здравствуйте, Maks1509, Вы писали:

M>Здравствуйте, fuyant, Вы писали:


F>>Здравствуйте, fuyant, Вы писали:


F>>>Тупо везение. Вообще то это UB


F>>Неправильно выразился. Никакой тут не UB — это четкий крэш. А не падает потому что тупо везет. Может из-за дебаг-версии, может из-за виртуалки.


M>Да мне самому очень интересно, я некоторым тестерам скидывал приложение, всё отлично работало (на семёрке никто не тестировал из них). Это не отладочная сборка точно. Соответсвенно для меня было удивлением такое поведение программы.


M>Код в инициализации диалога:

M>
M>var
M>  pszData: Array of Array [0..MAX_PATH-1] of WideChar;
M>  // заполняем здесь массив.
M>  SetWindowLongPtrW(GetDlgItem(hWnd, IDC_LANG_LIST), GWL_USERDATA, Longint(pszData));
M>


Если все работает и не падает, то могу предположить следующее.
Элементы массива — искомые строки — создаются в куче. Указатели на созданные строки помещаются в USERDATA, потому они и нормально функциклюют.
Зато присутствуют утечки памяти — если эти строки создались в куче, память, выделенную под них, нужно освободить после использования, т.е. delete [] pszData. Ну или как там на делфи это делается, я не знаю....
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.