home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / Iczelion / mmf.txt < prev    next >
Text File  |  2000-05-25  |  25KB  |  571 lines

  1.               Advanced Win32 Assembly Lessons
  2.             Memory Mapped Files 
  3.                Sharing Data Between Instances
  4.             
  5.  
  6.     Memory management under Windows Operative system has greatly changed
  7. since the days when DOS was the king. Both Win16 and DOS share a common
  8. address space for all applications making them very prone to crashing. Under
  9. Win95/98/NT every application has its own private address space which cannot
  10. be seen by any other process. This address space is 4 GB long and each
  11. application access it using a 32 bit pointer. Supposedly, this configuration
  12. makes the operative system more stable, and although I am generalizing,
  13. there are meaningful differences between Win95/98 and WinNT, which we could
  14. better appreciate by analyzing the memory layout of any particular Win32
  15. process.
  16.     
  17. Win95/98 Virtual Address Space Memory Layout:
  18. ---------------------------------------------
  19.  
  20.  
  21. From 0x00000000 to 0x00000FFF. These first 4KB is used to maintain
  22. compatibility with Win16 and DOS programs. It is unaccessible to any process
  23. raising an exception if a read/write attempt occurs.
  24.  
  25. From 0x00001000 to 0x003FFFFF. This 4 MB area is also used for compatibility
  26. issues but is accessible by any process. Off course, it is not recommended
  27. to play with this area.
  28.  
  29. From 0x00400000 to 0x7FFFFFFF. This 2 GB partition is the private address
  30. space assigned to every running process. Each win32 application receives an
  31. unshared, private 2 GB chunk of virtual address space (don't forget to
  32. subtract the bottom 4MB describe above). At this point, you should not
  33. confuse yourself, windows does not assign 2 GB of your precious memory to
  34. every running thread; this is "virtual" address space, not physical memory.
  35. Win95/98 (Win98 from now on) judiciously commits and maps physical storage
  36. the every process virtual address space according to its growing necessities.
  37.  
  38. From 0x80000000 to 0xBFFFFFFF. This partition is 1 GB long and is shared
  39. among all Win32 process. Here, Win98 maps all memory allocations, dynamic
  40. link libraries (KERNEL32.DLL, USER32.DLL, GDI32.DLL, ADVAPI32.DLL), memory
  41. mapped files (MMF from now on) and Win16 applications. It is useful to say
  42. that DLL's are always mapped to the same fixed virtual addresses.
  43.  
  44. From 0xC0000000 to 0xFFFFFFFF. This partition is also 1 GB long; here is
  45. where the operative system code resides. Unfortunately, this area is also
  46. accessible to all win32 processes and that is why Win98 is more prone to
  47. crashing than WinNT.
  48.  
  49.     Now that you know how this wonderful 4 GB world is constrained by
  50. invisible barriers, is time to discuss about the subject of this
  51. tutorial.
  52.     
  53.     Managing memory under win98 can be achieved by three different
  54. strategies: virtual memory allocation, memory mapped files and heaps. Each
  55. method is best suited for certain tasks. MMF is used to access large buffers
  56. of data in memory, mainly files like EXE, DLL (which explains the name of
  57. this method), to be more accurate, both the user and the operative system
  58. can map files in memory, for instance, the operative system loads files like
  59. kernel32.dll using this feature.
  60. MMF has been fairly well described years before the release of Win95,
  61. nevertheless, we make a shy use of what is in fact, one of the most powerful
  62. features of Win32 OS for programmers and crackers.
  63. Although Win98 supports MMF to certain extent, it is WinNT which unleashes
  64. the whole power of it. Making use of MMF on any of these OS requires the
  65. knowledge of only a few API calls. Let's start by listing them:
  66.  
  67. CreateFile
  68. CreateFileMapping
  69. MapViewOfFile - MapViewOfFileEx
  70. OpenFileMapping
  71. UnmapViewOfFile
  72. FlushViewOfFile
  73. CloseHandle
  74.  
  75.     Some of these API functions feature a unicode version too. Instead
  76. of copy&Paste the information from the Win32 Programmer's Reference, is
  77. better to discuss each API on the context of a real life example. You can
  78. check the whole code in one piece in the MMF sharing data example file
  79. (included with this tutorial).
  80.     
  81.  
  82. .- CreateFile: 
  83.  
  84.     There is no real life code for this one because I didn't use it in
  85. the example. Check the parameters in your SDK API reference. This function
  86. is used to create or open already existing files (and other devices). It
  87. returns a handle that identifies the file object (hFile). CreateFileMapping
  88. requires as one of its parameters, the handle of the file that is going to
  89. be mapped, this handle is returned by CreateFile function, however, in all
  90. cases we don't need to map a file, but simply to commit an area of memory to
  91. store or share data, in which case the programmer doesn't need to call this
  92. function to create the mapping object. Both CreateFileMapping and CreateFile,
  93. return a handle. These handles are not the same and each one identifies a
  94. diferent object, thereby you should provide code to close them individually
  95. (by calling CloseHandle function) whenever the program does not need the
  96. mapping object anymore.
  97.     
  98. .- CreateFileMapping:
  99.  
  100.         call CreateFileMappingA, INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, \
  101.         0, 1000h, offset szObjectName
  102.  
  103.         mov     hFileMapping, eax
  104.  
  105. CreateFileMapping function simply creates a mapping object and returns a
  106. handle (HFileMapping) to it. It doesn't reserve or commits any memory.
  107. The first parameter is the Handle of the file that is going to be mapped
  108. returned by CreateFile function. In our case, INVALID_HANDLE_VALUE is used
  109. as the first parameter, so a mapping object not related to any particular
  110. file is created. A side-effect could occur due to this fact; if Createfile
  111. function fails, it returns 0xFFFFFFFF and not NULL as other API's, so the
  112. first parameter to CreatefileMapping in that instance would be 0xFFFFFFFF
  113. which is valid and all the mapping object manipulations would succeed,
  114. however, the application wouldn't be handling the intended file but a
  115. different mapping object. The second parameter is a pointer to a security
  116. attributes structure. It can be NULL (our case) to use the default security
  117. attributes. The third parameter specifies the protection characteristics for
  118. the mapping object, this value should be consistent with the protection
  119. attributes used in the CreateFile function. One particular parameter is
  120. important to discuss in detail, PAGE_WRITECOPY. Win98 is not asgood as WinNT to maintain consistency when a memory area is shared between
  121. several applications and to prevent any disaster there is PAGE_WRITECOPY.
  122. When specified, a single mapping object is created (as in any other case),
  123. but if a write attempt is carried out by a different instance of the program
  124. that created the mapping object, the system commits additional memory from
  125. the paging file and creates a private additional copy of these pages, finally
  126. mapping it to the virtual address space of the new program's instance. So
  127. each program modifies its own copy of the original file. Normally, to
  128. preserve resources, the same memory area is mapped to all virtual address
  129. spaces that access the same mapping object, so whatever one process changes
  130. in the mapping object would be reflected to all of the other instances of the
  131. program that are accessing the same data. The next two parameters are the
  132. maximum size the mapping object can take in memory. It serves to assure the
  133. system has enough resources to map the desiredobject. This value is expressed as a 64 bit value (two dwords) because the
  134. system is capable of handling files of up to 1 quintillion bytes (18 EB),
  135. however, only a 4 GB piece of such enormous file can be mapped at one time,
  136. but in practice, you will be mapping much more less than this and if you wish
  137. to handle large files, the system can map partial sections of a large file to
  138. preserve your scarce resources. You can set both of these parameters as NULL
  139. if you don't think the file will grow in size after the mapping object is
  140. manipulated, off course, if you think your file will grow in size (because
  141. you are a Win32 Virus programmer and your virus is going to end up attached
  142. to the host file), then you should consider a maximum space that is equal to:
  143. OriginalFileSize+VirusSize+SomeWorkSpace. In our example, I've used 1000h
  144. (4096 bytes) as the size of the mapping object. The MMF sharing example
  145. application only gathers a few bytes from the Edit control window and even
  146. so, I've reserved 4KB of your precious memory to map the object. Don't be mad
  147. at me, there's a reasonable explanation for this. In x86 machines, memory
  148. must be allocated in small chunks of 4096 bytes (this is known as the page
  149. size); you cannot allocate less than this and if you do, the system will
  150. round up your requested size to an even multiple of the page size. In the
  151. same way, memory areas must start and end at an even multiple of the
  152. allocation granularity of the system (64 KB for x86).
  153. The last parameter in CreatefileMapping is the mapping object's name. You
  154. can use NULL in most cases (not in our example) because the mapping object
  155. would be manipulated by a single instance of the program that created it, at
  156. a time. In our case, a name is assigned to the object as we intend to
  157. manipulate it from different instances of the same program.
  158.  
  159.     Well, at this point you could be overwhelmed by all this technical
  160. issues, but now you can figure out the advantages of File-mapping;
  161. manipulating a file in memory using pointers instead of slow ReadFile,
  162. WriteFile and SetFilePointer operations, sharing large streams of data
  163. between several instances of the same program or various different programs,
  164. etc.
  165.     
  166. .- MapViewOfFile. 
  167.  
  168.         call MapViewOfFile, hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 1000h
  169.  
  170.         mov lpMappedObject, eax
  171.  
  172.     Now that the mapping object was created, you need to reserve and
  173. commit physical storage for your object. MapViewOfFile, takes some physical
  174. storage from the paging file and commits it, finally it maps the committed
  175. area to your program virtual space. This API takes 5 parameters; the first
  176. of it is the handle to the mapping object returned by CreateFileMapping
  177. function. This handle could also be obtained using OpenFileMapping function
  178. which is a key function in our MMF Sharing Data Example. The second parameter
  179. is related to the protection attributes of the committed memory area. This
  180. parameter has to be consistent (there's a complex relation here, so you
  181. better read it in the Win32 Programmer's Reference) with the protection
  182. parameter in CreateFileMapping function executed before. I used
  183. FILE_MAP_ALL_ACCESS to have unrestricted access to the file mapping object.
  184. The next two parameters are there because as I said before, you can map a
  185. selected piece of a big file (called VIEW). These two parameters refer to a
  186. 64 bit pointer to the first byte in the file to be mapped. If you specify
  187. NULL in both parameters, the whole file is mapped. If the system does not
  188. have enough resources to map the file the function returns NULL. Win98 can
  189. not map an small view of a file if the total file size is bigger than its
  190. available resources; Win98 requires always to commit the whole file size
  191. from the paging file. WinNT can map an small view of a big file even if
  192. this file cannot be mapped in a whole, due to resources limitations. If
  193. you specify NULL in both parameters, the system attempts to map the file
  194. from its beginning. The last parameter refers to the number of bytes in the
  195. file you wish to map. This is a 32 bit value, so is obvious a file larger
  196. than 4 GB cannot be mapped. If you specify NULL in this parameter, the
  197. system attempts to map the whole file at once.
  198.     
  199. .- UnmapViewOfFile. 
  200.  
  201.         call UnmapViewOfFile, lpMappedObject
  202.  
  203.  
  204.     When you no longer need the file mapping object, this function is
  205. used to cleanup the committed physical storage in your virtual address space.
  206. In other words, it frees your virtual address space of the file mapping
  207. object. Calling MapViewOfFile again, will simply map another location of
  208. your address space but it will not unmap the previous committed area. It
  209. takes only one parameter that is nothing more than the base address of the
  210. file mapping object as returned by MapViewOfFile function. One important
  211. feature of MMF is that all modifications in the mapping object are not
  212. immediately reflected in the paging file or in the file in the disk. In fact,
  213. much of these changes are stored in the system cache and later written in
  214. large chunks. When you call UnmapViewOfFile, everything that could be
  215. temporarily stored in the cache would be immediately written to the backed
  216. file whether it be the paging file or a file in one of your storage units.
  217. One important variation of the MapViewOfFile function is MapViewOfFileEx. It
  218. takes one additional parameter if compared with MapViewOfFile. This parameter
  219. is of the LPVOID type and indicates to the function the memory location in
  220. the process virtual address where the first byte of the mapping object should
  221. be located. This function is very important if you want to share a file
  222. mapping object between several instances of the same program and need that
  223. all instances "to see" the object at the same base address. Win98 usually
  224. maps several views of the same file using a common memory location in the
  225. virtual address space, but this is not always true.
  226. In other to clean the cache and update the backed file without calling
  227. UnmapViewOfFile, Win32 provides another function called FlushViewOfFile.
  228.     
  229. .- FlushViewOfFile. It ensures all data in the system cache is stored in the
  230. file.
  231.  
  232. .- CloseHandle. 
  233.  
  234.         call CloseHandle, hFileMapping
  235.  
  236.     You must never forget to close any object opened during the process
  237. of creating MMF. Two objects, the file mapping object and the file object
  238. must be closed using this function. In our example, we didn't use any file
  239. object, only a file mapping object, that is why we closed only the mapping
  240. object.
  241.     
  242.     
  243.     Although you have been reading for quiet a while, very few has been
  244. said about the bottom line of this tutorial, in other words, we still have
  245. to explain how MMF are used to share data between applications. Let me write
  246. again here, the CreateFileMapping function layout:
  247.  
  248. call CreateFileMappingA, INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, \
  249.         0, 1000h, offset szObjectName
  250.  
  251. As you can see, the last parameter is the file mapping object name. This
  252. parameter could be NULL if only one running instance needs to access the
  253. mapping object, but if you want to share it among several applications or
  254. instances, you'll have to pass here a pointer to a string zero terminated
  255. name for your object. This name can be passed later to another function,
  256. OpenFileMapping which returns a process relative handle to the original
  257. handle of the file mapping object. This handle can be used to create another
  258. view of the same file from the point of view of another instance or process
  259. passing it to MapViewOfFile function.
  260.  
  261. .- OpenFileMapping. 
  262.  
  263.         call OpenFileMappingA, FILE_MAP_ALL_ACCESS, TRUE, \
  264.         offset szObjectName
  265.         mov     hFileMapping, eax
  266.         call MapViewOfFile, hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 1000h
  267.         mov     lpMappedObject, eax
  268.  
  269.  
  270.  
  271. It opens an already created mapping object. If the object does not exist in
  272. the first place, the function returns NULL. If the object exists, this is
  273. what happens:
  274.  
  275. The system maps the physical storage where the original object was located to
  276. the address space of the instance requesting access to the mapping object.
  277. Fortunately, the system does not commit additional physical storage to map
  278. the new view of the file; it just maps the same physical storage previously
  279. committed to both address spaces. The result is obvious, if any instance
  280. modifies the object in its virtual address, the same modification occurs in
  281. the physical storage and therefore in all other virtual spaces of any other
  282. instances where that physical storage was mapped too.
  283. Take a look on how I got a process relative handle to the original file
  284. mapping object. OpenFileMapping takes three parameters. The first one
  285. refers to the access attributes, I used a combination of READ and WRITE
  286. access (FILE_MAP_ALL_ACCESS). The next parameter indicates if the handle
  287. returned by the function can be inherited. It means that a child process can
  288. inherit not only the same mapping object, but even the same original handle
  289. to it. When you use OpenFileMapping, what you get is a handle to the original
  290. handle. In this last case you can use the original handle directly in the
  291. child process. Of course, you have to device a method to transfer the
  292. original handle from the parent process to its child because although the
  293. handle is inheritable, the child process has no way to get the original
  294. handle by itself. Another fundamental aspect of OpenFileMapping is that it
  295. cannot get a handle of a non-previously existing object, so it serves (as in
  296. our example) not only to get a handle to the shareable file mapping object
  297. but also to figure out if another instance has already created the object.
  298. There are several other ways to share data using MMF, inheritance (partially
  299. discussed) is a feature that permits the original handle of an object to be
  300. passed to a child process. the second parameter to CreateFileMapping is a
  301. structure called SECURITY_ATTRIBUTES that is 12 bytes long and once set it
  302. permits the handle obtained with this function to be inheritable. You can
  303. also share a mapping object (Win98 only) by directly accessing a mapped
  304. object in another's application address space. You can easily access the
  305. address space of another process using certain functions, but I do not
  306. recommend it in the case of MMF because if the application that created the
  307. mapping object decides to decommit the physical address, then, the second
  308. application would rise an access violation. The last possibility is to call
  309. CreateFileMapping using SEC_RESERVE parameter. This will reserve address
  310. space for the mapping object without committing physical storage to it. You
  311. can later commit physical storage to the mapping object space using
  312. VirtualAlloc. This memory space is shareable between processes because it is
  313. located inside a mapping object boundaries.
  314.     
  315.     Finally, if you want to experiment a little, run the Sharing Data
  316. Example included in the same package with this tutorial (mmf1.exe). Type some
  317. data in the Edit control and press the button "Store Data". A mapping object
  318. will be created to store the data you typed using the paging file. Now open
  319. another instance of the same program running mmf1.exe again (without closing
  320. the previous instance) and press the "Retrieve Data" button. The second
  321. instance will retrieve the data you typed in the Edit control of the first
  322. instance from the mapping object.
  323.     
  324.     I guess this is all for now. Here you have a copy of the original
  325. MMF Sharing Data Example application:
  326.     
  327.  
  328. ;--------------------------------------------------------------------------
  329. ;                     mmf1.asm (compile using tasm32)
  330. ;--------------------------------------------------------------------------
  331. .386
  332. .model flat,STDCALL
  333.  
  334. include W32.INC ; Some useful structures definitions. Available in
  335.                 ; Barry Kauler's Book companion disk.
  336.  
  337. UNICODE = 0     ; ANSI character set defined
  338.  
  339. extrn CreateFileMappingA:PROC
  340. extrn MapViewOfFile:PROC
  341. extrn UnmapViewOfFile:PROC
  342. extrn OpenFileMappingA:PROC
  343. extrn GetDlgItemTextA:PROC
  344. extrn OpenFileMappingA:PROC
  345.  
  346. .data
  347.  
  348. IDD_DIALOG1  equ                   101
  349. IDI_ICON1    equ                   102
  350. IDC_BUTTON1  equ                   1000
  351. IDC_BUTTON2  equ                   1001
  352. IDC_EDIT1    equ                   1002
  353. IDC_STATIC   equ                   -1
  354.  
  355. rect        RECT <?>
  356. ps              PAINTSTRUCT <?>
  357. hInstance    dd ?
  358. hwnd        dd ?
  359. height          dd ?
  360. width           dd ?
  361. s_height        dd ?
  362. s_width         dd ?
  363. szObjectName    db 'mmfobject',0
  364. szRetData       db 1000h dup (0)
  365. szDataSize      dd ?
  366. szNewInst       db 'Open a new instance now!',0
  367. .code
  368.  
  369. start:
  370.     
  371.     
  372.         call GetModuleHandle, 0
  373.         mov hInstance, eax
  374.  
  375.         call DialogBoxParam, hInstance, IDD_DIALOG1, 0, offset DlgProc, 0
  376.         call ExitProcess, 0
  377.  
  378.         DlgProc PROC hWP:HWND, message:UINT, wparam:WPARAM, lparam:LPARAM
  379.     
  380.         LOCAL hDW:HWND
  381.         LOCAL hwndChild:HWND
  382.         LOCAL hFile:HANDLE
  383.         LOCAL hFileMapping:HANDLE
  384.         LOCAL lpMappedObject:POINTER
  385.  
  386.         .IF message==WM_PAINT
  387.  
  388.         call      paint
  389.  
  390.         .ELSEIF message==WM_COMMAND
  391.  
  392.         call      command
  393.  
  394.         .ELSEIF message==WM_INITDIALOG
  395.  
  396.         call      initdlg
  397.  
  398.         .ELSEIF message==WM_DESTROY
  399.  
  400.         call      destroy
  401.  
  402.         .ENDIF
  403.  
  404.     xor eax, eax
  405.         ret 
  406.  
  407. paint:
  408.  
  409.         call BeginPaint, hWP, offset ps
  410.  
  411.         call EndPaint, hWP, offset ps
  412.     
  413.         mov eax, 0
  414.     
  415.         ret
  416.     
  417. command:
  418.  
  419.         cmp wparam, IDC_BUTTON1
  420.         jz map
  421.         cmp wparam, IDC_BUTTON2
  422.         jz retrieve
  423.         cmp wparam, IDCANCEL
  424.         jz destroy
  425.  
  426.         mov eax, 0
  427.         ret
  428.  
  429. map:
  430.         call GetDlgItemTextA, hWP, IDC_EDIT1, offset szRetData, 40h
  431.         lea     edi, [szRetData]
  432.         xor     eax, eax
  433.         or      ecx, -1
  434.         repnz   scasb
  435.         not     ecx
  436.         sub     edi, ecx
  437.         mov     szDataSize, ecx
  438.         cmp     [szRetData], 0
  439.         jnz     _map
  440.  
  441.         xor eax, eax
  442.         ret
  443.  
  444. _map:
  445.  
  446.         call CreateFileMappingA, INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, \
  447.         0, 1000h, offset szObjectName
  448.         mov     hFileMapping, eax
  449.  
  450.         call MapViewOfFile, hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 1000h
  451.         mov lpMappedObject, eax
  452.  
  453.         call GetDlgItem, hWP, IDC_BUTTON2
  454.         mov hwndChild, eax
  455.         call EnableWindow, hwndChild, TRUE
  456.  
  457.         xor      ecx, ecx
  458.         mov      ecx, szDataSize
  459.         lea      esi, [szRetData]
  460.         mov      edi, lpMappedObject
  461.         rep      movsb
  462.  
  463.         call GetDlgItem, hWP, IDC_BUTTON1
  464.         mov hwndChild, eax
  465.         call EnableWindow, hwndChild, FALSE
  466.         call SetDlgItemTextA, hWP, IDC_EDIT1, offset szNewInst
  467.  
  468.         ret
  469.  
  470. retrieve:
  471.  
  472.         call OpenFileMappingA, FILE_MAP_ALL_ACCESS, TRUE, \
  473.         offset szObjectName
  474.         mov     hFileMapping, eax
  475.         call MapViewOfFile, hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 1000h
  476.         mov     lpMappedObject, eax
  477.         call SetDlgItemTextA, hWP, IDC_EDIT1, lpMappedObject
  478.  
  479.         ret
  480.         
  481. initdlg:
  482.  
  483.         call OpenFileMappingA, FILE_MAP_ALL_ACCESS, TRUE, \
  484.         offset szObjectName
  485.         cmp     eax, NULL
  486.         jnz     another_instance
  487.  
  488.         call GetDlgItem, hWP, IDC_BUTTON2
  489.         mov hwndChild, eax
  490.         
  491.         call EnableWindow, hwndChild, FALSE
  492.         jmp Sk_Button
  493.  
  494. another_instance:
  495.  
  496.         call GetDlgItem, hWP, IDC_BUTTON1
  497.         mov hwndChild, eax
  498.     
  499.         call EnableWindow, hwndChild, FALSE
  500.  
  501. Sk_Button:
  502.  
  503.  
  504.         call GetSystemMetrics, SM_CXFULLSCREEN
  505.         mov s_width, eax
  506.  
  507.         call GetSystemMetrics, SM_CYFULLSCREEN
  508.         mov s_height, eax
  509.         
  510.         call GetWindowRect, hWP, offset rect
  511.  
  512.         mov eax, rect.rc_bottom
  513.         sub eax, rect.rc_top
  514.         mov height, eax
  515.  
  516.         mov eax, rect.rc_right
  517.         sub eax, rect.rc_left
  518.         mov width, eax
  519.  
  520.         mov eax, s_width
  521.         sub eax, width
  522.         shr eax, 01h
  523.         mov s_width, eax
  524.  
  525.         mov eax, s_height
  526.         sub eax, height
  527.         shr eax, 01h
  528.         mov s_height, eax
  529.  
  530.         call MoveWindow, hWP, s_width, s_height, width, height, FALSE
  531.  
  532.         ret
  533.  
  534. destroy:
  535.  
  536.         call UnmapViewOfFile, lpMappedObject
  537.         call CloseHandle, hFileMapping
  538.         call EndDialog, hWP, 0
  539.  
  540.         ret
  541.     
  542.         DlgProc endp
  543.                     
  544.     ends
  545.     end    start
  546.  
  547. ;-------------------------------------------------------------------
  548. ;            mmf1.rc (Compile using brcc32)
  549. ;-------------------------------------------------------------------
  550.  
  551. #define IDD_DIALOG1                     101
  552. #define IDI_ICON1                       102
  553. #define IDC_BUTTON1                     1000
  554. #define IDC_BUTTON2                     1001
  555. #define IDC_EDIT1                       1002
  556. #define IDC_STATIC                      -1
  557.  
  558. IDD_DIALOG1 DIALOG DISCARDABLE  0, 0, 188, 94
  559. STYLE DS_3DLOOK | DS_CENTER | WS_POPUP | WS_CAPTION | WS_THICKFRAME
  560. CAPTION "MMF Sharing Data - (c) Aesculapius"
  561. FONT 8, "MS Sans Serif"
  562. BEGIN
  563.     PUSHBUTTON      "Exit",IDCANCEL,68,73,50,14
  564.     PUSHBUTTON      "Store Data",IDC_BUTTON1,7,52,76,17
  565.     PUSHBUTTON      "Retrieve Data",IDC_BUTTON2,105,52,76,17
  566.     EDITTEXT        IDC_EDIT1,34,33,118,12,ES_AUTOHSCROLL
  567.     LTEXT           "Type Data Here:",IDC_STATIC,66,21,54,8
  568.     ICON            IDI_ICON1,IDC_STATIC,7,7,21,20
  569. END
  570. IDI_ICON1               ICON    DISCARDABLE     "icon1.ico"
  571.