FileMap.pas
上传用户:psxgmh
上传日期:2013-04-08
资源大小:15112k
文件大小:8k
源码类别:

Delphi/CppBuilder

开发平台:

Delphi

  1. unit FileMap;
  2. interface
  3. uses
  4.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  5.   StdCtrls, Dialogs;
  6. type
  7.   //定义TFileMap类
  8.   TFileMap = class(TComponent)
  9.   private
  10.     FMapHandle: THandle; //内存映射文件句柄
  11.     FMutexHandle: THandle; //互斥句柄
  12.     FMapName: string; //内存映射对象
  13.     FSynchMessage: string; //同步信息
  14.     FMapStrings: TStringList; //存储映射文件信息
  15.     FSize: DWord; //映射文件大小
  16.     FMessageID: DWord; //注册的消息号
  17.     FMapPointer: PChar; //映射文件的数据区指针
  18.     FLocked: Boolean; //锁定
  19.     FIsMapOpen: Boolean; //文件是否打开
  20.     FExistsAlready: Boolean; //表示是否已经建立文件映射了
  21.     FReading: Boolean; //正在读取内存映射文件数据
  22.     FAutoSynch: Boolean; //是否自动同步
  23.     FOnChange: TNotifyEvent; //当内存数据区内容改变时
  24.     FFormHandle: Hwnd; //存储本窗口的窗口句柄
  25.     FPNewWndHandler: Pointer; //
  26.     FPOldWndHandler: Pointer; //
  27.     procedure SetMapName(Value: string);
  28.     procedure SetMapStrings(Value: TStringList);
  29.     procedure SetSize(Value: DWord);
  30.     procedure SetAutoSynch(Value: Boolean);
  31.     procedure EnterCriticalSection;
  32.     procedure LeaveCriticalSection;
  33.     procedure MapStringsChange(Sender: TObject);
  34.     procedure NewWndProc(var FMessage: TMessage);
  35.   public
  36.     constructor Create(AOwner: TComponent); override;
  37.     destructor Destroy; override;
  38.     procedure OpenMap;
  39.     procedure CloseMap;
  40.     procedure ReadMap;
  41.     procedure WriteMap;
  42.     property ExistsAlready: Boolean read FExistsAlready;
  43.     property IsMapOpen: Boolean read FIsMapOpen;
  44.   published
  45.     property MaxSize: DWord read FSize write SetSize;
  46.     property AutoSynchronize: Boolean read FAutoSynch write SetAutoSynch;
  47.     property MapName: string read FMapName write SetMapName;
  48.     property MapStrings: TStringList read FMapStrings write SetMapStrings;
  49.     property OnChange: TNotifyEvent read FOnChange write FOnChange;
  50.   end;
  51. implementation
  52. //构造函数
  53. constructor TFileMap.Create(AOwner: TComponent);
  54. begin
  55.   inherited Create(AOwner);
  56.   FAutoSynch := True;
  57.   FSize := 4096;
  58.   FReading := False;
  59.   FMapStrings := TStringList.Create;
  60.   FMapStrings.OnChange := MapStringsChange;
  61.   FMapName := 'Unique & Common name';
  62.   FSynchMessage := FMapName + 'Synch-Now';
  63.   if AOwner is TForm then
  64.   begin
  65.     FFormHandle := (AOwner as TForm).Handle;
  66.     //得到窗口处理过程的地址
  67.     FPOldWndHandler := Ptr(GetWindowLong(FFormHandle, GWL_WNDPROC));
  68.     FPNewWndHandler := MakeObjectInstance(NewWndProc);
  69.     if FPNewWndHandler = nil then
  70.       raise Exception.Create('超出资源');
  71.     //设置窗口处理过程新的地址
  72.     SetWindowLong(FFormHandle, GWL_WNDPROC, Longint(FPNewWndHandler));
  73.   end
  74.   else raise Exception.Create('组件的所有者应该是TForm');
  75. end;
  76. //析构函数
  77. destructor TFileMap.Destroy;
  78. begin
  79.   CloseMap;
  80.   //还原Windows处理过程地址
  81.   SetWindowLong(FFormHandle, GWL_WNDPROC, Longint(FPOldWndHandler));
  82.   if FPNewWndHandler <> nil then
  83.     FreeObjectInstance(FPNewWndHandler);
  84.   //释放对象
  85.   FMapStrings.Free;
  86.   FMapStrings := nil;
  87.   inherited destroy;
  88. end;
  89. //打开文件映射,并映射到进程空间
  90. procedure TFileMap.OpenMap;
  91. var
  92.   TempMessage: array[0..255] of Char;
  93. begin
  94.   if (FMapHandle = 0) and (FMapPointer = nil) then
  95.   begin
  96.     FExistsAlready := False;
  97.       // 创建文件映射对象
  98.     FMapHandle := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, FSize, PChar(FMapName));
  99.     if (FMapHandle = INVALID_HANDLE_VALUE) or (FMapHandle = 0) then
  100.       raise Exception.Create('创建文件映射对象失败!')
  101.     else
  102.     begin
  103.    //判断是否已经建立文件映射了
  104.       if (FMapHandle <> 0) and (GetLastError = ERROR_ALREADY_EXISTS) then
  105.         FExistsAlready := True; //如果已建立的话,就设它为True
  106.     //映射文件的视图到进程的地址空间
  107.       FMapPointer := MapViewOfFile(FMapHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
  108.       if FMapPointer = nil then
  109.         raise Exception.Create('映射文件的视图到进程的地址空间失败')
  110.       else
  111.       begin
  112.         StrPCopy(TempMessage, FSynchMessage);
  113.       //在Windows中注册消息常量
  114.         FMessageID := RegisterWindowMessage(TempMessage);
  115.         if FMessageID = 0 then
  116.           raise Exception.Create('注册消息失败')
  117.       end
  118.     end;
  119.       //创建互斥对象,在写文件映射空间时,用到它,以保持数据同步
  120.     FMutexHandle := Windows.CreateMutex(nil, False, PChar(FMapName + '.Mtx'));
  121.     if FMutexHandle = 0 then
  122.       raise Exception.Create('创建互斥对象失败');
  123.     FIsMapOpen := True;
  124.     if FExistsAlready then //判断内存文件映射是否已打开
  125.       ReadMap
  126.     else
  127.       WriteMap;
  128.   end;
  129. end;
  130. //解除文件视图和内存映射空间的关系,并关闭文件映射
  131. procedure TFileMap.CloseMap;
  132. begin
  133.   if FIsMapOpen then
  134.   begin
  135.     //释放互斥对象
  136.     if FMutexHandle <> 0 then
  137.     begin
  138.       CloseHandle(FMutexHandle);
  139.       FMutexHandle := 0;
  140.     end;
  141.     //关闭内存对象
  142.     if FMapPointer <> nil then
  143.     begin
  144.    //解除文件视图和内存映射空间的关系
  145.       UnMapViewOfFile(FMapPointer);
  146.       FMapPointer := nil;
  147.     end;
  148.     if FMapHandle <> 0 then
  149.     begin
  150.     //并关闭文件映射
  151.       CloseHandle(FMapHandle);
  152.       FMapHandle := 0;
  153.     end;
  154.     FIsMapOpen := False;
  155.   end;
  156. end;
  157. //读取内存文件映射内容
  158. procedure TFileMap.ReadMap;
  159. begin
  160.   FReading := True;
  161.   if (FMapPointer <> nil) then FMapStrings.SetText(FMapPointer);
  162.   FReading := False;
  163. end;
  164. //向内存映射文件里写
  165. procedure TFileMap.WriteMap;
  166. var
  167.   StringsPointer: PChar;
  168.   HandleCounter: integer;
  169.   SendToHandle: HWnd;
  170. begin
  171.   if FMapPointer <> nil then
  172.   begin
  173.     StringsPointer := FMapStrings.GetText;
  174.     //进入互斥状态,防止其他线程进入同步区域代码
  175.     EnterCriticalSection;
  176.     if StrLen(StringsPointer) + 1 <= FSize
  177.       then System.Move(StringsPointer^, FMapPointer^, StrLen(StringsPointer) + 1)
  178.     else
  179.       raise Exception.Create('写字符串失败,字符串太大!');
  180.     //离开互斥状态
  181.     LeaveCriticalSection;
  182.     //广播消息,表示内存映射文件内容已修改
  183.     SendMessage(HWND_BROADCAST, FMessageID, FFormHandle, 0);
  184.     //释放StringsPointer
  185.     StrDispose(StringsPointer);
  186.   end;
  187. end;
  188. //当MapStrins值改变时
  189. procedure TFileMap.MapStringsChange(Sender: TObject);
  190. begin
  191.   if FReading and Assigned(FOnChange) then
  192.     FOnChange(Self)
  193.   else if (not FReading) and FIsMapOpen and FAutoSynch then
  194.     WriteMap;
  195. end;
  196. //设置MapName属性值
  197. procedure TFileMap.SetMapName(Value: string);
  198. begin
  199.   if (FMapName <> Value) and (FMapHandle = 0) and (Length(Value) < 246) then
  200.   begin
  201.     FMapName := Value;
  202.     FSynchMessage := FMapName + 'Synch-Now';
  203.   end;
  204. end;
  205. //设置MapStrings属性值
  206. procedure TFileMap.SetMapStrings(Value: TStringList);
  207. begin
  208.   if Value.Text <> FMapStrings.Text then
  209.   begin
  210.     if Length(Value.Text) <= FSize then
  211.       FMapStrings.Assign(Value)
  212.     else
  213.       raise Exception.Create('写入值太大');
  214.   end;
  215. end;
  216. //设置内存文件大小
  217. procedure TFileMap.SetSize(Value: DWord);
  218. var
  219.   StringsPointer: PChar;
  220. begin
  221.   if (FSize <> Value) and (FMapHandle = 0) then
  222.   begin
  223.     StringsPointer := FMapStrings.GetText;
  224.     if (Value < StrLen(StringsPointer) + 1) then
  225.       FSize := StrLen(StringsPointer) + 1
  226.     else FSize := Value;
  227.     if FSize < 32 then FSize := 32;
  228.     StrDispose(StringsPointer);
  229.   end;
  230. end;
  231. //设置是否同步
  232. procedure TFileMap.SetAutoSynch(Value: Boolean);
  233. begin
  234.   if FAutoSynch <> Value then
  235.   begin
  236.     FAutoSynch := Value;
  237.     if FAutoSynch and FIsMapOpen then WriteMap;
  238.   end;
  239. end;
  240. //进入互斥,使得被同步的代码不能被别的线程访问
  241. procedure TFileMap.EnterCriticalSection;
  242. begin
  243.   if (FMutexHandle <> 0) and not FLocked then
  244.   begin
  245.     FLocked := (WaitForSingleObject(FMutexHandle, INFINITE) = WAIT_OBJECT_0);
  246.   end;
  247. end;
  248. //解除互斥关系,可以进入保护的同步代码区
  249. procedure TFileMap.LeaveCriticalSection;
  250. begin
  251.   if (FMutexHandle <> 0) and FLocked then
  252.   begin
  253.     ReleaseMutex(FMutexHandle);
  254.     FLocked := False;
  255.   end;
  256. end;
  257. //消息捕获过程
  258. procedure TFileMap.NewWndProc(var FMessage: TMessage);
  259. begin
  260.   with FMessage do
  261.   begin
  262.     if FIsMapOpen then //内存文件打开
  263.    {如果消息是FMessageID,且WParam不是FFormHandle,就调用ReadMap,
  264.     去读取内存映射文件的内容,表示内存映射文件的内容已变}
  265.       if (Msg = FMessageID) and (WParam <> FFormHandle) then
  266.         ReadMap;
  267.     Result := CallWindowProc(FPOldWndHandler, FFormHandle, Msg, wParam, lParam);
  268.   end;
  269. end;
  270. end.