484 / 397 / 68
Регистрация: 14.02.2014
Сообщений: 1,930
1
.NET 4.x

WinApi и работа с альтернативными файловыми потоками

15.07.2016, 17:40. Показов 3406. Ответов 8
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго времени суток.
Пытаюсь разобраться с работой альтернативных файловых потоков в NTFS.
Как я понял из C# с ними можно работать только через WinApi (CreateFile, WriteFile и ReadFile).
Соответственно написал для этих функцию обёртку.
С Create и Write проблем нет. Возникли проблемы с чтением. Функция отрабатывает, возвращает True, но данные не получает. При этом данные в альтернативный файловый поток точно записываются, проверял из командной строки.

Функции класса обёртки WinApi*:
Кликните здесь для просмотра всего текста

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
        // Импорт функции CreateFile
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr CreateFile(
            string lpFileName,
            uint dwDesiredAccess,
            uint dwShareMode,
            IntPtr lpSecurityAttributes,
            byte dwCreationDisposition,
            short dwFlagsAndAttributes,
            IntPtr hTemplateFile);
 
        // Импорт функции ReadFile
        [DllImport("kernel32", SetLastError = true)]
        private static extern unsafe bool ReadFile(IntPtr _hFile, void* _lpBuffer, uint _nNumberOfBytesToRead, uint* _lpNumberOfBytesRead, uint _lpOverlapped);
 
        // Импорт функции WriteFile
        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToWrite, ref int N, int N1);
 
        // Импорт функции CloseHandle
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool CloseHandle(IntPtr hObject);
 
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern int GetLastError();
 
  // Конструктор класса
        // s - путь к файлу или устройство
        public LDrive(string s, byte Metod)
        {
            pl = CreateFile(s, GENERIC_READ | GENERIC_WRITE, 0, IntPtr.Zero, Metod, 0x80, IntPtr.Zero);
        }
 
        // Закрыть хендл
        public bool close()
        {
            return CloseHandle(this.pl);
        }
 
        // Записать
        public bool Write(byte[] buf, uint NofBytesToWrite)
        {
            return WriteFile(this.pl, buf, NofBytesToWrite, ref N, 0);
        }
 
        // Получить код ошибки
        public int Error()
        {
            return GetLastError();
        }
 
        // Прочитать
        public bool Read(ref byte[] buf, uint NofBytesToRead)
        {
            unsafe
            {
                fixed (void* pvPacket = buf)
                {
                    uint readingbytes = 0;
                    bool isOk = ReadFile(this.pl, pvPacket, (uint)buf.Length, &readingbytes, 0);
                    return isOk;
                }
            }          
        }


Код, которым пытаюсь прочитать данные:
Кликните здесь для просмотра всего текста

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
        static byte Create = 2;
        static byte Open = 3;
        static string MyStream = "MyStream";
        static LDrive drive = new LDrive(@"H:\1.txt:" + MyStream, Open);
 
        static void Main(string[] args)
        {
            if ((int)drive.pl == -1)
                Console.WriteLine(drive.Error());
            //byte[] outData = Encoding.Unicode.GetBytes("Это скрытый текст");
           // if (!drive.Write(outData, (uint)outData.Length))
               // Console.WriteLine(drive.Error());
            byte[] buf = new byte[512];
            if (!drive.Read(ref buf, 512))
                Console.WriteLine(drive.Error());
            drive.close();
            Console.ReadKey();
        }


* чтобы не изобретать велосипед, взял сигнатуры, найденные в сети. Вроде ошибок в них не вижу. Создание хэндла и запись в файл работают точно.

С pInvoke вообще и WinApi в частности дел почти не имел, мог где-то глупо накосячить. Прошу помощи более опытных коллег.
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
15.07.2016, 17:40
Ответы с готовыми решениями:

Работа с потоками
У меня приложение через заданный интервал (в таймере) отправляет запрос на сайт и парсит ответ, при...

Работа с потоками
Ребята, помогите. На C# программирую недавно, про потоки слышу впервые. Подскажите как это можно...

работа с потоками
При работе с методом выдает ошибку: "Недопустимая операция в нескольких потоках: попытка доступа к...

Работа с потоками
Добрые люди дайте готовый кусочек кода по работе с потоками Требования такие Запустив энное...

8
Администратор
Эксперт .NET
16561 / 13006 / 5114
Регистрация: 17.03.2014
Сообщений: 26,532
Записей в блоге: 1
15.07.2016, 19:41 2
Лучший ответ Сообщение было отмечено aquaMakc как решение

Решение

aquaMakc, можно проще. С минимумом p/invoke, без указателей и unsafe кода. Достаточно вызвать только CreateFile, получить от неё дескриптор, обернуть вокруг него FileStream и дальше использовать .NET классы:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
static void Main(string[] args)
{
    using (var fstream = FileStreamHelper.OpenWithStream(@"d:\11111", "MyStream", FileMode.Create, FileAccess.Write))
    using (var writer = new StreamWriter(fstream, Encoding.Unicode))
    {
        writer.Write("Это скрытый текст");
    }
    using (var fstream = FileStreamHelper.OpenWithStream(@"d:\11111", "MyStream", FileMode.Open, FileAccess.Read))
    using (var reader = new StreamReader(fstream, Encoding.Unicode))
    {
        Console.WriteLine(reader.ReadToEnd());
    }
    Console.ReadKey();
}
FileStreamHelper
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
using System.IO;
using Microsoft.Win32.SafeHandles;
 
public static class FileStreamHelper
{
    public static FileStream OpenWithStream(string fileName, string streamName, FileMode mode, FileAccess access)
    {
        return OpenWithStream(fileName, streamName, mode, access, FileShare.None);
    }
    
