Пишу простенький файловый менеджер, возник ряд вопросов. Язык С++
Возник такой вопрос, для атрибутов файлов существуют константные обозначения FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_COMPRESSED и т.д. а если файл является, допустим, архивным и скрытым да еще и только для чтения? В заголовочном файле winnt.h, где данные константы объявляются, ни чего подобного нет, из чего предполагаю, что в данном случае константы как то комбинируются!
Искал везде где только можно, ни какой информации не нашел, может кто сталкивался и разрешит мои затруднения?
И еще возник вопрос: каким образом получить список доступных устроиств хранения данных? Например сколько дисков, есть ли в сидироме диск, доступны ли флэш диски. И как обновлять данный список автоматически при его изменение.
И так же еще: как узнать какая программа работает с конкретным файлом и как по желанию пользователя запустить ее, что бы она начала работу именнно с этим файлом?
Т.е. тогда ты должен обрабатывать результат функции
DWORD GetFileAttributes(
LPCTSTR lpFileName // address of the name of a file or directory
);
операторами побитового сдвига << и >>
Определенный бит отвечает за определённый аттрибут файла
2. Про диски
а)DWORD GetLogicalDrives(VOID)
DWORD GetLogicalDriveStrings(
DWORD nBufferLength, // size of buffer
LPTSTR lpBuffer // address of buffer for drive strings
);
б)UINT GetDriveType(
LPCTSTR lpRootPathName // address of root path
);
в) Информацию о вставленном диске можно попробовать получить посредтвом чтения с устройства как с файла.
Способ может не самый удобный :)
CreateFile()
SetFilePointer()
ReadFile()
Если диск будет вставлен, то ты будешь читать диск полностью, если нет,
то там ничего не будет :)
3. И про запуск программ по желанию пользователя.
Таким способом тебе даже не нужно знать про привязки программ к конкретному типу файлов
(А вообще привязки в реестре HKCR)
HINSTANCE ShellExecute(
HWND hwnd, // handle to parent window
LPCTSTR lpOperation, // pointer to string that specifies operation to perform
LPCTSTR lpFile, // pointer to filename or folder name string
LPCTSTR lpParameters, // pointer to string that specifies executable-file parameters
LPCTSTR lpDirectory, // pointer to string that specifies default directory
INT nShowCmd // whether file is shown when opened
);
FILE_ATTRIBUTE_HIDDEN 0x00000002
FILE_ATTRIBUTE_SYSTEM 0x00000004
FILE_ATTRIBUTE_DIRECTORY 0x00000010
FILE_ATTRIBUTE_ARCHIVE 0x00000020
........................................................................
........................................................................
В таком случая на сколько я тебя понял код будет:
int n;
for( int i = 0; i < 26; i++ )
{
n = ((df>>i)&0x00000001);
//дальше сравниваем с константами
}
Если я не прав, поправь меня как надо, так как в верности сомневаюсь.
Еще осталась проблема с тем как обработать изменение количества доступных дисков, на сколько я понимаю, при появление или отключения устройства должно посылаться некоторое сообщение, в таком случае возникает вопрос, какое это сообщение и как его правильно обработать?
И возник еще один вопрос, как получить иконку, для каждого типа файлов не посредтвенно из файла?
FILE_ATTRIBUTE_HIDDEN 00000010
FILE_ATTRIBUTE_SYSTEM 00000100
...
Не нужно ничег сдвигать нужно просто умножить (как учил Буль) твой df на какую-нибудь из констант и проверить результат:
...
}
Тоесть допустим у тебя df = 3 те(00000011) тогда после умножения на 00000001 ты получишь 00000001.
2. Диски посылается сообщение WM_DEVICECHANGE описание смотри в справке
3.Иконку можно получить через ExtractAssociatedIcon - к сожаления не знаю где в MSVC++она описана =(
Не нужно ничег сдвигать нужно просто умножить (как учил Буль) твой df на какую-нибудь из констант и проверить результат:
...
}
Тоесть допустим у тебя df = 3 те(00000011) тогда после умножения на 00000001 ты получишь 00000001.
Правильно, но ведь надо получить атрибуты типа скрытый+архивный, в таком случае мы вообще не получим атрибута, твоим способом, так как если атрибуты комбинируются, то функция вернет число - битовую маску, к примеру, когда писал программу для поиска файлов на Builder'е то имел такие результаты, если мне не изменяет память 128 это системный, а 317 это уже скрытый системный!
Спасибо, с остальным ты мне очень помог!=)
А что кроме побитового умножения ничего не существует ещё ?
..<файл скрытый и архивный>
..<файл скрытый и архивный>
Кстати, это вариант, не уверен что будет работать, но попробовать стоит...
bool is_readonly;
bool is_hidden;
bool is_system;
bool is_directory;
bool is_archive;
bool is_encripted;
bool is_normal;
bool is_temporary;
bool is_sparse_file;
bool is_reparse_point;
bool is_compressed;
bool is_offline;
bool is_not_indexed;
};
bool get_attribute(TCHAR* fname, struct file_attribute & fa) {
DWORD attr=GetFileAttributes(fname);
bool result = ( attr != 0xFFFFFFFF );
if (result) {
fa.is_readonly = ( 0 != ( attr & FILE_ATTRIBUTE_READONLY ) );
fa.is_hidden = ( 0 != ( attr & FILE_ATTRIBUTE_HIDDEN ) );
fa.is_system = ( 0 != ( attr & FILE_ATTRIBUTE_SYSTEM ) );
fa.is_directory = ( 0 != ( attr & FILE_ATTRIBUTE_DIRECTORY ) );
fa.is_archive = ( 0 != ( attr & FILE_ATTRIBUTE_ARCHIVE ) );
fa.is_encripted = ( 0 != ( attr & FILE_ATTRIBUTE_ENCRYPTED ) );
fa.is_normal = ( 0 != ( attr & FILE_ATTRIBUTE_NORMAL ) );
fa.is_temporary = ( 0 != ( attr & FILE_ATTRIBUTE_TEMPORARY ) );
fa.is_sparse_file = ( 0 != ( attr & FILE_ATTRIBUTE_SPARSE_FILE ) );
fa.is_reparse_point = ( 0 != ( attr & FILE_ATTRIBUTE_REPARSE_POINT ) );
fa.is_compressed = ( 0 != ( attr & FILE_ATTRIBUTE_COMPRESSED ) );
fa.is_offline = ( 0 != ( attr & FILE_ATTRIBUTE_OFFLINE ) );
fa.is_not_indexed = ( 0 != ( attr & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED ) );
}
return result;
}
#include <windows.h>
using namespace std;
int main(void)
{
DWORD df = GetFileAttributes("C:\\Новый текстовый документ (2).txt");
cout << df<< endl;
if((df&FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY)
cout << "Read only"<< endl;
if((df&FILE_ATTRIBUTE_HIDDEN) == FILE_ATTRIBUTE_HIDDEN)
cout << "Hidden"<< endl;
system("pause");
return EXIT_SUCCESS;
}
Может тупой вопрос, но все же сам ни как не могу понять, какая констанка соответсвует в атрибутах ярлыку?:confused:
Может тупой вопрос, но все же сам ни как не могу понять, какая констанка соответсвует в атрибутах ярлыку?:confused:
Ярлык это просто файл (anyfile) с расширением .lnk, просто он видной по особому интерпретируется, если пошаманить, то можно открыть черех hex и почитать.
Присоединяюсь, инфы по этому вопросу почти нет!
В теме http://forum.codenet.ru/showthread.php?t=42593 я вчера ответил, смотрите внимательнее
#include <iostream>
using std::cout;
using std::endl;
int main()
{
WIN32_FIND_DATA FindFileData;
HANDLE hf;
hf=FindFirstFile("c:\\*", &FindFileData);
if (hf!=INVALID_HANDLE_VALUE)
{
do
{
cout << FindFileData.cFileName << endl;
}
while (FindNextFile(hf,&FindFileData)!=0);
FindClose(hf);
}
system("pause");
return EXIT_SUCCESS;
}
В Dev-C++, собственно как и в MVS C++ 6.0, данный код прекрасно компилиться и работает!
Однако в MVS 2005 C++ и MVS 2008 C++ я получаю следующую ошибку
1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
C WCHAR все работает, но хотелось бы узнать в чем дело, и можно это как то обойти? Я так догадываюсь что это связано с Unicode...:confused:
Для переносимости кода в таком случае использовать макрос TEXT()
Для переносимости кода в таком случае использовать макрос TEXT()
Ясно, спасибо.
А если мне допустим надо?
{
<skip>
hf = FindFirstFile(path, &FindFileData);
<skip>
}
При юникоде будет использоватся wchar_t, а без юникода - char
При юникоде будет использоватся wchar_t, а без юникода - char
Ясно, спасибо, хотелось бы как то без wchar обойтись, но видать придется!=(
[QUOTE=Artem_3A]хотелось бы как то без wchar обойтись[/QUOTE]Интересно, чем же плох юникод?
Однако в MVS 2005 C++ и MVS 2008 C++ я получаю следующую ошибку
1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
C WCHAR все работает, но хотелось бы узнать в чем дело, и можно это как то обойти? Я так догадываюсь что это связано с Unicode...:confused:
На самом деле, если внимательно посмотреть, то, по крайней мере, в MS VS 2005 существует как функция FindFirstFileW, так и FinFirstFileA. Первая работает с юникодом, вторая - с ANSI. Чтобы упростить жизнь разработчикам специально создан макрос FindFirstFile. Если взглянуть на его описание в winbase.h:
[highlight=cpp]
#ifdef UNICODE
#define FindFirstFile FindFirstFileW
#else
#define FindFirstFile FindFirstFileA
#endif // !UNICODE
[/highlight]
то можно ясно увидеть, как решить вашу проблему. В коде лучше использовать макрос FindFirstFile, а уже при необходимости включать/отключать поддрежку юникода, например с помощью директивы undef. Аналогичная практика рапространена и для многих других функций, так что просто стоит быть любопытнее:)
Есть рекурсивная функция поиска файлов по диску:
{
WIN32_FIND_DATA fn;
HANDLE hf;
hf = FindFirstFiles(adress, &fn);
if(hf!=INVALID_HANDEL_VALUE)
{
do
{
if((df&FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
{
char* newAdress;
<skip>
.............
<skip>
searchFiles(newAdress);
}
}while(FindNextFiles(hf, &fn)!=0)
}
}
Если просмотреть адреса поиска то у меня лично получилось:
C:\\Acer\*
C:\\Acer\.\*
C:\\Acer\.\.\*
C:\\Acer\.\.\.\*
................................
C:\\Acer\.\.\.\.\.\.\.\.\.\.\.\.\.\.\*
Естественно ни каких папок "." и в поминет нет. newAdress преобразовывается правильно. "." возникают именно при поиске.
Может кто нить сталкивался?:confused: И может объяснить в чем дело?
Те если мы находимся в папке C:\test\ есть файл test.txt, то
C:\test\test.txt и .\test.txt - одно и тоже.
Так же есть ".." - ссылка на родительскую папку. ..\test.txt для пред идущего примера будет указывать на C:\test.txt
При поиске необходимо это учитывать. Например так
continue;
Естественно ни каких папок "." и в поминет нет. newAdress преобразовывается правильно. "." возникают именно при поиске.
Может кто нить сталкивался?:confused: И может объяснить в чем дело?
На самом деле папки "." и ".." остались от дос'а и обозначают родительский каталог и на саму себя те "с:\a\b\c\.." это то же что и "c:\a\b\"
так что просто делай проверку паки на имя "." и ".."
Теперь такой вопрос!
#include <iostream>
#include <windows.h>
#include "Kfile.h"
#include <vector>
using namespace std;
void searchFiles(const char* const adress, vector<CKfile> &list);
int _tmain(int argc, _TCHAR* argv[])
{
char* adress;
<skip>
vector<CKfile> list;
searchFiles(adress, list);
for(int i=0; i<list.size(); i++)
cout << list.getLocation()<< endl;
system("pause");
return EXIT_SUCCESS;
}
void searchFiles(const char* const adress, vector<CKfile> &list)
{
WIN32_FIND_DATAA fn;
HANDLE hf;
hf = FindFirstFileA(adress, &fn);
if(hf!=INVALID_HANDLE_VALUE)
{
do
{
try
{
if((fn.dwFileAttributes&FILE_ATTRIBUTE_HIDDEN) == FILE_ATTRIBUTE_HIDDEN)
throw 1;
if((fn.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY)
continue;
if((fn.dwFileAttributes&FILE_ATTRIBUTE_SYSTEM) == FILE_ATTRIBUTE_SYSTEM)
continue;
char* newAdress;
newAdress = new char[1000];
strncpy(newAdress, adress, 1000);
for(int i=0; i<strlen(newAdress); i++)
{
if((newAdress=='*') || (newAdress=='\0'))
{
newAdress='\0';
break;
}
}
if(strcmp(fn.cFileName, ".")==0)
continue;
if(strcmp(fn.cFileName, "..")==0)
continue;
strcat(newAdress,fn.cFileName);
for(int i=0; i<strlen(newAdress)+1; i++)
{
if(newAdress=='\0')
{
newAdress='\\';
newAdress[i+1]='*';
newAdress[i+2]='\0';
break;
}
}
searchFiles(newAdress, list);
delete newAdress;
}
catch(int e)
{
if((fn.dwFileAttributes&FILE_ATTRIBUTE_SYSTEM) != FILE_ATTRIBUTE_SYSTEM)
{
CKfile temp;
temp.setData(fn, adress);
list.push_back(temp);
}
}
}while(FindNextFileA(hf, &fn)!=0);
FindClose(hf);
}
}
temp.setData(fn, adress);
{
for(int i=0; i<260; i++)
{
name=temp.cFileName;
if(temp.cFileName=='\0')
break;
}
size = temp.nFileSizeHigh*(1+MAXDWORD) + temp.nFileSizeLow;
strncpy(location, path, 10000);
location[strlen(location)]='\0';
strncat(location, name, (10000-strlen(location)));
lastAccesTime = ConvertTime(temp.ftLastAccessTime);
createTime = ConvertTime(temp.ftCreationTime);
if((temp.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
dirFlag = true;
return;
}
В процессе вылетает:
This may be due to a corruption of the heap, and indicates a bug in Searchfiles.exe or any of the DLLs it has loaded.
The output window may have more diagnostic information
Причина кроется в этом участке кода:
temp.setData(fn, adress);
list.push_back(temp);
А именно в list.push_back(temp);
В чем именно я так и не могу понять!=(
Кто знает, подскажите где я туплю!
Artem_3A, смогу сказать точнее, когда выложишь полный код класса
WIN32_FIND_DATAA fn;
HANDLE hf;
hf = FindFirstFileA(adress, &fn);
if(hf!=INVALID_HANDLE_VALUE)
{
do
{
try
{
if(strcmp(fn.cFileName, ".")==0) continue; // <<<
if(strcmp(fn.cFileName, "..")==0) continue; // <<<
if((fn.dwFileAttributes&FILE_ATTRIBUTE_HIDDEN) == FILE_ATTRIBUTE_HIDDEN)
throw 1;
if((fn.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY)
continue;
if((fn.dwFileAttributes&FILE_ATTRIBUTE_SYSTEM) == FILE_ATTRIBUTE_SYSTEM)
continue;
char* newAdress;
newAdress = new char[1000];
strncpy(newAdress, adress, 1000);
for(int i=0; i<strlen(newAdress); i++)
{
if((newAdress=='*') || (newAdress=='\0'))
{
newAdress='\0';
break;
}
}
// if(strcmp(fn.cFileName, ".")==0) continue; // <<<
// if(strcmp(fn.cFileName, "..")==0) continue; // <<<
strcat(newAdress,fn.cFileName);
for(int i=0; i<strlen(newAdress)+1; i++)
{
if(newAdress=='\0')
{
newAdress='\\';
newAdress[i+1]='*';
newAdress[i+2]='\0';
break;
}
}
searchFiles(newAdress, list);
delete newAdress;
}
catch(int e)
{
if((fn.dwFileAttributes&FILE_ATTRIBUTE_SYSTEM) != FILE_ATTRIBUTE_SYSTEM)
{
CKfile temp;
temp.setData(fn, adress);
list.push_back(temp);
}
}
}while(FindNextFileA(hf, &fn)!=0);
FindClose(hf);
}
}
У меня теперь возникло два, так сказать, финальных вопроса!
Во первых, как получить дескриптор файла зная полный путь к нему, включая имя?
Во вторых, меня интересует как правильнее можно изменить права доступа к файлу?
И в третьих, что выполниться быстрее? Копирование "в ручную", пробегая циклом и копируя, или через функцию strcmp?(char*)