Главная страница
Навигация по странице:

  • UnmapViewOfFile

  • Файлы данных, проецируемые в память

  • CreateFile

  • MapViewOfFile

  • Совместный доступ процессов к данным через

  • Обработка текстового и графического файлов

  • Работа с файлами больших размеров

  • Лабораторная работа № 8

  • Теоретические сведения Форматы данных

  • Запись информации в буфер обмена

  • GlobalAlloc

  • GlobalLock

  • SetClipboardData.

  • IsClipboardFormatAvailable

  • Пользовательский формат данных

  • Системное_программирование. Практикум для студентов специальностей 140 01 02 Информационные системы и технологии


    Скачать 1.66 Mb.
    НазваниеПрактикум для студентов специальностей 140 01 02 Информационные системы и технологии
    Дата02.09.2020
    Размер1.66 Mb.
    Формат файлаpdf
    Имя файлаСистемное_программирование.pdf
    ТипПрактикум
    #136562
    страница5 из 6
    1   2   3   4   5   6
    CreateFile позволяет процессу открывать файл, про- ецируемый в память другим процессом: hTxtFile =
    CreateFileW(L"kate.txt",GENERIC_READ,FILE_SHARE_READ,
    NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    55
    Функция CreateFileMapping создаёт уже другие, «проецирую- щие» внутренние структуры и связывает «сущность на диске» с
    «
    сущностью в адресном пространстве»:
    //Создание объекта ядра «проекция файла» hTxtMappingFile=CreateFileMappingA(hTxtFile,NULL,PAGE_READO
    NLY,0,0,"kate");
    По своему месту в последовательности действий она создаёт что-то наподобие «адресного пространства из файла». Этот объект поддерживает соответствие между содержимым файла и адресным пространством процесса, использующего этот файл (“kate” – имя объекта файлового отображения). Так как мы хотим отобразить весь файл, то четвертый и пятый параметры должны быть равны нулю.
    Функция MapViewOfFile делает "проекцию в память":
    //Проецирование данных файла на адресное пространство процесса hTxtMapFileStartAddr =
    MapViewOfFile(hTxtMappingFile,FILE_MAP_READ,0,0,0);
    Здесь hTxtMappingFile – дескриптор созданного объекта файло- вого отображения. Второй параметр определяет режим доступа к файлу. Значение, возвращаемое функцией MapViewOfFile, имеет тип "указатель". Если функция отработала успешно, то она вернет начальный адрес данных объекта файлового отображения.
    Функция OpenFileMapping используется для открытия объекта ядра «проекция файла»:
    //Открытие объекта ядра «проекция файла» hTxtMappingFile =
    OpenFileMappingA(FILE_MAP_READ,FALSE,"kate");
    Функция UnmapViewOfFile прекращает отображение в адресное пространство процесса того файла, который перед этим был отоб- ражен при помощи функции MapViewOfFile:
    UnmapViewOfFile(hTxtMapFileStartAddr);

    56
    Файлы данных, проецируемые в память
    Операционная система позволяет проецировать на адресное про- странство процесса и файл данных. Это очень удобно при манипу- ляциях с большими потоками данных.
    Для проецирования файла данных нужно выполнить три операции:
    1. Создать или открыть объект ядра "файл", идентифицирующий дисковый файл, который Вы хотите использовать как проецируе- мый в память. Для создания объекта “файл” используется функция
    CreateFile .
    2. С помощью функции CreateFileMapping создается объект ядра
    “проецируемый файл”, чтобы сообщить системе размер файла и способ доступа к нему. При этом используется описатель файла
    (handle), возвращенный функцией CreateFile. Теперь файл готов к проецированию.
    3. Производится отображение объекта “проецируемый файл” или его части на адресное пространство процесса. Для этого применяет- ся функция MapViewOfFile.
    Для открепления файла от адресного пространства процесса ис- пользуется функция UnmapViewOfFile, а для уничтожения объек- тов “файл” и “проецируемый файл” – функция CloseHandle.
    Общая схема работы с проецированными файлами такова:
    //Открытие объекта ядра «файл» hTxtFile = CreateFileW(L"kate.txt",…);
    //Создание объекта ядра «проекция файла» hTxtMappingFile=CreateFileMappingA(hTxtFile,…,"kate");
    //Проецирование данных файла на адресное пространство процесса hTxtMapFileStartAddr = MapViewOfFile(hTxtMappingFile,…);
    Совместный доступ процессов к данным через
    механизм проецирования
    Совместное использование данных в этом случае происходит так: два или более процесса проецируют в память представления одного и того же объекта "проекция файла", т.е. одни и те же стра-

    57 ницы физической памяти. В результате, когда один процесс запи- сывает данные в представление общего объекта "проекция файла", изменения немедленно отражаются на представлениях в других процессах. Но при этом все процессы должны использовать одина- ковое имя объекта "проекция файла".
    1.exe
    case WM_INITDIALOG: hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE,
    NULL, PAGE_READWRITE, 0, 1000, TEXT("katarina")); if(hFileMapping == NULL)
    MessageBox(hDlg,TEXT("Невозможно создать проекцию файла в Page-файле..."),TEXT("Error"),MB_ICONERROR); else
    { sharedBuffer = (LPTSTR) MapViewOfFile(hFileMapping,
    FILE_MAP_ALL_ACCESS,0,0,0);
    }
    2.exe
    hFileMapping =
    OpenFileMapping(FILE_MAP_READ,FALSE,TEXT("katarina")); if(hFileMapping == NULL)
    MessageBox(hDlg,TEXT("Невозможно создать проекцию файла..."),TEXT("Error"),MB_ICONERROR); else
    { sharedBuffer = (LPTSTR) MapViewOfFile(hFileMapping,
    FILE_MAP_READ,0,0,0);
    DWORD dwError = GetLastError();
    }
    Обработка текстового и графического файлов
    двумя процессами
    При обработке текстовых и графических файлов небольшого размера можно спроецировать весь файл в память. Затем произве- сти его обработку. По завершении обработки файла необходимо прекратить отображение на адресное пространство представления объекта «проекция файла» и закрыть описатель всех объектов ядра.

    58
    Текстовый файл:
    //Открытие объекта ядра «проекция файла» hTxtMappingFile =
    OpenFileMappingA(FILE_MAP_READ,FALSE,"kate"); if(hTxtMappingFile != NULL)
    {
    //Проецирование данных файла на адресное пространство процесса hTxtMapFileStartAddr = MapViewOfFile(hTxtMappingFile,
    FILE_MAP_READ,0,0,0);
    //Вывод данных из текстового файла в эдит
    SetDlgItemTextA(hDlg,
    IDC_EDIT_TEXT,(char*)hTxtMapFileStartAddr);
    //Отключение файла данных от адресного пространства процесса
    UnmapViewOfFile(hTxtMapFileStartAddr);
    //Закрытие объекта «проекция файла»
    CloseHandle(hTxtMappingFile);
    Графический файл:
    //Открытие объекта ядра «файл» hBmpFile =
    CreateFileA("LOVE.bmp",GENERIC_READ,FILE_SHARE_READ,NULL,
    OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
    GetClientRect(GetDlgItem(hDlg,IDC_BMPFRAME),&rect);
    //Создание объекта ядра «проекция файла» hBmpMappingFile = CreateFileMappingA( hBmpFile,
    //описатель файла
    NULL,
    //аттрибуты защиты объекта ядра
    PAGE_READONLY,
    //атрибут защиты, присваиваемый
    // страницам физической памяти
    0,0,
    //максимальный размер файла в
    // байтах (0 -- размер меньше
    4Гб)
    "BmpFile");
    //имя объекта ядра
    //Проецирование данных файла на адресное пространство процесса hBmpMapFileAddr = MapViewOfFile( hBmpMappingFile,
    // описатель объекта «проекция файла»
    FILE_MAP_READ,
    // вид доступа к данным
    0,0,
    // смещение в файле до байта файла данных,
    //который нужно считать в представлении первым

    59 0);
    // сколько байтов файла данных должно быть
    //спроецировано на адресное пространство
    //(0 -- от смещения и до конца файла)
    BITMAPFILEHEADER *bFileHeader=
    (BITMAPFILEHEADER*)hBmpMapFileAddr;
    BITMAPINFO *bInfo=(BITMAPINFO*)((char*)hBmpMapFileAddr+14); hdc=GetDC(GetDlgItem(hDlg,IDC_BMPFRAME)); hBmpFile=CreateDIBitmap(hdc,&(bInfo->bmiHeader),
    CBM_INIT,(char*)hBmpMapFileAddr+bFileHeader->bfOffBits, bInfo,DIB_PAL_COLORS); hMemDC=CreateCompatibleDC(hdc);
    SelectObject(hMemDC,hBmpFile);
    StretchBlt(hdc,0,0,rect.right,rect.bottom,hMemDC,
    0,0,bInfo->bmiHeader.biWidth,bInfo->bmiHeader.biHeight,
    SRCCOPY);
    ReleaseDC(GetDlgItem(hDlg,IDC_BMPFRAME),hdc);
    DeleteDC(hMemDC);
    DeleteObject(hBmpFile); return (INT_PTR)TRUE;
    Работа с файлами больших размеров
    //*****Работа с большим файлом******************* if (LOWORD(wParam) == IDC_HUGE)
    {
    // начальные границы представлений всегда начинаются no
    // адресам, кратным гранулярности выделения памяти
    SYSTEM_INFO sinf;
    GetSystemInfo(&sinf);
    /
    / открываем файл данных
    HANDLE hBigFile = CreateFileA("ТЕСТ.txt", GENERIC_READ,
    FILE_SHARE_READ, NULL,OPEN_EXISTING,
    FILE_FLAG_SEQUENTIAL_SCAN,NULL);
    // создаем объект проекции файла
    HANDLE hHugeFileMapping = CreateFileMapping(hBigFile,
    NULL,PAGE_READONLY, 0, 0, NULL);
    DWORD dwFileSizeHigh;
    __int64 dwFileSize = GetFileSize(hBigFile,
    &dwFileSizeHigh); dwFileSize += (((__int64) dwFileSizeHigh) << 32);
    // доступ к описателю объекта файл нам больше не нужен

    60
    CloseHandle(hBigFile);
    __int64 dwFileOffset = 0;
    DWORD dwNumOfOs = 0; char symbol[100] = "";
    DWORD dwPrBarRange = dwFileSize/sinf.dwAllocationGranularity; while (dwFileSize > 0)
    {
    // определяем, сколько байтов надо спроецировать
    DWORD dwBytesInBlock = sinf.dwAllocationGranularity; if (dwFileSize < sinf.dwAllocationGranularity) dwBytesInBlock = (DWORD)dwFileSize;
    //Проецирование данных файла на адресное
    //
    пространство процесса
    PBYTE hHugeMapFileStartAddr = (PBYTE)
    MapViewOfFile(hHugeFileMapping,FILE_MAP_READ,
    (DWORD) (dwFileOffse t >> 32), // начальный байт
    (DWORD) (dwFileOffset & 0xFFFFFFFF), // в файле dwBytesInBlock); // число проецируемых байтов
    SetDlgItemTextA(hDlg, IDC_EDIT_HUGEFILE, (char*) hHugeMapFileStartAddr);
    SendMessage(GetDlgItem(hDlg, IDC_PROGRESS),
    (UINT)PBM_STEPIT, 0, 0);
    // прекращаем проецирование представления,
    // чтобы в адресном пространстве
    // не образовалось несколько представлений одного файла
    UnmapViewOfFile(hHugeMapFileStartAddr);
    // переходим к следующей группе байтов в файле dwFileOffset += dwBytesInBlock; dwFileSize -= dwBytesInBlock;
    }
    CloseHandle(hHugeFileMapping); return (INT_PTR)TRUE;
    }

    61
    Пример взаимодействия процессов через Page файл.
    1.exe
    case WM_INITDIALOG: hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE,
    NULL, PAGE_READWRITE, 0, 1000, TEXT("katarina")); if(hFileMapping == NULL)
    MessageBox(hDlg,TEXT("Невозможно создать проекцию файла в
    Page- файле..."),TEXT("Error"),MB_ICONERROR); else
    { sharedBuffer = (LPTSTR) MapViewOfFile(hFileMapping,
    FILE_MAP_ALL_ACCESS,0,0,0);
    }
    2.exe
    hFileMapping =
    OpenFileMapping(FILE_MAP_READ,FALSE,TEXT("katarina")); if(hFileMapping == NULL)
    MessageBox(hDlg,TEXT("Невозможно создать проекцию файла..."),TEXT("Error"),MB_ICONERROR); else
    { sharedBuffer = (LPTSTR) MapViewOfFile(hFileMapping,
    FILE_MAP_READ,0,0,0);
    DWORD dwError = GetLastError();
    }

    62
    Лабораторная работа № 8
    БУФЕР ОБМЕНА
    Цель работы: изучить основы работы с объектом – буфер обмена.
    Изучаемые вопросы
    1. Форматы данных.
    2.
    Запись информации в буфер обмена.
    3.
    Чтение информации из буфера обмена.
    4.
    Передача информации пользовательского типа *.
    Постановка задачи
    Создать приложение, состоящее из двух процессов:
    − первый процесс записывает текстовый файл и растровый рисунок в буфер обмена;
    − второй процесс считывает информацию из буфера обмена и отображает в окне процесса.
    Текстовый файл и файл с растровым рисунком взять из преды- дущих лабораторных работ.
    Теоретические сведения
    Форматы данных
    Ниже в таблице 8.1 представлены типы данных и соответствую- щие им форматы данных.

    63
    Таблица 8.1
    Форматы данных
    Формат
    Тип данных
    CF_BITMAP
    Растр (bitmap) в чистом виде
    CF_DIB
    Растр (bitmap) с заголовком BITMAPINFO
    CF_DIF
    Универсальный формат обмена (Data
    Interchange Format)
    CF_DSPBITMAP
    Пользовательское растровое изображение
    CF_DSPENHMETAFILE
    Пользовательский расширенный метафайл
    CF_DSPMETAFILEPICT
    Пользовательский метафайл
    CF_DSPTEXT
    Пользовательский текст
    СF_ENHMETAFILE
    Расширенный метафайл
    CF_METAFILEPICT
    Метафайл в стиле METAFILEPICT
    CF_OEMTEXT
    Текст в кодировке OEM
    CF_OWNERDISPLAY
    Пользовательский формат данных
    CF_PALETTE
    Цветовая палитра
    CF_PENDATA
    Формат для данных, связанных с элек- тронным пером
    CF_RIFF
    Файл ресурсов (Resource Interchange File
    Format)
    CF_SYLK
    Символическая ссылка
    CF_TEXT
    Текст
    CF_TIFF
    Графика в формате TIFF
    CF_WAVE
    Звук в формате WAVE
    CF_UNICODETEXT
    Текст в кодировке UNICODE
    Запись информации в буфер обмена
    Общая процедура записи данных в буфер обмена состоит из сле- дующих шагов:

    64 a)
    Прежде чем поместить в буфер обмена какую-либо инфор- мацию, ваша программа (далее просто окно) должна его от- крыть, используя функцию OpenClipboard: if (OpenClipboard(hDlg))
    //открываем буфер обмена b)
    После того, как программа открыла буфер обмена, она должна его очистить от предыдущего содержания, для чего следует вызвать функцию EmptyClipboard. if (EmptyClipboard())
    //очищение буфера обмена c)
    Выделяем блок глобальной памяти, достаточный для того, чтобы хранить в нем данные, которые необходимо поме- стить в буфер обмена.
    HGLOBAL hGl; hGl = GlobalAlloc(GMEM_DDESHARE, strlen(buffer2));
    //заказываем блок памяти
    Функция GlobalAlloc() выделяет память и возвращает дескрип- тор выделенного блока.
    Для получения указателя на область памяти, выделенную при помощи GlobalAlloc(), следует использовать функцию GlobalLock():
    LPVOID lpstr = (char *) GlobalLock(hGl);
    //блокируем его
    Функция GlobalLock() фиксирует в памяти объект (блок), де- скриптор которого передается в параметре hGl. Зафиксированный объект не перемещается в памяти и не выгружается. Функция
    GlobalLock
    () возвращает адрес начала блока в случае успешного завершения или NULL при возникновении ошибки.
    После получения указателя на глобальный блок памяти необхо- димо скопировать в этот блок данные, которые Вы хотите поме- стить в буфер обмена. memcpy(lpstr, buffer2, strlen(buffer2));
    //записываем данные

    65
    Когда копирование завершится, блок памяти можно разблокиро- вать, вызвав функцию GlobalUnlock():
    GlobalUnlock(hGl);
    //разблокировать блок
    Теперь мы имеем полное право помещать в него свои данные в различных форматах, используя функцию SetClipboardData.
    SetClipboardData(CF_TEXT, hGl);
    //помещаем данные в буфер обмена
    Чтение информации из буфера обмена
    Для чтения данных из буфера обмена используется следующая последовательность шагов: a)
    Необходимо открыть буфер обмена; if (OpenClipboard(hDlg))
    Чтобы получить доступ к данным, хранящимся в буфере обмена, последний должен быть открыт. b)
    Чтобы извлечь информацию из буфера обмена, окно должно вызвать функцию GetClipboardData.
    HANDLE hData = GetClipboardData(CF_TEXT);
    //извлекаем информацию из буфера
    Данная функция в качестве параметра принимает формат буфера обмена, для того чтобы извлечь данные в этом формате.
    Если в буфер обмена данные поместила другая программа, вы мо- жете проверить доступные форматы данных перед их непосредствен- ным извлечением, используя функцию IsClipboardFormatAvailable. if (IsClipboardFormatAvailable(CF_TEXT))
    //проверка на доступные файлы c)
    Копируем данные из буфера обмена d)
    Закрываем буфер обмена
    CloseClipboard();

    66
    Пользовательский формат данных
    Возможно ситуация, когда приложению необходимо поместить данные в буфер обмена, а стандартные форматы для этого не под- ходят. Выходом из такой ситуации является возможность регистра- ции собственного формата данных.
    Для того чтобы зарегистрировать новый формат буфера обмена, используется функция RegisterClipboardFormat. В качестве пара- метра этой функции следует передать указатель на текстовую стро- ку, закрытую двоичным нулем и содержащую имя регистрируемого нестандартного формата данных для буфера обмена.
    Функция возвращает нулевое значение при ошибке или иденти- фикатор зарегистрированного формата данных, который можно ис- пользовать аналогично идентификаторам стандартных форматов в качестве параметра функции SetClipboardData.
    Два различных приложения или две копии одного приложения могут зарегистрировать формат с одним и тем же именем, при этом функция RegisterClipboardFormat вернет один и тот же идентифика- тор формата. Поэтому два приложения всегда смогут "договорить- ся", если они знают имя нестандартного формата данных.
    В приведенном ниже коде регистрируется новый формат дан- ных, представленный структурой MyClipboardData, а затем запол- ненная структура помещается в буфер обмена: if (LOWORD(wParam) == IDC_BUTTON1)
    {
    UINT format =
    RegisterClipboardFormat(L"MyClipboardData");
    //регистрируем наш формат данных
    MyClipboardData MCD;
    SendDlgItemMessageA(hDlg, IDC_EDIT2, WM_GETTEXT, 50,
    (LPARAM)MCD.InfData); if (OpenClipboard(hDlg))
    //для работы с буфером обмена его нужно открыть
    { if (EmptyClipboard())
    {
    HGLOBAL hGl;
    EmptyClipboard();
    //очищаем буфер hGl = GlobalAlloc(GMEM_DDESHARE, sizeof(MyClipboardData)); //выделим память

    67
    MyClipboardData * buffer = (MyClipboardData *)
    GlobalLock(hGl); //запишем данные в память
    *buffer = MCD;
    //поместим данные в буфер обмена
    GlobalUnlock(hGl);
    SetClipboardData(format, hGl);
    //помещаем данные в буфер обмена
    CloseClipboard();
    //после работы с буфером, его нужно закрыть
    } return (INT_PTR)TRUE;
    }}
    В приведенном ниже коде извлекается из буфера обмена данные, представленные структурой MyClipboardData: case IDC_BUTTON1:
    { if (OpenClipboard(hDlg))
    {
    UINT format =
    RegisterClipboardFormat(L"MyClipboardData");
    //вызываем второй раз, чтобы просто получить формат if (IsClipboardFormatAvailable(format))
    {
    MyClipboardData MCD;
    //извлекаем данные из буфера
    HANDLE hData = GetClipboardData(format);
    MyClipboardData* buffer = (MyClipboardData *)
    GlobalLock(hData);
    //заполняем нашу структуру полученными данными
    MCD = *buffer;
    GlobalUnlock(hData)
    SetDlgItemTextA(hDlg, IDC_EDIT1, MCD.In fData);
    CloseClipboard();
    }
    }
    CloseClipboard(); return TRUE;
    }

    68
    1   2   3   4   5   6


    написать администратору сайта