    public static FileStream OpenWithStream(string fileName, string streamName, FileMode mode, FileAccess access, FileShare share)
    {
        uint desiredAccess = (access & FileAccess.Read) == FileAccess.Read ? GenericRead : 0;
        desiredAccess |= (access & FileAccess.Write) == FileAccess.Write ? GenericWrite : 0;
        
        SafeFileHandle fileHandle = CreateFile(
            fileName + ":" + streamName,
            desiredAccess,
            share,
            IntPtr.Zero,
            mode,
            FileAttributes.Normal,
            IntPtr.Zero
        );
        if (fileHandle.IsInvalid)
        {
            int win32error = Marshal.GetLastWin32Error();
            Marshal.ThrowExceptionForHR(win32error);
            switch(win32error)
            {
                case 2:
                    throw new FileNotFoundException("Failed to open file with specified stream", fileName + ":" + streamName);
                default:
                    throw new IOException("Failed to open file with specified stream");
            }
        }
        return new FileStream(fileHandle, access);
    }
 
    const uint GenericRead = 0x80000000;
    const uint GenericWrite = 0x40000000;
 
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern SafeFileHandle CreateFile(
        string fileName,
        uint desiredAccess,
        [MarshalAs(UnmanagedType.U4)] FileShare share,
        IntPtr lpSecurityAttributes,
        [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
        [MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes,
        IntPtr hTemplateFile
    );
}
3
484 / 397 / 68
Регистрация: 14.02.2014
Сообщений: 1,930
15.07.2016, 23:03  [ТС] 3
OwenGlendower, грац, выглядит рабоче. Но только в понедельник смогу до IDE добраться.
0
Master of Orion
Эксперт .NET
6098 / 4954 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
15.07.2016, 23:52 4
OwenGlendower, 2 вопроса по коду
1) зачем после ThrowExceptionForHR делать свитч, он же вроде недостижим?
2) Насколько я помню, код ошибки и HResult это разные коды (возвращаемые GetHRForLastWin32Error и GetLastWin32Error соответственно)
0
Администратор
Эксперт .NET
16561 / 13006 / 5114
Регистрация: 17.03.2014
Сообщений: 26,532
Записей в блоге: 1
16.07.2016, 01:01 5
Psilon, 1) ThrowExceptionForHR не всегда генерирует исключение, поэтому switch достижим. Я тестировал это на ситуации с несуществующим файлом.

2) ты прав. Это разные вещи. Я пытался съэкономить себе работу по генерации исключений, но допустил ошибку. Собственно из-за путаницы между кодом и hresult-ом метод ThrowExceptionForHR не генерировал исключения. Можно переписать генерацию исключений так:
C#
1
2
3
4
5
6
7
8
if (fileHandle.IsInvalid)
{
    int win32error = Marshal.GetLastWin32Error();
    int hresult = (win32error & 0x0000FFFF) | unchecked((int)0x80070000);
    Exception ex = Marshal.GetExceptionForHR(hresult);
    if (ex != null) throw ex;
    throw new System.ComponentModel.Win32Exception(win32error, string.Format("Failed to open file with specified stream: '{0}'", path));
}
0
Master of Orion
Эксперт .NET
6098 / 4954 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
16.07.2016, 01:43 6
OwenGlendower, а зачем это делать руками, если я правильно помню, то marshal это и делает?..
C#
1
2
3
4
5
6
7
8
9
10
        [System.Security.SecurityCritical]  // auto-generated_required 
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        public static int GetHRForLastWin32Error()
        {
            int dwLastError = GetLastWin32Error(); 
            if ((dwLastError & 0x80000000) == 0x80000000)
                return dwLastError; 
            else 
                return (dwLastError & 0x0000FFFF) | unchecked((int)0x80070000);
        }
Соответственно:
C#
1
2
3
int hresult = Marshal.GetHRForLastWin32Error();
Exception ex = Marshal.GetExceptionForHR(hresult);
throw ex ?? new Win32Exception(hresult, string.Format("Failed to open file with specified stream: '{0}'", path));
Добавлено через 2 минуты
Возможно Marshal не возвращал именно потому что не было проверки на 0x80000000, тогда он неправильно складывался с 0x80070000 и получалась неверная маска, по которой он не мог вернуть исключение.
0
Администратор
Эксперт .NET
16561 / 13006 / 5114
Регистрация: 17.03.2014
Сообщений: 26,532
Записей в блоге: 1
16.07.2016, 08:14 7
Psilon, делаю руками по WinAPI привычке получать код ошибки один раз и работать с ним. Нам здесь нужно два кода - HResult для GetHRForLastWin32Error и Win32Error для класса Win32Exception.
0
Master of Orion
Эксперт .NET
6098 / 4954 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
16.07.2016, 09:05 8
OwenGlendower, и все же я думаю, что проблема именно в этом
Например если код ошибки 0x92345678 то по твоему алгоритму получается 0x80075678, а по майкровостовскому 0x92345678.
0
484 / 397 / 68
Регистрация: 14.02.2014
Сообщений: 1,930
18.07.2016, 09:04  [ТС] 9
OwenGlendower, ) работает. Можно начинать встраивать в своё ПО вирусы *шутка*
0
18.07.2016, 09:04
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
18.07.2016, 09:04
Помогаю со студенческими работами здесь

Работа с потоками
Доброе время суток подскажите пож как реализовать : "Шарики. Координаты заданного количества...

Работа с потоками
Здравствуйте. Проблема заключается в следующем, в параллельном потоке мне нужно чтобы label1...

Работа с потоками...
Понимаю, что тема проезжена и не раз, однако спрошу:-[: Есть консольное приложение, оно занимается...

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


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2023, CyberForum.ru