Привет всем! Ребята мне очень неудобно обращаться к вам с такой просьбой, но другого выхода (за разумное время) у меня нет... Есть две функции, написанные на C++. Они показывают: как нужно использовать функцию SHBrowseForFolder в своих программах. Я попробовал перевести их на ассемблер, но у меня ничего не получилось. Удалось перевести только первую функцию и ~50% кода второй (да и то, пока не знаю правильно или нет) и все - я застрял... Кое-что из смутившего меня я, кажется, примерно представляю, как сделать в теории, но на практике этого сделать не получается, т.к. я быстро запутался в одном заголовочном файле (у меня маленький опыт копания в них). А некоторые вещи я вообще не представляю, как реализовать. В общем, помогите, кто может! Переведите эти функции на ассемблер! SOS!!! Ниже я привожу тексты этих двух функций. Кое-где я сделал свои комментарии: ********************************************************** #include <windows.h> #include <atlbase.h> #include <shlobj.h> #pragma comment(lib,"shell32") static int CALLBACK BrowseCallbackProc (HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData) { TCHAR szPath[_MAX_PATH]; switch (uMsg) { case BFFM_INITIALIZED: if (lpData) SendMessage(hWnd,BFFM_SETSELECTION,TRUE,lpData); break; case BFFM_SELCHANGED: SHGetPathFromIDList(LPITEMIDLIST(lParam),szPath); SendMessage(hWnd, BFFM_SETSTATUSTEXT, NULL, LPARAM(szPath)); break; } return 0; } BOOL GetFolder (LPCTSTR szTitle, LPTSTR szPath, LPCTSTR szRoot, HWND hWndOwner) { if (szPath == NULL) return false; bool result = false; LPMALLOC pMalloc; if (::SHGetMalloc(&pMalloc) == NOERROR) { BROWSEINFO bi; ::ZeroMemory(&bi,sizeof bi); bi.ulFlags = BIF_RETURNONLYFSDIRS; // дескриптор окна-владельца диалога bi.hwndOwner = hWndOwner; // добавление заголовка к диалогу bi.lpszTitle = szTitle; // отображение текущего каталога bi.lpfn = BrowseCallbackProc; bi.ulFlags |= BIF_STATUSTEXT; // установка каталога по умолчанию bi.lParam = LPARAM(szPath); // установка корневого каталога if (szRoot != NULL) { IShellFolder *pDF; if (SHGetDesktopFolder(&pDF) == NOERROR) { LPITEMIDLIST pIdl = NULL; ULONG chEaten; ULONG dwAttributes; USES_CONVERSION; //Эту и следующую строчку я вообще незнаю как реализовать... LPOLESTR oleStr = T2OLE(szRoot); pDF->ParseDisplayName(NULL,NULL,oleStr,&chEaten,&pIdl,&dwAttributes); pDF->Release(); bi.pidlRoot = pIdl; } } LPITEMIDLIST pidl = ::SHBrowseForFolder(&bi); if (pidl != NULL) { if (::SHGetPathFromIDList(pidl,szPath)) result = true; pMalloc->Free(pidl); } if (bi.pidlRoot != NULL) pMalloc->Free(bi.pidlRoot); pMalloc->Release(); } return result; } Прототип нашей функции может выглядеть следующим образом: BOOL GetFolder(LPCTSTR szTitle,LPTSTR szPath,LPCTSTR szRoot=NULL,HWND hWndOwner=NULL); ********************************************************** Так теперь показываю, что я всетаки перевел сам (тут, скорее всего, есть куча ошибок): ********************************************************** BrowseCallbackProc proc hWndWORD, uMsgWORD, wParamWORD, lParamWORD mov eax, uMsg .if eax==BFFM_INITIALIZED .if lParam invoke SendMessage, hWnd, BFFM_SETSELECTION, TRUE, lParam .endif .elseif eax==BFFM_SELCHANGED invoke SHGetPathFromIDList, lParam, offset FullPath invoke SendMessage, hWnd, BFFM_SETSTATUSTEXT, NULL, offset FullPath .endif xor eax, eax ret BrowseCallbackProc endp GetFolder proc LPCTSTR szTitle, LPTSTR szPath, LPCTSTR szRoot, HWND hWndOwner LOCAL resultWORD LOCAL pMallocWORD LOCAL bi:BROWSEINFO LOCAL pDFWORD LOCAL pIdlWORD LOCAL chEatenWORD LOCAL dwAttributesWORD mov result, 0 .if !szPath xor eax, eax ret .endif invoke SHGetMalloc, addr pMalloc .if eax==NOERROR invoke ZeroMemory, addr bi, sizeof(bi) mov bi.ulFlags, BIF_RETURNONLYFSDIRS mrm bi.hwndOwner, hWndOwner mrm bi.lpszTitle, szTitle mov bi.lpfn, offset OpenFolderProc or bi.ulFlags, BIF_STATUSTEXT; mrm bi.lParam, szPath ; ; .if szRoot ; invoke SHGetDesktopFolder, addr pDF ; .if eax==NOERROR ; mov pIdl, NULL ; ; .endif ; .endif invoke SHBrowseForFolder, addr bi mov pIdl, eax .if eax invoke SHGetPathFromIDList pIdl, szPath .if eax mov result, TRUE .endif mov eax, pMalloc mov eax, [eax+IMalloc.Free] ; Это только в теории... push pIdl call eax .endif .endif GetFolder endp P.S: Это нужно не для домашнего задания! Мне просто самому интересно... Да и код - стандартный - IMHO, многим пригодится. P.P.S: Прошу прощение, за то что не использую тэги...
Код (Text): .DATA? sBuf db 512 dup (?) .CODE bifCB PROC hWnd:DWORD,uMsg:UINT,wParam:DWORD,lParam:DWORD .IF uMsg == BFFM_INITIALIZED .IF lParam invoke PostMessage,hWnd,BFFM_SETSELECTION,1,lParam .ENDIF .ENDIF ret bifCB ENDP GetFolder proc LPCTSTR szTitle, LPTSTR szPath, LPCTSTR szRoot, HWND hWndOwner push hWndOwner pop DWORD PTR [sBuf] ; hwndOwner and DWORD PTR [sBuf + 4],0 ; pidlRoot and DWORD PTR [sBuf + 8],0 ; pszDisplayName push szTitle pop DWORD PTR [sBuf + 12] ; lpszTitle mov DWORD PTR [sBuf + 16],BIF_STATUSTEXT ; ulFlags mov DWORD PTR [sBuf + 20],OFFSET bifCB ; lpfn push szPath pop DWORD PTR [sBuf + 24] ; lParam and DWORD PTR [sBuf + 28],0 ; iImage invoke SHBrowseForFolder,OFFSET sBuf test eax,eax jz @err invoke SHGetPathFromIDList,eax,szPath @err: ret GetFolder endp Осталось только добавить pMalloc->Free(pidl); Хмм... Об этом уже писали в форуме.
Привет всем! semen Да, я знаю о такой возможности, но на момент создания этого поста у меня не было (и сейчас пока еще нет) соответствующего компилятора... Хотя у кого-то из знакомых я видел MS Visual Studio v6.0, надо будет поискать. Quantum При написании программы я использовал почти такой же код... Причем совершенно забыл про pMalloc->Free(pidl). Спасибо, что напомнил. Я просил перевести этот С++-шный код потому что он показывает как можно более полно использовать возможности диалога открытия папки. К примеру, он демонстрирует следующее: * Установка дескриптора окна-владельца диалога. * Добавление заголовка к диалогу. * Отображение текущего каталога. * Установка каталога по умолчанию. * Установка корневого каталога. Я не вижу причин не использовать эти возможности. Этот код я взял из статьи Игоря Ткачева, "Как выдать окно выбора каталога?" на RSDN. Я уже стал подумывать: а не бросить ли мне эту затею? Тем более, что я подсмотрел как для этой цели можно использовать диалог выбора файла (а он гораздо симпатичнее и проще в использовании)... Всем большое спасибо!
привет! на тебе раб. пример - мучай его хотел вчера кинуть - так инет нам выключили (змеи) 1. диалогом выбора файла нельзя выбрать директорию (по-моему) 2. процедурой обработки сообщений можно творить с окном че хочешь, но поток сообщений туда ограничен: я лепил чекбокс на окне и обрабатывал сообщение о выборе директории, однако если его значение менять после ее выбора - то значение получалось неверное. хотя, вероятно, я испробовал не все 706301455__seldir.zip
shoo Да, это действительно так. В общем, я тоже так думаю. Но, как то раз (в ответе на вопрос №5049), в субскрайбовской рассылке по ассемблеру, один из ее экспертов (Gibbel) сказал, что некоторые умельцы сумели ее для этого приспособить. С тех пор я ищу пример этого... На днях смотрел утилитку Zidrav и, вроде бы, в ней именно так и было по идее сделано. По этому я и обрадовался. Я решил, что диалог выбора файла позволяет выбрать (если указать имя вручную) еще не существующий файл. Но сейчас попробовал это сделать, но у меня ничего не вышло. Видимо это ошибка в той утилитке. За аттач спасибо, сейчас гляну...
наверно нужно флаг указать, что можно указывать несущ файлы - ща не могу глянуть - сисю переустанавливаю (задрала)
shoo Quantum Спасибо за инфу. Буду знать. Автор вышеуказанной утилитки видимо забыл сбросить эти флаги, поэтому там эта фича не работает.
shoo Тогда получается, что в некоторых случаях, если немного по извращаться, то диалог выбора папки все-таки можно заменить на диалог открытия файла. Например, это можно сделать в моем случае: мне диалог выбора папки нужен для выбора папки, в которой будет создан новый файл. Вызывается этот диалог при нажатии на кнопку, закрепленную за полем ввода. После выбора папки, путь к ней помещается в это поле ввода. Причем это поле ввода может заполняться и автоматически при выборе открываемого файла. Сделано это для удобства, чтобы новый файл по умолчанию создавался в той же папке, в которой находится открываемый файл. Теперь посмотрим, как в этом случае можно заменить диалог выбора папки на диалог выбора файла. Для этого просто меняем задачу поля ввода: теперь оно будет содержать не путь к папке, а путь к еще не существующему файлу. Первоначально этот путь будет генерироваться автоматически, после того как пользователь выберет открываемый файл. А далее, если он решит изменить папку, в которой будет создан новый файл, он нажмет соответствующую кнопку и ему будет выдан диалог выбора файла, но фишка в том, что поле имени файла уже будет заполнено по умолчанию значением из поля ввода и юзеру останется указать только новую папку... Ну а в том случае, если перед этим поле ввода еще не будет заполнено, то юзеру помимо папки придется указать и имя файла… Вот вроде бы и все.