# HG changeset patch # User bsmith@81767d24-ef19-dc11-ae90-00e081727c95 # Date 1082180289 0 # Node ID 1a210e2f214bb5e80a1b01cb69cca8aa8b9d8579 # Parent f4093dce8155bdae95a62d5dc658e1c42414cf33 Added a bunch of support routines I now own due to the settlement agreement with F/X. Shared memory and named event semaphores in particular. diff -r f4093dce8155 -r 1a210e2f214b compat.c --- a/compat.c Mon Apr 12 03:52:15 2004 +0000 +++ b/compat.c Sat Apr 17 05:38:09 2004 +0000 @@ -713,6 +713,85 @@ return fseek(stream, offset, whence); } +void API nice_strformat(char *dest, long double val, int dec) +{ + char formatbuf[10]; + char format = 0; + double printval; + + /* 1024 ^ 3 = Gigabytes */ + if(val >= 1073741824L) + { + printval = val/(1073741824L); + format = 'G'; + } + /* 1024 ^ 2 = Megabytes */ + else if(val >= 1048576) + { + printval = val/(1048576); + format = 'M'; + } + /* 1024 = Kilobytes */ + else if(val > 1024) + { + printval = val/1024; + format = 'K'; + } + else + printval = val; + + /* Generate the format string */ + sprintf(formatbuf, "%%.%df%c", dec, format); + /* Create the pretty value */ + sprintf(dest, formatbuf, printval); +} + +/* Update the current working directory based on the + * path of the executable being executed. + */ +void API initdir(int argc, char *argv[]) +{ + if(argc > 0) + { + char *tmpdir = strdup(argv[0]); + int z, len = strlen(argv[0]); + + for(z=len;z > -1;z--) + { + if(tmpdir[z] == '/') + { + tmpdir[z+1] = 0; + setpath(tmpdir); + free(tmpdir); + return; + } + } + free(tmpdir); + } +} + +/* + * Sets the current directory (and drive) information. + * Parameters: + * path: A buffer containing the new path. + * Returns: + * -1 on error. + */ +int API setpath(char *path) +{ +#if defined(__OS2__) || defined(__WIN32__) + if(strlen(path) > 2) + { + if(path[1] == ':') + { + char drive = toupper(path[0]); + _chdrive((drive - 'A')+1); + } + } +#endif + return chdir(path); +} + static int locale_number = -1, locale_count = 0; static char **locale_text = NULL; diff -r f4093dce8155 -r 1a210e2f214b compat.h --- a/compat.h Mon Apr 12 03:52:15 2004 +0000 +++ b/compat.h Sat Apr 17 05:38:09 2004 +0000 @@ -232,4 +232,7 @@ int API fsseek(FILE *stream, long offset, int whence); int API locale_init(char *filename, int my_locale); char * API locale_string(char *default_text, int message); +void API nice_strformat(char *dest, long double val, int dec); +void API initdir(int argc, char *argv[]); +int API setpath(char *path); #endif diff -r f4093dce8155 -r 1a210e2f214b dw.def --- a/dw.def Mon Apr 12 03:52:15 2004 +0000 +++ b/dw.def Sat Apr 17 05:38:09 2004 +0000 @@ -250,3 +250,13 @@ dw_taskbar_insert @440 dw_taskbar_delete @441 + dw_named_memory_new @450 + dw_named_memory_get @451 + dw_named_memory_free @452 + + dw_named_event_new @460 + dw_named_event_get @461 + dw_named_event_reset @462 + dw_named_event_post @463 + dw_named_event_wait @464 + dw_named_event_close @465 diff -r f4093dce8155 -r 1a210e2f214b dw.h --- a/dw.h Mon Apr 12 03:52:15 2004 +0000 +++ b/dw.h Sat Apr 17 05:38:09 2004 +0000 @@ -223,6 +223,7 @@ typedef HWND HMENUI; typedef HMODULE HMOD; typedef unsigned short UWORD; +typedef unsigned long HSHM; extern HAB dwhab; extern HMQ dwhmq; @@ -463,6 +464,7 @@ typedef HANDLE HMTX; typedef HANDLE HEV; typedef HANDLE HMOD; +typedef HANDLE HSHM; typedef struct _container { ColorInfo cinfo; @@ -737,6 +739,12 @@ } *HEV; typedef pthread_t DWTID; typedef void * HMOD; +typedef struct _dw_unix_shm { + int fd; + char *path; + int sid; + int size; +} HSHM; typedef struct _hpixmap { unsigned long width, height; @@ -856,6 +864,14 @@ #define DW_MENU_SEPARATOR "" #define DW_NOMENU 0 +/* Return value error codes */ +#define DW_ERROR_NONE 0 +#define DW_ERROR_GENERAL 1 +#define DW_ERROR_TIMEOUT 2 +#define DW_ERROR_NON_INIT 3 +#define DW_ERROR_NO_MEM 4 +#define DW_ERROR_INTERRUPT 5 + #if defined(__OS2__) || defined(__EMX__) #define DW_OS2_RGB(a) ((DW_RED_VALUE(a) << 16) | (DW_GREEN_VALUE(a) << 8) | DW_BLUE_VALUE(a)) #endif @@ -1089,5 +1105,14 @@ void API dw_signal_disconnect_by_window(HWND window); void API dw_signal_disconnect_by_data(HWND window, void *data); void API dw_signal_disconnect_by_name(HWND window, char *signame); +HEV API dw_named_event_new(char *name); +HEV API dw_named_event_get(char *name); +int API dw_named_event_reset(HEV eve); +int API dw_named_event_post(HEV eve); +int API dw_named_event_wait(HEV eve, unsigned long timeout); +int API dw_named_event_close(HEV eve); +HSHM API dw_named_memory_new(void **dest, int size, char *name); +HSHM API dw_named_memory_get(void **dest, int size, char *name); +int API dw_named_memory_free(HSHM handle, void *ptr); #endif diff -r f4093dce8155 -r 1a210e2f214b dwcompat.def --- a/dwcompat.def Mon Apr 12 03:52:15 2004 +0000 +++ b/dwcompat.def Sat Apr 17 05:38:09 2004 +0000 @@ -39,3 +39,6 @@ locale_init @50 locale_string @51 + + nice_strformat @60 + initdir @61 diff -r f4093dce8155 -r 1a210e2f214b dwcompatw.def --- a/dwcompatw.def Mon Apr 12 03:52:15 2004 +0000 +++ b/dwcompatw.def Sat Apr 17 05:38:09 2004 +0000 @@ -35,3 +35,6 @@ locale_init @50 locale_string @51 + nice_strformat @60 + initdir @61 + setpath @62 diff -r f4093dce8155 -r 1a210e2f214b dww.def --- a/dww.def Mon Apr 12 03:52:15 2004 +0000 +++ b/dww.def Sat Apr 17 05:38:09 2004 +0000 @@ -247,3 +247,13 @@ dw_taskbar_insert @440 dw_taskbar_delete @441 + dw_named_memory_new @450 + dw_named_memory_get @451 + dw_named_memory_free @452 + + dw_named_event_new @460 + dw_named_event_get @461 + dw_named_event_reset @462 + dw_named_event_post @463 + dw_named_event_wait @464 + dw_named_event_close @465 diff -r f4093dce8155 -r 1a210e2f214b gtk/dw.c --- a/gtk/dw.c Mon Apr 12 03:52:15 2004 +0000 +++ b/gtk/dw.c Sat Apr 17 05:38:09 2004 +0000 @@ -7368,6 +7368,339 @@ return TRUE; } +struct _seminfo { + int fd; + int waiting; +}; + +static void _handle_sem(int *tmpsock) +{ + fd_set rd; + struct _seminfo *array = (struct _seminfo *)malloc(sizeof(struct _seminfo)); + int listenfd = tmpsock[0]; + int bytesread, connectcount = 1, maxfd, z, posted = 0; + char command; + sigset_t mask; + + sigfillset(&mask); /* Mask all allowed signals */ + pthread_sigmask(SIG_BLOCK, &mask, NULL); + + /* problems */ + if(tmpsock[1] == -1) + { + free(array); + return; + } + + array[0].fd = tmpsock[1]; + array[0].waiting = 0; + + /* Free the memory allocated in dw_named_event_new. */ + free(tmpsock); + + while(1) + { + FD_ZERO(&rd); + FD_SET(listenfd, &rd); + + maxfd = listenfd; + + /* Added any connections to the named event semaphore */ + for(z=0;z maxfd) + maxfd = array[z].fd; + + FD_SET(array[z].fd, &rd); + } + + if(select(maxfd+1, &rd, NULL, NULL, NULL) == -1) + return; + + if(FD_ISSET(listenfd, &rd)) + { + struct _seminfo *newarray; + int newfd = accept(listenfd, 0, 0); + + if(newfd > -1) + { + /* Add new connections to the set */ + newarray = (struct _seminfo *)malloc(sizeof(struct _seminfo)*(connectcount+1)); + memcpy(newarray, array, sizeof(struct _seminfo)*(connectcount)); + + newarray[connectcount].fd = newfd; + newarray[connectcount].waiting = 0; + + connectcount++; + + /* Replace old array with new one */ + free(array); + array = newarray; + } + } + + /* Handle any events posted to the semaphore */ + for(z=0;z -1) + close(tmpsock[0]); + if(tmpsock[1] > -1) + close(tmpsock[1]); + if(ev > -1) + close(ev); + free(tmpsock); + return 0; + } + + /* Create a thread to handle this event semaphore */ + pthread_create(&dwthread, NULL, (void *)_handle_sem, (void *)tmpsock); + return ev; +} + +/* Open an already existing named event semaphore. + * Parameters: + * eve: Pointer to an event handle to receive handle. + * name: Name given to semaphore which can be opened + * by other processes. + */ +HEV dw_named_event_get(char *name) +{ + struct sockaddr_un un; + int ev = socket(AF_UNIX, SOCK_STREAM, 0); + if(ev < 0) + return 0; + + un.sun_family=AF_UNIX; + mkdir("/tmp/.dw", S_IWGRP|S_IWOTH); + strcpy(un.sun_path, "/tmp/.dw/"); + strcat(un.sun_path, name); + connect(ev, (struct sockaddr *)&un, sizeof(un)); + return ev; +} + +/* Resets the event semaphore so threads who call wait + * on this semaphore will block. + * Parameters: + * eve: Handle to the semaphore obtained by + * an open or create call. + */ +int dw_named_event_reset(HEV eve) +{ + /* signal reset */ + char tmp = (char)0; + + if(eve < 0) + return 0; + + if(write(eve, &tmp, 1) == 1) + return 0; + return 1; +} + +/* Sets the posted state of an event semaphore, any threads + * waiting on the semaphore will no longer block. + * Parameters: + * eve: Handle to the semaphore obtained by + * an open or create call. + */ +int dw_named_event_post(HEV eve) +{ + + /* signal post */ + char tmp = (char)1; + + if(eve < 0) + return 0; + + if(write(eve, &tmp, 1) == 1) + return 0; + return 1; +} + +/* Waits on the specified semaphore until it becomes + * posted, or returns immediately if it already is posted. + * Parameters: + * eve: Handle to the semaphore obtained by + * an open or create call. + * timeout: Number of milliseconds before timing out + * or -1 if indefinite. + */ +int dw_named_event_wait(HEV eve, unsigned long timeout) +{ + fd_set rd; + struct timeval tv, *useme; + int retval = 0; + char tmp; + + if(eve < 0) + return DB_EVENT_NON_INIT; + + /* Set the timout or infinite */ + if(timeout == -1) + useme = NULL; + else + { + tv.tv_sec = timeout / 1000; + tv.tv_usec = timeout % 1000; + + useme = &tv; + } + + FD_ZERO(&rd); + FD_SET(eve, &rd); + + /* Signal wait */ + tmp = (char)2; + write(eve, &tmp, 1); + + retval = select(eve+1, &rd, NULL, NULL, useme); + + /* Signal done waiting. */ + tmp = (char)3; + write(eve, &tmp, 1); + + if(retval == 0) + return DW_EVENT_TIMEOUT; + else if(retval == -1) + return DW_EVENT_INTERRUPT; + + /* Clear the entry from the pipe so + * we don't loop endlessly. :) + */ + read(eve, &tmp, 1); + return 0; +} + +/* Release this semaphore, if there are no more open + * handles on this semaphore the semaphore will be destroyed. + * Parameters: + * eve: Handle to the semaphore obtained by + * an open or create call. + */ +int dw_named_event_close(HEV eve) +{ + /* Finally close the domain socket, + * cleanup will continue in _handle_sem. + */ + close(eve); + return 0; +} + /* * Setup thread independent color sets. */ @@ -7383,6 +7716,102 @@ _dw_thread_remove(dw_thread_id()); free(tmp); } + +/* + * Allocates a shared memory region with a name. + * Parameters: + * handle: A pointer to receive a SHM identifier. + * dest: A pointer to a pointer to receive the memory address. + * size: Size in bytes of the shared memory region to allocate. + * name: A string pointer to a unique memory name. + */ +HSHM dw_named_memory_new(void **dest, int size, char *name) +{ + char namebuf[1024]; + HSHM handle; + + mkdir("/tmp/.dw", S_IWGRP|S_IWOTH); + sprintf(namebuf, "/tmp/.dw/%s", name); + + if((handle->fd = open(namebuf, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) + return 0; + + ftruncate(handle->fd, size); + + /* attach the shared memory segment to our process's address space. */ + *dest = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, handle->fd, 0); + + if(*dest == MAP_FAILED) + { + close(handle->fd); + *dest = NULL; + return 0; + } + + handle->size = size; + handle->sid = getsid(0); + handle->path = strdup(namebuf); + + return handle; +} + +/* + * Aquires shared memory region with a name. + * Parameters: + * dest: A pointer to a pointer to receive the memory address. + * size: Size in bytes of the shared memory region to requested. + * name: A string pointer to a unique memory name. + */ +HSHM dw_named_memory_get(void **dest, int size, char *name) +{ + char namebuf[1024]; + HSHM handle; + + mkdir("/tmp/.dw", S_IWGRP|S_IWOTH); + sprintf(namebuf, "/tmp/.dw/%s", name); + + if((handle->fd = open(namebuf, O_RDWR)) < 0) + return -1; + + /* attach the shared memory segment to our process's address space. */ + *dest = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, handle->fd, 0); + + if(*dest == MAP_FAILED) + { + close(handle->fd); + *dest = NULL; + return 0; + } + + handle->size = size; + handle->sid = -1; + handle->path = NULL; + + return handle; +} + +/* + * Frees a shared memory region previously allocated. + * Parameters: + * handle: Handle obtained from DB_named_memory_allocate. + * ptr: The memory address aquired with DB_named_memory_allocate. + */ +int dw_named_memory_free(HSHM handle, void *ptr) +{ + int rc = munmap(ptr, handle.size); + + close(handle.fd); + if(handle.path) + { + /* Only remove the actual file if we are the + * creator of the file. + */ + if(handle.sid != -1 && handle.sid == getsid(0)) + remove(handle.path); + free(handle.path); + } + return rc; +} /* * Creates a new thread with a starting point of func. * Parameters: diff -r f4093dce8155 -r 1a210e2f214b os2/dw.c --- a/os2/dw.c Mon Apr 12 03:52:15 2004 +0000 +++ b/os2/dw.c Sat Apr 17 05:38:09 2004 +0000 @@ -7932,6 +7932,188 @@ return TRUE; } +/* Create a named event semaphore which can be + * opened from other processes. + * Parameters: + * eve: Pointer to an event handle to receive handle. + * name: Name given to semaphore which can be opened + * by other processes. + */ +HEV API dw_named_event_new(char *name) +{ + int rc; + char *semname = malloc(strlen(name)+8); + HEV ev = 0; + + if(!semname) + return 0; + + strcpy(semname, "\\sem32\\"); + strcat(semname, name); + + DosCreateEventSem(semname, &ev, 0L, FALSE); + + free(semname); + return ev; +} + +/* Open an already existing named event semaphore. + * Parameters: + * eve: Pointer to an event handle to receive handle. + * name: Name given to semaphore which can be opened + * by other processes. + */ +HEV API dw_named_event_get(char *name) +{ + char *semname = malloc(strlen(name)+8); + HEV ev; + + if(!semname) + return 0; + + strcpy(semname, "\\sem32\\"); + strcat(semname, name); + + DosOpenEventSem(semname, &ev); + + free(semname); + return ev; +} + +/* Resets the event semaphore so threads who call wait + * on this semaphore will block. + * Parameters: + * eve: Handle to the semaphore obtained by + * an open or create call. + */ +int API dw_named_event_reset(HEV eve) +{ + ULONG count; + + return DosResetEventSem(eve, &count); +} + +/* Sets the posted state of an event semaphore, any threads + * waiting on the semaphore will no longer block. + * Parameters: + * eve: Handle to the semaphore obtained by + * an open or create call. + */ +int API dw_named_event_post(HEV eve) +{ + return DosPostEventSem(eve); +} + + +/* Waits on the specified semaphore until it becomes + * posted, or returns immediately if it already is posted. + * Parameters: + * eve: Handle to the semaphore obtained by + * an open or create call. + * timeout: Number of milliseconds before timing out + * or -1 if indefinite. + */ +int API dw_named_event_wait(HEV eve, unsigned long timeout) +{ + int rc; + + rc = DosWaitEventSem(eve, timeout); + switch (rc) + { + case ERROR_INVALID_HANDLE: + rc = DW_ERROR_NON_INIT; + break; + case ERROR_NOT_ENOUGH_MEMORY: + rc = DW_ERROR_NO_MEM; + break; + case ERROR_INTERRUPT: + rc = DW_ERROR_INTERRUPT; + break; + case ERROR_TIMEOUT: + rc = DW_ERROR_TIMEOUT; + break; + } + + return rc; +} + +/* Release this semaphore, if there are no more open + * handles on this semaphore the semaphore will be destroyed. + * Parameters: + * eve: Handle to the semaphore obtained by + * an open or create call. + */ +int API dw_named_event_close(HEV eve) +{ + int rc; + + rc = DosCloseEventSem(eve); + switch (rc) + { + case ERROR_INVALID_HANDLE: + rc = DW_ERROR_NON_INIT; + break; + + case ERROR_SEM_BUSY: + rc = DW_ERROR_BUSY; + break; + } + + return rc; +} + +/* + * Allocates a shared memory region with a name. + * Parameters: + * handle: A pointer to receive a SHM identifier. + * dest: A pointer to a pointer to receive the memory address. + * size: Size in bytes of the shared memory region to allocate. + * name: A string pointer to a unique memory name. + */ +int API dw_named_memory_alloc(HSHM *handle, void **dest, int size, char *name) +{ + char namebuf[1024]; + + sprintf(namebuf, "\\sharemem\\%s", name); + + if(DosAllocSharedMem((void *)dest, namebuf, size, PAG_COMMIT | PAG_WRITE | PAG_READ) != NO_ERROR) + return -1; + + return 0; +} + +/* + * Aquires shared memory region with a name. + * Parameters: + * dest: A pointer to a pointer to receive the memory address. + * size: Size in bytes of the shared memory region to requested. + * name: A string pointer to a unique memory name. + */ +int API dw_named_memory_get(HSHM *handle, void **dest, int size, char *name) +{ + char namebuf[1024]; + + sprintf(namebuf, "\\sharemem\\%s", name); + + if(DosGetNamedSharedMem((void *)dest, namebuf, PAG_READ | PAG_WRITE) != NO_ERROR) + return -1; + + return 0; +} + +/* + * Frees a shared memory region previously allocated. + * Parameters: + * handle: Handle obtained from DB_named_memory_allocate. + * ptr: The memory address aquired with DB_named_memory_allocate. + */ +int API dw_named_memory_free(HSHM handle, void *ptr) +{ + if(DosFreeMem(ptr) != NO_ERROR) + return -1; + return 0; +} + /* * Encapsulate the message queues on OS/2. */ diff -r f4093dce8155 -r 1a210e2f214b win/dw.c --- a/win/dw.c Mon Apr 12 03:52:15 2004 +0000 +++ b/win/dw.c Sat Apr 17 05:38:09 2004 +0000 @@ -27,6 +27,7 @@ DWORD dwVersion = 0, dwComctlVer = 0; DWTID _dwtid = -1; +SECURITY_DESCRIPTOR _dwsd; #define PACKVERSION(major,minor) MAKELONG(minor,major) @@ -3266,6 +3267,10 @@ FreeLibrary(huser); } + /* Initialize Security for named events and memory */ + InitializeSecurityDescriptor(&_dwsd, SECURITY_DESCRIPTOR_REVISION); + SetSecurityDescriptorDacl(&_dwsd, TRUE, (PACL) NULL, FALSE); + return 0; } @@ -7870,7 +7875,188 @@ { if(eve) return CloseHandle(*eve); - return FALSE; + return 0; +} + +/* Create a named event semaphore which can be + * opened from other processes. + * Parameters: + * eve: Pointer to an event handle to receive handle. + * name: Name given to semaphore which can be opened + * by other processes. + */ +HEV API dw_named_event_new(char *name) +{ + SECURITY_ATTRIBUTES sa; + + sa.nLength = sizeof( SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = &_dwsd; + sa.bInheritHandle = FALSE; + + return CreateEvent(&sa, TRUE, FALSE, name); +} + +/* Destroy this semaphore. + * Parameters: + * eve: Handle to the semaphore obtained by + * a create call. + */ +HEV API dw_named_event_get(char *name) +{ + return OpenEvent(EVENT_ALL_ACCESS, FALSE, name); +} + +/* Resets the event semaphore so threads who call wait + * on this semaphore will block. + * Parameters: + * eve: Handle to the semaphore obtained by + * an open or create call. + */ +int API dw_named_event_reset(HEV eve) +{ + int rc; + + rc = ResetEvent(eve); + if(!rc) + return 1; + + return 0; +} + +/* Sets the posted state of an event semaphore, any threads + * waiting on the semaphore will no longer block. + * Parameters: + * eve: Handle to the semaphore obtained by + * an open or create call. + */ +int API dw_named_event_post(HEV eve) +{ + int rc; + + rc = SetEvent(eve); + if(!rc) + return 1; + + return 0; +} + +/* Waits on the specified semaphore until it becomes + * posted, or returns immediately if it already is posted. + * Parameters: + * eve: Handle to the semaphore obtained by + * an open or create call. + * timeout: Number of milliseconds before timing out + * or -1 if indefinite. + */ +int API dw_named_event_wait(HEV eve, unsigned long timeout) +{ + int rc; + + rc = WaitForSingleObject(eve, timeout); + switch (rc) + { + case WAIT_FAILED: + rc = DW_ERROR_TIMEOUT; + break; + + case WAIT_ABANDONED: + rc = DW_ERROR_INTERRUPT; + break; + + case WAIT_OBJECT_0: + rc = 0; + break; + } + + return rc; +} + +/* Release this semaphore, if there are no more open + * handles on this semaphore the semaphore will be destroyed. + * Parameters: + * eve: Handle to the semaphore obtained by + * an open or create call. + */ +int API dw_named_event_close(HEV eve) +{ + int rc; + + rc = CloseHandle(eve); + if(!rc) + return 1; + + return 0; +} + +/* + * Allocates a shared memory region with a name. + * Parameters: + * handle: A pointer to receive a SHM identifier. + * dest: A pointer to a pointer to receive the memory address. + * size: Size in bytes of the shared memory region to allocate. + * name: A string pointer to a unique memory name. + */ +HSHM API dw_named_memory_new(void **dest, int size, char *name) +{ + SECURITY_ATTRIBUTES sa; + HSHM handle; + + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = &_dwsd; + sa.bInheritHandle = FALSE; + + handle = CreateFileMapping((HANDLE)0xFFFFFFFF, &sa, PAGE_READWRITE, 0, size, name); + + if(!handle) + return 0; + + *dest = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0); + + if(!*dest) + { + CloseHandle(handle); + return 0; + } + + return handle; +} + +/* + * Aquires shared memory region with a name. + * Parameters: + * dest: A pointer to a pointer to receive the memory address. + * size: Size in bytes of the shared memory region to requested. + * name: A string pointer to a unique memory name. + */ +HSHM API dw_named_memory_get(void **dest, int size, char *name) +{ + HSHM handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, name); + + if(!handle) + return 0; + + *dest = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0); + + if(!*dest) + { + CloseHandle(handle); + return 0; + } + + return handle; +} + +/* + * Frees a shared memory region previously allocated. + * Parameters: + * handle: Handle obtained from DB_named_memory_allocate. + * ptr: The memory address aquired with DB_named_memory_allocate. + */ +int API dw_named_memory_free(HSHM handle, void *ptr) +{ + UnmapViewOfFile(ptr); + CloseHandle(handle); + return 0; } /*