Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Доступ к памяти.  (Прочитано 25586 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Клерик
Гость
« : 08-11-2005 12:32 » 

Возможно ли в делфи - работать с памятью на прямую? Мне нужно из одной программы - передать сигнал или информацию в другую. Через винт будет медленно :nono:
И если вдруг это возможно пошлите меня (то есть дайте ссылку) туда, где я могу вдоволь начитаться по этому поводу. Ну если не влом может так - напрямую обьяснить. И дать пример - как.
Обьясню даже так: одна программа посылает сигнал другой программе и в определенном месте в памяти(которым можно пользоваться) оставляет пакет информации размером хоть в байт... Обе программы независимы друг от друга.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #1 : 08-11-2005 12:45 » 

Клерик , такое получится только через сообщения виндовс.

Детали не скажу, я - сишник Улыбаюсь
Записан

Oldy
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 08-11-2005 13:24 » 

Да возможно. Смотрите File Mapping в Win32 Developers Refernces или в MSDN.

Цитата
File mapping enables a process to treat the content of a file as if it were a block of memory in the process's address space. Therefore, instead of using file input and output (I/O) operations, the process can use simple pointer operations to examine and modify the contents of the file.

The Win32 API enables two or more processes to access the same file-mapping object. Each process receives a pointer to memory in its own address space. With this pointer, the process can read or modify the contents of the file.
« Последнее редактирование: 20-12-2007 18:31 от Алексей1153++ » Записан

С уважением, Oldy.
Клерик
Гость
« Ответ #3 : 09-11-2005 12:52 » 

Дело в том, что этот процесс будет проходить очень часто. То есть ОООчень часто. И мне нужно, что бы этот процесс - занимал как можно меньше действий - иначе все будет ой-ой-ой как долго.
Я могу этот процесс сделать через винт - в этом нет особых трудностей. - Но здесь в 40 раз теряется скорость только при чтении и записи + ещё действия на создание и сохранение файла, 40 умножить на 4 = 160 раз.. Еще плюс что-то не учел.... К примеру текстовую переменную... + куча действий. - которые включают в себя ещё действия. И еще: Когда идет работа с винтом - память тоже задействуется Улыбаюсь
Так вот - самый быстрый способ - я думаю напрямую через память... Но как я уже понял - это довольно-таки сложный для понимания процесс... Но другого выхода я не вижу.
Мне было бы достаточно хотябы ячейку в 1 байт. И для меня это уже 4 канала...
один бит указывает на то, что идет передача(в будущем пригодиться), второй на то, что передается(1/0) - и того четыре канала(транзита).
Я был бы очень признателен вам, если вы мне ткнули пальцем что читать...
Записан
Oldy
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 09-11-2005 13:41 » 

Работа с File Mapping  практически ни чем не отличается от работы с винтом, т.е. файл проэцируется в память образуя Shared Memory. Далее вся работа ведется через этот файл функциями ReadFile и WriteFile. Естественно, что размер файла не ограничивается одним байтом, а может достигать достаточно больших размеров. Работа с этой областью памяти может выполняться из разных процессов по семафору. Для изучения смотрите описание функций:

CreateFileMapping
FlushViewOfFile
MapViewOfFile
MapViewOfFileEx
OpenFileMapping
UnmapViewOfFile 

и ссылки, например:
http://delphiworld.narod.ru/base/file_mapping.html
http://www.rsdn.ru/Forum/Message/690607.htm

Ну и еще. Если все предлагаемое избыточно, то может быть будет проще работать (передавать информацию) через сокеты или named pipe ( http://www.delphimaster.ru/articles/named_pipes/ )
« Последнее редактирование: 09-11-2005 13:50 от Oldy » Записан

С уважением, Oldy.
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #5 : 09-11-2005 13:48 » 

Делай как посоветовал Oldy. По своей сути именованная проекция файла есть объект ядра. И винда сама берет на себя поддержку онного. Тебе только останется сказать ей, где бы ты хотел видеть данную проекцию. Механизм свопирования Винды почти полностью построен именно на проекции файла. Чтобы уведомлять чужие процессы, об изменении можно посылать сообшения в данные процессы или также использовать объекты ядра типа мутексы, сообшения.
Вот пример из книги Рихтера. Правда сделанный на С++;
Код:
BOOL FileReverse(PCTSTR pszPathname, PBOOL pfIsTextUnicode) {

   *pfIsTextUnicode = FALSE;  // Assume text is Unicode

   // Open the file for reading and writing.
   HANDLE hFile = CreateFile(pszPathname, GENERIC_WRITE | GENERIC_READ, 0,
      NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

   if (hFile == INVALID_HANDLE_VALUE) {
      chMB("File could not be opened.");
      return(FALSE);
   }

   // Get the size of the file (I assume the whole file can be mapped).
   DWORD dwFileSize = GetFileSize(hFile, NULL);

   // Create the file-mapping object. The file-mapping object is 1 character
   // bigger than the file size so that a zero character can be placed at the
   // end of the file to terminate the string (file). Because I don't yet know
   // if the file contains ANSI or Unicode characters, I assume worst case
   // and add the size of a WCHAR instead of CHAR.
   HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE,
      0, dwFileSize + sizeof(WCHAR), NULL);

   if (hFileMap == NULL) {
      chMB("File map could not be opened.");
      CloseHandle(hFile);
      return(FALSE);
   }

   // Get the address where the first byte of the file is mapped into memory.
   PVOID pvFile = MapViewOfFile(hFileMap, FILE_MAP_WRITE, 0, 0, 0);

   if (pvFile == NULL) {
      chMB("Could not map view of file.");
      CloseHandle(hFileMap);
      CloseHandle(hFile);
      return(FALSE);
   }

   // Does the buffer contain ANSI or Unicode?
   int iUnicodeTestFlags = -1;   // Try all tests
   *pfIsTextUnicode = IsTextUnicode(pvFile, dwFileSize, &iUnicodeTestFlags);

   if (!*pfIsTextUnicode) {
      // For all the file manipulations below, we explicitly use ANSI
      // functions because we are processing an ANSI file.

      // Put a zero character at the very end of the file.
      PSTR pchANSI = (PSTR) pvFile;
      pchANSI[dwFileSize / sizeof(CHAR)] = 0;

      // Reverse the contents of the file.
      _strrev(pchANSI);

      // Convert all "\n\r" combinations back to "\r\n" to
      // preserve the normal end-of-line sequence.
      pchANSI = strchr(pchANSI, '\n'); // Find first '\n'.

      while (pchANSI != NULL) {
         // We have found an occurrence....
         *pchANSI++ = '\r';   // Change '\n' to '\r'.
         *pchANSI++ = '\n';   // Change '\r' to '\n'.
         pchANSI = strchr(pchANSI, '\n'); // Find the next occurrence.
      }

   } else {
      // For all the file manipulations below, we explicitly use Unicode
      // functions because we are processing a Unicode file.

      // Put a zero character at the very end of the file.
      PWSTR pchUnicode = (PWSTR) pvFile;
      pchUnicode[dwFileSize / sizeof(WCHAR)] = 0;

      if ((iUnicodeTestFlags & IS_TEXT_UNICODE_SIGNATURE) != 0) {
         // If the first character is the Unicode BOM (byte-order-mark),
         // 0xFEFF, keep this character at the beginning of the file.
         pchUnicode++;
      }

      // Reverse the contents of the file.
      _wcsrev(pchUnicode);

      // Convert all "\n\r" combinations back to "\r\n" to
      // preserve the normal end-of-line sequence.
      pchUnicode = wcschr(pchUnicode, L'\n'); // Find first '\n'.

      while (pchUnicode != NULL) {
         // We have found an occurrence....
         *pchUnicode++ = L'\r';   // Change '\n' to '\r'.
         *pchUnicode++ = L'\n';   // Change '\r' to '\n'.
         pchUnicode = wcschr(pchUnicode, L'\n'); // Find the next occurrence.
      }
   }

   // Clean up everything before exiting.
   UnmapViewOfFile(pvFile);
   CloseHandle(hFileMap);

   // Remove trailing zero character added earlier.
   SetFilePointer(hFile, dwFileSize, NULL, FILE_BEGIN);
   SetEndOfFile(hFile);
   CloseHandle(hFile);

   return(TRUE);
}

В данной программе он меняет местами символы в файле.
« Последнее редактирование: 20-12-2007 18:32 от Алексей1153++ » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
zubr
Модератор

by
Offline Offline
Пол: Мужской

« Ответ #6 : 09-11-2005 22:41 » 

Вот пример с отображением файла в память на Delphi:
Код:
Программа создает дисковый файл, состоящий из 100000 случайных вещественных чисел (длину файла можно выбрать другой, если изменить значение редактора длина массива). Файл с именем test.dat создается путем отображения файла в память (кнопка память) и традиционным способом (кнопка Файл). В обоих случаях показывается время счета (процессор 400 МГц, память 64 Мбайт). Чем больше частота и память, тем больше будет разница во времени.

unit Unit1; 
interface 
uses 
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,   StdCtrls, ComCtrls, Spin; 
type 
  TFormI = class (TForm) 
    btMem: TButton; 
    btFile: TButton; 
    se: TSpinEdit; 
    Labell: TLabel; 
    pb: TProgressBar; 
    Label2: TLabel; 
    IbMem: TLabel; 
    IbFile: TLabel; 
    procedure btMemClick(Sender: TObject); 
    procedure btFileClick(Sender: TObject); 
  private 
    { Private declarations } 
  public 
    { Public declarations } 
  end; 

var 
  Form1: TForm1; 

implementation 
{$R *.DFM} 

procedure TForm1.btMemClick(Sender: TObject); 
  // Создание файла методом его отображения 
type PReal = ^Real; 
var 
  HFile, HMap: THandle; 
  AdrBase, AdrReal: PReal; 
  k: Integer; 
  FSize: Cardinal; 
  BegTime: TDateTime; 
begin 
  BegTime := Time; // Засекаем время пуска 
  // Готовим ProgressBar: 
  pb.Max := se.Value; 
  pb.Position := 0; 
  pb.Show; 
  FSize := se.Value * SizeOf(Real); // Длина файла HFile :=   FileCreate('test.dat'); // Создаем файл 
  if HFile = 0 then // Ошибка: возбуждаем исключение 
    raise Exception.Create('Ошибка создания файла'); 
  try 
    // Отображаем файл в память HMap := CreateFileMapping( 
    HFile, NIL, PAGE_READWRITE, 0, FSize, NIL); 
    if HMap = 0 then // Ошибка: возбуждаем исключение 
      raise Exception.Create('Ошибка отображения файла'); 
    try 
      // Создаем окно просмотра: 
      AdrBase := MapViewOfFile( 
      HMap, FILE_MAP_WRITE, О, О, FSize) ; 
      if AdrBase = NIL then // Ошибка: возбуждаем исключение 
        raise Exception.Create('Невозможно просмотреть файл'); 
      // Сохраняем начальный адрес для правильной ликвидации 
      // окна просмотра: 
      AdrReal := AdrBase; 
      for k := 1 to se.Value do 
        begin 
          AdrReal^ := Random; // Помещаем в файл новое число 
          // Перед наращиванием текущего адреса необходимо 
          // привести его к типу Integer или Cardinal: 
          AdrReal := Pointer(Integer(AdrReal) + SizeOf(Real)); 
          IbMem.Caption := IntToStr(k); 
          pb.Position := k; 
          Application.ProcessMessages; 
        end; 
       // Освобождаем окно просмотра: 
       UnmapViewOfFile(AdrBase) finally 
       // Освобождаем отображение CloseHandle(HMap) 
      end 
    finally 
     // Закрываем файл CloseHandle(HFile) 
    end; 
  // Сообщаем время счета pb.Hide; 
  IbMem.Caption := TimeToStr(Time-BegTime) 
end; 

procedure TFormI.btFileClick(Sender: TObject) ; 
  // Создание файла обычным методом var 
  F: File of Real; 
  k: Integer; 
  BegTime: TDateTime; 
  R: Real; // Буферная переменная для обращение к Write 
begin 
  BegTime := Time; // Засекаем начальное время счета // Готовим ProgressBar: 
  pb.Max := se.Value; 
  pb.Position := 0; 
  pb.Show; 
  // Создаем файл: 
  AssignFile(F, 'test.dat'); 
  Rewrite(F); 
  for k := 1 to se.Value do 
  begin 
    R := Random; // Параметрами обращения к Write 
    Write(F, R); // могут быть только переменные 
    IbFile.Caption := IntToStr(k); 
    pb.Position := k; 
    Application.ProcessMessages; 
  end; 
  CloseFile(F) ; 
  pb.Hide; 
  IbFile.Caption :=TimeToStr(Time-BegTime) 
end; 
end.
Пример взят с проекта Delphi Russian Knowledge Base
« Последнее редактирование: 20-12-2007 18:39 от Алексей1153++ » Записан
Клерик
Гость
« Ответ #7 : 10-11-2005 06:04 » 

Это написано на си++. Вопрос на засыпку: А можно ли с помощью этого способа(си++), отправлять сообщение, а примать на Делфи?
Типа: очень важно!!! (почти момент истины Улыбаюсь )
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #8 : 10-11-2005 06:41 » 

Клерик винда на всех программ одна Улыбаюсь
конечно можно
Записан

Клерик
Гость
« Ответ #9 : 11-11-2005 07:35 » 

А как послать сигнал? Есть ли способ полать сигнал из одной программы в другую?
Так я понял Oldy, можно в памяти выделить место под Файл, которым можно пользоваться(в своих корыстных целях). Но как послать сигнал из одной программы в другую? Сигнал, после которого 2я программа начнет читать то, что оставила ей первая?
Записан
Клерик
Гость
« Ответ #10 : 11-11-2005 07:55 » 

Кхе... кхе... У меня 98 винда, так что я не смогу восопользоваться сокетами Жаль
Записан
zubr
Модератор

by
Offline Offline
Пол: Мужской

« Ответ #11 : 11-11-2005 09:41 » 

Цитата
Кхе... кхе... У меня 98 винда, так что я не смогу восопользоваться сокетами
Во первых, нахрена тут сокеты. С помощью функции CreateFileMapping выделяется образ файла в памяти доступ к которому получается через глобальный идентификатор - строка символов. С помощью функции MapViewOfFile данные загоняются в память и читаются с памяти. Одна и другая программа (не важно на C или Delphi) создают образ памяти с помощью функции CreateFileMapping с одинаковым идентификатором. Можно также одной программой создать образ в памяти, а другой открыть хэндл образа памяти функцией OpenFileMapping. Функцией MapViewOfFile создается указатель на образ памяти в обоих программах, через который, к примеру, из одной программы передаются данные, а другая получает и наоборот.
Во вторых, это для меня что то новое, что в 98 винде отсуствуют сокеты, а как же тогда сетевые приложения в 98 винде выполняются?  Так больше нельзя...
Записан
Клерик
Гость
« Ответ #12 : 11-11-2005 10:07 » 

Я тут как бы не своими словами говорю на счет сокетов:
Цитата
Создание именованных каналов возможно только в NT-системах, подключение к созданному каналу возможно как в NT-системах, так и в Win9x. Кроме того, API работы с каналами в Win9x не поддерживает асинхронных операций ввода/вывода.
это от сюда: http://www.delphimaster.ru/articles/named_pipes/
Раз это можно сделать с помощью FileMapping, то это клево. Но меня всё-таки интересует еще один вопрос -
как подать сигнал? На этот вопрос может кто-нибудь ответить?
Еще раз алгоритм вкратце: Первая программа, посылает сигнал второй(предварительно оставив информацию в оперативке). Вторая мгновенно получает сигнал и считывать информацию. Вопрос: Как подать сигнал?
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #13 : 11-11-2005 13:56 » 

Есть несколько путей.
1. Банальное сообшение
Регистрируеш уникальное сообшение при помоши функции RegisterWindowMessage
Если получатель сообшения доподлино не известен. Посылаеш широковешательное сообшение
SendMessage(HWND_BROADCAST, WM_Твое_сообшение, 0, 0);
В своем втором приложении отлавливаеш сообшение и отрабатываеш его. Есть одно условие, приложение должно содержать окно.
2. В двух приложениях создаеш именованный объект ядра "Event" Функции CreateEvent, OpenEvent, ResetEvent,  SetEvent. И получаеш Хэндл "Event". Если будет только один приемник данных, то лучше создавать "Event" с автоподнятием флага.
В программе приемнике создаеш поток CreateThread, Если пишеш при помоши VCL Дельфи, то в ней сушествует класс потока. Приостанавливаеш поток при помоши функции WaitForSingleObject. Где объектом будет выступать созданный ранее "Event".
В посылаюшем приложении заполняеш расшариную память, отпускаеш флаг у "Event". В процессе приемнике запустится поток, который будет отрабатывать данные. После отработки, он обратно заснет, до следуюшей порции.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
zubr
Модератор

by
Offline Offline
Пол: Мужской

« Ответ #14 : 12-11-2005 07:23 » 

Цитата
Я тут как бы не своими словами говорю на счет сокетов:

Цитата
Создание именованных каналов возможно только в NT-системах, подключение к созданному каналу возможно как в NT-системах, так и в Win9x. Кроме того, API работы с каналами в Win9x не поддерживает асинхронных операций ввода/вывода.
это от сюда: http://www.delphimaster.ru/articles/named_pipes/
Именованные каналы - это не сокеты.
Можно рассылать широковещательные сообщения через мэйлслот, который работает как в WinNT так и в Win9X, единственное ограничение - размер передаваемого сообщения не должен превышать 424 байта для NT-систем. Правда, способы предложенные Finch более простые, имхо.
Записан
Oldy
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #15 : 12-11-2005 19:33 » 

Клерик, использование именованных каналов или сокетов для обмена данными между различными процессами я предложил как альтернативу, в том случае если механизм "File mapping" покажется через-чур избыточным или громоздким. Вообще, для решения подобных задач, возможны различные технологии. Все они изложены в MSDN: http://msdn.microsoft.com/library/en-us/ipc/base/interprocess_communications.asp 
Посмотрите пожалуйста, вдруг это поможет вам найти оптимальное решение вашей задачи.
« Последнее редактирование: 12-11-2005 20:02 от Oldy » Записан

С уважением, Oldy.
x77
Модератор

ro
Offline Offline
Пол: Мужской
меняю стакан шмали на обратный билет с Марса.


« Ответ #16 : 17-11-2005 12:04 » 

самый простой способ - использование функции SendMessage c параметром WM_COPYDATA. нет времени приводит код, я в командировке, но эта функция позволяет передавать всё, что угодно от строки до любой типизованной структуры.

варианты с маппингом, пайпами, и пр. - это полная засада, в данном случае - неоправданная Улыбаюсь
Записан

Oldy
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #17 : 17-11-2005 13:42 » 

Да нет там засады, все очень просто.
Пишущий процесс создает именованную область при помощи CreateFileMapping,  помещает туда данные и например сигнальный байт (по разряду на каждый читающий процесс). Обновление данных произведет только когда все флаги в сигнальном байте будут сброшены.
Читающие процессы, открывают именованную область при помощи OpenFileMapping. Считывают данные и флаги.  Если флаг для конкретного процесса установлен выполняем его сброс и обрабатываем данные. Флаг не установлен - отдыхаем. Проверяем по таймеру.
Или все не так?
Записан

С уважением, Oldy.
Клерик
Гость
« Ответ #18 : 17-11-2005 14:15 » 

Это не выгодно - по таймеру... Если между этими программами будут проходить сотни, или тысячи таких процессов, то сколько будет занимать времени? Можно ли послать сигнал мгновенно? Если да, то это выход - причем самый что не на есть лучший, тогда и инфо можно будет передавать с помощью сигналов. То есть вручную кодировать сигнал. Неужели нет выхода?
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #19 : 17-11-2005 14:30 » 

Клерик , WM_COPYDATA пользуй, правильно тебе 77 говорит Улыбаюсь
Код:
lResult = SendMessage(
  // returns LRESULT in lResult
  (HWND) hWndControl,      // handle to destination control
  (UINT) WM_COPYDATA,      // message ID
  (WPARAM) wParam,      // = (WPARAM) () wParam;
  (LPARAM) lParam      // = (LPARAM) () lParam;
  ); 

wParam - Handle to the window passing the data.

lParam - Pointer to a COPYDATASTRUCT structure that contains the data to be passed.

Return Value

If the receiving application processes this message, it should return TRUE; otherwise, it should return FALSE.


Remarks

The data being passed must not contain pointers or other references to objects not accessible
 to the application receiving the data.

While this message is being sent, the referenced data must not be changed by another thread
of the sending process.

The receiving application should consider the data read-only. The lParam parameter is valid only
 during the processing of the message. The receiving application should not free the memory
 referenced by lParam. If the receiving application must access the data after SendMessage returns,
 it must copy the data into a local buffer.
 


--------------------
typedef struct tagCOPYDATASTRUCT {
    ULONG_PTR dwData;
    DWORD cbData;
    PVOID lpData;
} COPYDATASTRUCT, *PCOPYDATASTRUCT;

dwData - Specifies data to be passed to the receiving application.
cbData - Specifies the size, in bytes, of the data pointed to by the lpData member.
lpData - Pointer to data to be passed to the receiving application. This member can be
           NULL.


Записан

Oldy
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #20 : 17-11-2005 14:47 » 

Ну не выгодно по таймеру, делайте в бесконечном цикле (не забудьте про Application.ProcessMessages), а вот будет-ли SendMessage для "N" читающих процессов быстрее - вопрос.
« Последнее редактирование: 17-11-2005 14:54 от Oldy » Записан

С уважением, Oldy.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #21 : 17-11-2005 14:51 » 

Oldy , зато будет асинхронно Улыбаюсь
Записан

Oldy
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #22 : 17-11-2005 15:07 » 

Алексей, возможно ты и прав, но по условиям тех. задания -
Цитата
Обьясню даже так: одна программа посылает сигнал другой программе и в определенном месте в памяти(которым можно пользоваться) оставляет пакет информации размером хоть в байт... Обе программы независимы друг от друга.
напрашивается FileMapping. Так-же предложены альтернативные (все на что способна Windows) способы обмена данными (см. ссылку на MSDN\interprocess communications), в том числе и WM_COPYDATA.
Клерику осталось выбрать наиболее подходящий вариант. Улыбаюсь
« Последнее редактирование: 17-11-2005 16:12 от Oldy » Записан

С уважением, Oldy.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines