//____________________________________________________________________________
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1995 - 1996.
//
//  File:       shared.cxx
//
//  Contents:   This file contains a set of routines for the management of
//              shared memory.
//
//  Functions:  SCHEDAllocShared: Allocates a handle (in a given process)
//                  to a copy of a memory block in this process.
//
//              SCHEDFreeShared: Releases the handle (and the copy of the
//                  memory block)
//
//              SCHEDLockShared: Maps a handle (from a given process) into
//                  a memory block in this process.  Has the option of
//                  transfering the handle to this process, thereby deleting
//                  it from the given process
//
//              SCHEDUnlockShared: Opposite of SCHEDLockShared, unmaps the
//                  memory block
//
//  History:    4/1/1996   RaviR   Created (stole from shell\dll\shared.c)
//
//____________________________________________________________________________

#include "..\pch\headers.hxx"
#pragma hdrstop


HANDLE
MapHandle(
    HANDLE  hData,
    DWORD   dwSource,
    DWORD   dwDest,
    DWORD   dwDesiredAccess,
    DWORD   dwFlags)
{
    HANDLE hSource = NULL;
    HANDLE hDest = NULL;
    HANDLE hNew = NULL;
    BOOL fOk;

    if (dwSource == GetCurrentProcessId())
        hSource = GetCurrentProcess();
    else
        hSource = OpenProcess( PROCESS_DUP_HANDLE, FALSE, dwSource);

    if (!hSource)
        goto DoExit;

    if (dwDest == GetCurrentProcessId())
        hDest = GetCurrentProcess();
    else
        hDest = OpenProcess( PROCESS_DUP_HANDLE, FALSE, dwDest);

    if (!hDest)
        goto DoExit;

    fOk = DuplicateHandle( hSource, hData,
                           hDest, &hNew,
                           dwDesiredAccess,
                           FALSE, dwFlags | DUPLICATE_SAME_ACCESS);
    if (!fOk)
        hNew = (HANDLE)NULL;

DoExit:
    if (hSource && dwSource != GetCurrentProcessId())
        CloseHandle(hSource);

    if (hDest && dwDest != GetCurrentProcessId())
        CloseHandle(hDest);

    return hNew;
}



HANDLE
SCHEDAllocShared(
    LPCVOID lpvData,
    DWORD   dwSize,
    DWORD   dwDestinationProcessId)
{
    HANDLE  hData;
    SHMAPHEADER* lpmh;
    HANDLE hUsableData;

    //
    // Make a filemapping handle with this data in it.
    //
    hData = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,0,
                               dwSize+sizeof(SHMAPHEADER),NULL);
    if (hData == NULL)
    {
        // DebugMsg...
        return NULL;
    }

    lpmh = (SHMAPHEADER *)MapViewOfFile(hData, FILE_MAP_READ | FILE_MAP_WRITE,
                                                                    0, 0, 0);

    if (!lpmh)
    {
        // DebugMsg...
        CloseHandle(hData);
        return NULL;
    }
    lpmh->dwSize = dwSize;

    if (lpvData)
        memcpy((LPVOID)(lpmh+1),lpvData,dwSize);

    UnmapViewOfFile(lpmh);

    hUsableData = MapHandle(hData,
                            GetCurrentProcessId(),
                            dwDestinationProcessId,
                            FILE_MAP_ALL_ACCESS,
                            DUPLICATE_CLOSE_SOURCE);
    return hUsableData;
}



LPVOID
SCHEDLockShared(
    HANDLE  hData,
    DWORD   dwSourceProcessId)
{
    SHMAPHEADER*   lpmh;
    HANDLE          hUsableData;

    hUsableData = MapHandle(hData,dwSourceProcessId,GetCurrentProcessId(),FILE_MAP_ALL_ACCESS,0);

    //
    // Now map that new process specific handle and close it
    //
    lpmh = (SHMAPHEADER*)MapViewOfFile(hUsableData,
                    FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);

    CloseHandle(hUsableData);

    if (!lpmh)
        return NULL;

    return (LPVOID)(lpmh+1);
}



BOOL
SCHEDUnlockShared(
    LPVOID  lpvData)
{
    SHMAPHEADER* lpmh = (SHMAPHEADER*)lpvData;

    //
    // Now just unmap the view of the file
    //
    return UnmapViewOfFile(lpmh-1);
}



BOOL
SCHEDFreeShared(
    HANDLE hData,
    DWORD dwSourceProcessId)
{
    HANDLE hUsableData;

    //
    // The below call closes the original handle in whatever process it
    // came from.
    //
    hUsableData = MapHandle(hData,dwSourceProcessId,
                            GetCurrentProcessId(),
                            FILE_MAP_ALL_ACCESS,DUPLICATE_CLOSE_SOURCE);

    //
    // Now free up the local handle
    //
    return CloseHandle(hUsableData);
}
