ID Number: Q72419
5.10 6.00 6.00a
OS/2
Summary:
Allocating a shared data segment is often desirable when writing a
dynamic link library (DLL) or .EXE. For instance, there may be state
information that you want to share between all instances of the DLL in
memory, or you may want to share data between two separate instances
of an .EXE.
There are several ways to implement this depending upon your data
requirements. If you want the memory to be allocated dynamically, you
can use OS/2 API calls. To create the memory, use DosAllocShrSeg() for
OS/2 versions 1.x and DosAllocSharedMem() for OS/2 version 2.0. To
access the memory, use DosGetShrSeg() and DosGetSharedMem(),
respectively. With this method, you control the size and availability
of the memory at run time. The drawback to this method is that you
must use pointers to store and retrieve data in the segment.
More Information:
If you are using Microsoft C version 6.0 or later, you can declare a
static variable based on a shared segment. For example
int _based (_segname("MyData")) MyInt;
declares an integer that resides in the segment named "MyData". As
long as you declare that segment to be of class SHARED in the module
definition file (.DEF) for the .EXE or DLL, it will be shared by all
processes that define it.
Finally, if you want to store data in a shared segment without having
to use the OS/2 APIs or the _based operator, you can declare a segment
created by the compiler as shared. First, compile the data you want in
the shared segment with the /ND (name data segment) option followed by
the segment name. Assuming a segment name of "MYDATA," the compiler
will create the following three segments:
Segment name: MYDATA
Contains: Initialized global data
Initialized static data
Strings
Segment name: MYDATA_BSS
Contains: Uninitialized static data
Segment name: MYDATA_CONST
Contains: Read-only and floating-point constants
Segment values for far data
The compiler will also create a group called MYDATA_GROUP, which
contains these three segments. Because they are all in a group, all
three segments must then be declared as SHARED in the .DEF file for
the .EXE or DLL. For this example, the .DEF file must contain the
following:
SEGMENTS
MYDATA class 'FAR_DATA' SHARED
MYDATA_BSS class 'FAR_DATA' SHARED
MYDATA_CONST class 'FAR_DATA' SHARED
The sample code below illustrates this method. There are two DLLs, a
main program, a .DEF file, and a .CMD file for building everything. An
important point to remember is that the module compiled with /ND
cannot have any C run-time calls in it.
Sample Code 1
-------------
/* DLL1.C
*
* Declare an array of chars that will be residing in shared memory.
* This module must be compiled with /ND and the segment name added
* to the .DEF file as shared for that to happen.
* In addition, the data must be initialized to be placed in the
* default data segment... (named by /ND)
*
* GetDllData merely returns a pointer to the block. No run time
* can be used unless linked with CDLLOBJS.LIB version of run time.
*/
char array[480] = "Some text";
char far * _loadds _export GetDllData(void);
char far * _loadds _export GetDllData(void)
{
return(array);
}
Sample Code 2
-------------
/* DLL2.C
*
* Provide a way to test that the DLL is actually loaded.
* Print message.
*/
#include <stdio.h>
void _export _loadds DllFunc(void);
void _export _loadds DllFunc(void)
{
printf("Inside DLL Function...\n");
}
Sample Code 3
-------------
/* MAIN.C
*
* Test that the array resides in a shared memory segment. If there
* are no arguments, initialize the first 240 bytes of the array to
* "PROG1"; if there is one command-line argument, initialize the
* second 240 bytes to "PROG2". Print out the memory over and over
* every second until a key press is detected.
*/
#define INCL_DOSPROCESS
#include <os2.h>
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <conio.h>
extern char array[];
char far * _loadds _export GetDllData(void);
void _loadds _export DllFunc(void);
void main(int argc, char * argv[]);
void main(int argc, char * argv[])
{
int x;
char far *DllData;
if (argc == 2)
for ( x = 240; x < 480; x+=6)
memcpy( &array[x], "Prog2", 6);
else
if (argc == 1)
for ( x = 0; x < 240; x+=6)
memcpy( &array[x], "Prog1", 6);
DllFunc();
DllData = GetDllData(); // Get a pointer to the shared block
while (!kbhit()) // and print it out till a key is
{ // pressed
printf("Memory: ");
for (x = 0; x < 480; x++)
printf("%c", DllData[x]);
printf("\n");
DosSleep(1000L);
}
}
Sample Code 4
-------------
; THEDLL.DEF
LIBRARY THEDLL INITINSTANCE
DATA MULTIPLE
SEGMENTS
MYSEG CLASS 'FAR_DATA' SHARED
MYSEG_BSS CLASS 'FAR_DATA' SHARED
MYSEG_CONST CLASS 'FAR_DATA' SHARED
EXPORTS
_DllFunc
_GetDllData
_array
Sample Makefile
---------------
rem MAKECODE.CMD
@echo off
echo Compile DLL1.C with /ND to declare the shared segment...
cl /Zi /Od /ML /Gs /c /NDMYSEG DLL1.C
echo Compile DLL2.C with standard options...
cl /Zi /Od /ML /Gs /c DLL2.C
echo Link the two together with LLIBCDLL.LIB and THEDLL.DEF...
link /CO /NOD /NOI /MAP DLL2+DLL1,THEDLL.DLL,,LLIBCDLL+OS2,THEDLL.DEF;
echo Since we need to export data, run IMPLIB on the .DEF file...
IMPLIB THEDLL.LIB THEDLL.DEF
echo Compile the module for the .EXE using standard large model...
cl /Od /Zi /AL /Gs /c MAIN.C
echo Link with the DLL's import library.
link /CO /NOD /NOI /MAP MAIN,MAIN.EXE,,LLIBCEP+OS2+THEDLL;
echo Now, start the two processes in different screen groups.
echo The first with no arguments, the second with one...
echo start "Test Program 1" /fs MAIN
echo start "Test Program 2" /fs MAIN second