Тема: Shared Memory
Пример показывает использование разделяемой памяти.
Запустите несколько копий этой программы.
Нажимайте на кнопки для выбора цвета окна.
Все окна запущенных копий этой программы будут окрашены в выбранный цвет.
Так как у каждого процесса своё адресное пространство, то мы не можем просто так читать одну и ту же область памяти из разных процессов.
Стоит здесь заметить, что речь именно о процессах, а не потоках — у потоков одного процесса и адресное пространство общее.
Так вот, если всё же такая возможность(стырить байт из соседского процесса) нужна, то можно использовать разделяемую память(Shared Memory).
Открыть или создать её можно с помощью функции OpenSharedMemory.
Существуют флаги для этой функции, их можно найти в модуле KolibriOS
// OpenSharedMemory open\access flags
SHM_OPEN = $00;
SHM_OPEN_ALWAYS = $04;
SHM_CREATE = $08;
SHM_READ = $00;
SHM_WRITE = $01;
Для закрытия области существует функция CloseSharedMemory.
В этом примере создаётся область разделяемой памяти.
В эту область записывается значение для цвета окна.
При перерисовке цвет читается из области разделяемой памяти и окно окрашивается в этот цвет.
Теперь можно запустить несколько копий программы, и все они будут читать одну и ту же область памяти, и, следовательно,
их окна будут окрашены в одинаковый цвет.
Для того чтобы после нажатия кнопки сразу же произошла перерисовка всех наших окон,
мы проверяем, совпадает ли имя процесса с именем нашего процесса.
Если совпадает, то активируем его окно, затем вызываем перерисовку своего окна(On_Redraw).
Исходный код:
program SharedMem;
uses
KolibriOS;
const
COLOR_BLUE = $000000FF;
COLOR_RED = $00FF0000;
COLOR_GREEN = $0000FF00;
COLOR_BLACK = $00000000;
COLOR_DEFAULT = $00F0F0F0;
BLACK_BUTTON = 1000;
BLUE_BUTTON = 2000;
GREEN_BUTTON = 3000;
RED_BUTTON = 4000;
MY_SHARED_MEMORY_SIZE = 100; // in bytes
MY_SHARED_MEMORY_NAME = 'MySharedMemoryForTest'; // maximum 31 symbol with terminating zero byte
type
PDwordArray = ^DwordArray;
DwordArray = array [0..0] of LongWord;
var
WndLeft, WndTop: LongInt;
WndWidth: LongWord = 300;
WndHeight: LongWord = 150;
MySharedMemory: Pointer;
function StrCmp(Str1, Str2: PAnsiChar): LongInt; stdcall;
asm
PUSH EDI
PUSH ESI
MOV ESI, Str1
MOV EDI, Str2
XOR EAX, EAX
MOV ECX, $FFFFFFFF
REPNE SCASB
MOV EDI, Str2
NOT ECX
REPE CMPSB
MOV AL, [ESI - 1]
SUB AL, [EDI - 1]
POP ESI
POP EDI
end;
procedure SetBackColor(Color: LongWord);
begin
// write Color value to shared memory
PDwordArray(MySharedMemory)[0] := Color;
end;
function GetBackColor: LongWord;
begin
// read Color value from shared memory
GetBackColor := PDwordArray(MySharedMemory)[0];
end;
procedure On_Redraw;
begin
BeginDraw;
DrawWindow(WndLeft, WndTop, WndWidth, WndHeight, 'Shared Memory', GetBackColor,
WS_SKINNED_FIXED + WS_CLIENT_COORDS + WS_CAPTION, CAPTION_MOVABLE);
DrawText(10, 10, 'Press button to select window color', $000000FF, $00FFFFFF, DT_ZSTRING + DT_CP866_8x16 + DT_FILL_OPAQUE, 0);
DrawButton(10, 30, 50, 30, COLOR_RED, 0, RED_BUTTON);
DrawButton(70, 30, 50, 30, COLOR_GREEN, 0, GREEN_BUTTON);
DrawButton(10, 70, 50, 30, COLOR_BLUE, 0, BLUE_BUTTON);
DrawButton(70, 70, 50, 30, COLOR_BLACK, 0, BLACK_BUTTON);
EndDraw;
end;
procedure RedrawAllMyWindows;
var
MyThreadInfo, ThreadInfo: TThreadInfo;
MaxSlot: LongWord;
Slot: LongWord;
begin
// get maximum slot number of threads and get ThreadInfo about _Current_ Thread
MaxSlot := GetThreadInfo($FFFFFFFF, MyThreadInfo);
// we go through all the thread slots and if Name = NameOfCurrentThread then Activate
for Slot := 1 to MaxSlot do
begin
GetThreadInfo(Slot, ThreadInfo);
if StrCmp(MyThreadInfo.Name, ThreadInfo.Name) = 0 then
ActivateWindow(Slot);
end;
// activate window of current thread
ActivateWindow(GetSlotByID(MyThreadInfo.Identifier));
On_Redraw;
end;
begin
HeapInit;
// try to create new shared memory, if it fails then
// just open existing memory
// else
// set back color by default
// NOTE: you can also use the SHM_OPEN_ALWAYS flag, which means "open existing or create new if not exist"
MySharedMemory := OpenSharedMemory(MY_SHARED_MEMORY_NAME, MY_SHARED_MEMORY_SIZE, SHM_CREATE + SHM_WRITE);
if MySharedMemory = nil then
MySharedMemory := OpenSharedMemory(MY_SHARED_MEMORY_NAME, MY_SHARED_MEMORY_SIZE, SHM_OPEN + SHM_WRITE)
else
SetBackColor(COLOR_DEFAULT);
with GetScreenSize do
begin
WndLeft := (Width - WndWidth) div 2;
WndTop := (Height - WndHeight) div 2;
end;
while True do
case WaitEvent of
REDRAW_EVENT:
On_Redraw;
KEY_EVENT:
GetKey;
BUTTON_EVENT:
begin
case GetButton.ID of
BLUE_BUTTON:
SetBackColor(COLOR_BLUE);
GREEN_BUTTON:
SetBackColor(COLOR_GREEN);
RED_BUTTON:
SetBackColor(COLOR_RED);
BLACK_BUTTON:
SetBackColor(COLOR_BLACK);
else
Break;
end;
RedrawAllMyWindows;
end;
end;
end.
Примеров использования можно придумать гораздо больше, чем просто чтение\запись цвета окна — это могут быть любые данные.
Если это интересно, то пишите в комментариях — добавлю другие примеры по Shared Memory.