//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//

#include <celog.h>
#define MAX_STACK_FRAME 20


//----------------------------------------------------------
_inline void CELOG_HeapCreate(DWORD dwOptions, DWORD dwInitSize, DWORD dwMaxSize, HANDLE hHeap)
{
    if (IsCeLogZoneEnabled(CELZONE_HEAP | CELZONE_MEMTRACKING)) {
        CEL_HEAP_CREATE cl;

        cl.dwOptions = dwOptions;
        cl.dwInitSize = dwInitSize;
        cl.dwMaxSize = dwMaxSize;
        cl.hHeap = hHeap;
        cl.dwPID = GetCurrentProcessId();
        cl.dwTID = GetCurrentThreadId();

        CeLogData(TRUE, CELID_HEAP_CREATE, &cl, sizeof(CEL_HEAP_CREATE), 0,
                  CELZONE_HEAP | CELZONE_MEMTRACKING, 0, FALSE);
    }
}

//----------------------------------------------------------
_inline void CELOG_HeapAlloc(HANDLE hHeap, DWORD dwFlags, DWORD dwBytes, DWORD lpMem)
{
    if (IsCeLogZoneEnabled(CELZONE_HEAP | CELZONE_MEMTRACKING) && lpMem) {
        BYTE pTmp[sizeof(CEL_HEAP_ALLOC) + sizeof(StackSnapshot) + MAX_STACK_FRAME*sizeof(CallSnapshot)];
        PCEL_HEAP_ALLOC pcl = (PCEL_HEAP_ALLOC) pTmp;
        StackSnapshot *pStack = (StackSnapshot*) &pcl->adwStackTrace[0];
        DWORD dwLastError = GetLastError();  // Don't change lasterr while capturing callstack

        pcl->hHeap   = hHeap;
        pcl->dwFlags = dwFlags;
        pcl->dwBytes = dwBytes;
        pcl->lpMem   = lpMem;
        pcl->dwTID = GetCurrentThreadId();
        pcl->dwPID = GetCurrentProcessId();
        pcl->dwCallerPID = (DWORD)GetCallerProcess();

        pStack->wVersion = 1;
        pStack->wNumCalls = (WORD) GetCallStackSnapshot (MAX_STACK_FRAME, pStack->rgCalls, 0, 0);

        CeLogData(TRUE, CELID_HEAP_ALLOC, pcl,
                  (WORD)(sizeof(CEL_HEAP_ALLOC) + sizeof(StackSnapshot) + pStack->wNumCalls*sizeof(CallSnapshot)),
                  0, CELZONE_HEAP | CELZONE_MEMTRACKING, 0, FALSE);
        SetLastError(dwLastError);
    }
}

//----------------------------------------------------------
_inline void CELOG_HeapRealloc(HANDLE hHeap, DWORD dwFlags, DWORD dwBytes, DWORD lpMemOld, DWORD lpMem)
{
    if (IsCeLogZoneEnabled(CELZONE_HEAP | CELZONE_MEMTRACKING) && lpMem) {
        BYTE pTmp[sizeof(CEL_HEAP_REALLOC) + sizeof(StackSnapshot) + MAX_STACK_FRAME*sizeof(CallSnapshot)];
        PCEL_HEAP_REALLOC pcl = (PCEL_HEAP_REALLOC) pTmp;
        StackSnapshot *pStack = (StackSnapshot*) &pcl->adwStackTrace[0];
        DWORD dwLastError = GetLastError();  // Don't change lasterr while capturing callstack

        pcl->hHeap = hHeap;
        pcl->dwFlags = dwFlags;
        pcl->dwBytes = dwBytes;
        pcl->lpMemOld = lpMemOld;
        pcl->lpMem = lpMem;
        pcl->dwTID = GetCurrentThreadId();
        pcl->dwPID = GetCurrentProcessId();
        pcl->dwCallerPID = (DWORD)GetCallerProcess();

        pStack->wVersion = 1;
        pStack->wNumCalls = (WORD) GetCallStackSnapshot (MAX_STACK_FRAME, pStack->rgCalls, 0, 0);

        CeLogData(TRUE, CELID_HEAP_REALLOC, pcl,
                  (WORD)(sizeof(CEL_HEAP_REALLOC) + sizeof(StackSnapshot) + pStack->wNumCalls*sizeof(CallSnapshot)),
                  0, CELZONE_HEAP | CELZONE_MEMTRACKING, 0, FALSE);
        SetLastError(dwLastError);
    }
}

//----------------------------------------------------------
_inline void CELOG_HeapFree(HANDLE hHeap, DWORD dwFlags, DWORD lpMem)
{
    if (IsCeLogZoneEnabled(CELZONE_HEAP | CELZONE_MEMTRACKING)) {
        BYTE pTmp[sizeof(CEL_HEAP_FREE) + sizeof(StackSnapshot) + MAX_STACK_FRAME*sizeof(CallSnapshot)];
        PCEL_HEAP_FREE pcl = (PCEL_HEAP_FREE) pTmp;
        StackSnapshot *pStack = (StackSnapshot*) &pcl->adwStackTrace[0];
        DWORD dwLastError = GetLastError();  // Don't change lasterr while capturing callstack

        pcl->hHeap = hHeap;
        pcl->dwFlags = dwFlags;
        pcl->lpMem = lpMem;
        pcl->dwTID = GetCurrentThreadId();
        pcl->dwPID = GetCurrentProcessId();
        pcl->dwCallerPID = (DWORD)GetCallerProcess();

        pStack->wVersion = 1;
        pStack->wNumCalls = (WORD) GetCallStackSnapshot (MAX_STACK_FRAME, pStack->rgCalls, 0, 0);

        CeLogData(TRUE, CELID_HEAP_FREE, pcl,
                  (WORD)(sizeof(CEL_HEAP_FREE) + sizeof(StackSnapshot) + pStack->wNumCalls*sizeof(CallSnapshot)),
                  0, CELZONE_HEAP | CELZONE_MEMTRACKING, 0, FALSE);
        SetLastError(dwLastError);
    }
}

//----------------------------------------------------------
_inline void CELOG_HeapDestroy(HANDLE hHeap)
{
    if (IsCeLogZoneEnabled(CELZONE_HEAP | CELZONE_MEMTRACKING)) {
        CEL_HEAP_DESTROY cl;
    
        cl.hHeap = hHeap;
        cl.dwPID = GetCurrentProcessId();
        cl.dwTID = GetCurrentThreadId();
    
        CeLogData(TRUE, CELID_HEAP_DESTROY, &cl, sizeof(CEL_HEAP_DESTROY), 0,
                  CELZONE_HEAP | CELZONE_MEMTRACKING, 0, FALSE);
    }
}

