/**
 * sendMemoryPackage - uses Memory-Mapped files to do IPC messaging
 *                     with the Java AccessBridge DLL, informing the
 *                     Java AccessBridge DLL via SendMessage that something
 *                     is waiting for it in the shared file...
 *
 *                     In the SendMessage call, the third param (WPARAM) is
 *                     the source HWND (ourAccessBridgeWindow in this case),
 *                     and the fourth param (LPARAM) is the size in bytes of
 *                     the package put into shared memory.
 *
 */
BOOL
AccessBridgeJavaVMInstance::sendMemoryPackage(char *buffer, long bufsize) {

    // Protect against race condition where the memory mapped file is
    // deallocated before the memory package is being sent
    if (goingAway) {
        return FALSE;
    }
    BOOL retval = FALSE;

    DEBUG_CODE(char outputBuf[256]);
    DEBUG_CODE(sprintf(outputBuf, "AccessBridgeJavaVMInstance::sendMemoryPackage(, %d)", bufsize));
    DEBUG_CODE(AppendToCallInfo(outputBuf));

    DEBUG_CODE(PackageType *type = (PackageType *) buffer);
    DEBUG_CODE(if (*type == cGetAccessibleTextRangePackage) {
              )
    DEBUG_CODE(AppendToCallInfo("  'buffer' contains:"));
        DEBUG_CODE(GetAccessibleTextRangePackage *pkg = (GetAccessibleTextRangePackage *) (buffer + sizeof(PackageType)));
        DEBUG_CODE(sprintf(outputBuf, "    PackageType = %X", *type));
        DEBUG_CODE(AppendToCallInfo(outputBuf));
        DEBUG_CODE(sprintf(outputBuf, "    GetAccessibleTextRange: start = %d, end = %d, rText = %ls",
                           pkg->start, pkg->end, pkg->rText));
        DEBUG_CODE(AppendToCallInfo(outputBuf));
        DEBUG_CODE(
    })
AccessBridgeJavaVMInstance::~AccessBridgeJavaVMInstance() {
    DEBUG_CODE(char buffer[256]);

    DEBUG_CODE(AppendToCallInfo("***** in AccessBridgeJavaVMInstance::~AccessBridgeJavaVMInstance\r\n"));
    EnterCriticalSection(&sendMemoryIPCLock);

    // if IPC memory mapped file view is valid, unmap it
    goingAway = TRUE;
    if (memoryMappedView != (char *) 0) {
        DEBUG_CODE(sprintf(buffer, "  unmapping memoryMappedView; view = %p\r\n", memoryMappedView));
        DEBUG_CODE(AppendToCallInfo(buffer));
        UnmapViewOfFile(memoryMappedView);
        memoryMappedView = (char *) 0;
    }
    // if IPC memory mapped file handle map is open, close it
    if (memoryMappedFileMapHandle != (HANDLE) 0) {
        DEBUG_CODE(sprintf(buffer, "  closing memoryMappedFileMapHandle; handle = %p\r\n", memoryMappedFileMapHandle));
        DEBUG_CODE(AppendToCallInfo(buffer));
        CloseHandle(memoryMappedFileMapHandle);
        memoryMappedFileMapHandle = (HANDLE) 0;
    }
    LeaveCriticalSection(&sendMemoryIPCLock);

}
/**
 * initiateIPC - sets up the memory-mapped file to do IPC messaging
 *               1 file is created: to handle requests for information
 *               initiated from Windows AT.  The package is placed into
 *               the memory-mapped file (char *memoryMappedView),
 *               and then a special SendMessage() is sent.  When the
 *               JavaDLL returns from SendMessage() processing, the
 *               data will be in memoryMappedView.  The SendMessage()
 *               return value tells us if all is right with the world.
 *
 *               The set-up proces involves creating the memory-mapped
 *               file, and handshaking with the JavaDLL so it knows
 *               about it as well.
 *
 */
LRESULT
AccessBridgeJavaVMInstance::initiateIPC() {
    DEBUG_CODE(char debugBuf[256]);
    DWORD errorCode;

    DEBUG_CODE(AppendToCallInfo(" in AccessBridgeJavaVMInstance::initiateIPC()\r\n"));

    // create Windows-initiated IPC file & map it to a ptr
    memoryMappedFileMapHandle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
                                                  PAGE_READWRITE, 0,
                                                  // 8 bytes for return code
                                                  sizeof(WindowsInitiatedPackages) + 8,
                                                  memoryMappedFileName);
    if (memoryMappedFileMapHandle == NULL) {
        errorCode = GetLastError();
        DEBUG_CODE(sprintf(debugBuf, "  Failed to CreateFileMapping for %s, error: %X", memoryMappedFileName, errorCode));
        DEBUG_CODE(AppendToCallInfo(debugBuf));
        return errorCode;
    } else {
        DEBUG_CODE(sprintf(debugBuf, "  CreateFileMapping worked - filename: %s\r\n", memoryMappedFileName));
        DEBUG_CODE(AppendToCallInfo(debugBuf));
    }

    memoryMappedView = (char *) MapViewOfFile(memoryMappedFileMapHandle,
                                              FILE_MAP_READ | FILE_MAP_WRITE,
                                              0, 0, 0);
    if (memoryMappedView == NULL) {
        errorCode = GetLastError();
        DEBUG_CODE(sprintf(debugBuf, "  Failed to MapViewOfFile for %s, error: %X", memoryMappedFileName, errorCode));
        DEBUG_CODE(AppendToCallInfo(debugBuf));
        return errorCode;
    } else {
        DEBUG_CODE(sprintf(debugBuf, "  MapViewOfFile worked - view: %p\r\n", memoryMappedView));
        DEBUG_CODE(AppendToCallInfo(debugBuf));
    }


    // write some data to the memory mapped file
    strcpy(memoryMappedView, AB_MEMORY_MAPPED_FILE_OK_QUERY);


    // inform the JavaDLL that we've a memory mapped file ready for it
    char buffer[sizeof(PackageType) + sizeof(MemoryMappedFileCreatedPackage)];
    PackageType *type = (PackageType *) buffer;
    MemoryMappedFileCreatedPackage *pkg = (MemoryMappedFileCreatedPackage *) (buffer + sizeof(PackageType));
    *type = cMemoryMappedFileCreatedPackage;
    pkg->bridgeWindow = ABHandleToLong(ourAccessBridgeWindow);
    strncpy(pkg->filename, memoryMappedFileName, cMemoryMappedNameSize);
    sendPackage(buffer, sizeof(buffer));


    // look for the JavaDLL's answer to see if it could read the file
    if (strcmp(memoryMappedView, AB_MEMORY_MAPPED_FILE_OK_ANSWER) != 0) {
        DEBUG_CODE(sprintf(debugBuf, "  JavaVM failed to deal with memory mapped file %s\r\n",
                      memoryMappedFileName));
        DEBUG_CODE(AppendToCallInfo(debugBuf));
        return -1;
    } else {
        DEBUG_CODE(sprintf(debugBuf, "  Success!  JavaVM accpeted our file\r\n"));
        DEBUG_CODE(AppendToCallInfo(debugBuf));
    }

    return 0;
}