
// __________________________________________________________
//
//                         w2k_img.c
//            SBS Windows 2000 Image Library V1.01
//                08-27-2000 Sven B. Schreiber
//                       sbs@orgon.com
// __________________________________________________________

#define  _W2K_IMG_DLL_
#include "w2k_img.h"

// =================================================================
// DISCLAIMER
// =================================================================

/*

This software is provided "as is" and any express or implied
warranties, including, but not limited to, the implied warranties of
merchantibility and fitness for a particular purpose are disclaimed.
In no event shall the author Sven B. Schreiber be liable for any
direct, indirect, incidental, special, exemplary, or consequential
damages (including, but not limited to, procurement of substitute
goods or services; loss of use, data, or profits; or business
interruption) however caused and on any theory of liability,
whether in contract, strict liability, or tort (including negligence
or otherwise) arising in any way out of the use of this software,
even if advised of the possibility of such damage.

*/

// =================================================================
// REVISION HISTORY
// =================================================================

/*

08-09-2000 V1.00 Original version (SBS).

08-27-2000 V1.01 Upgrade (SBS).

    Added imgAnsiMatch(), imgTimeDay(), imgSymbolTable(),
    imgSymbolCompare(), imgSymbolSort(), and the complete
    imgTable*() function set. Revised the symbol file finder
    algorithm. Optimized OMAP address lookup. Added detection
    of calling conventions.

*/

// =================================================================
// GLOBAL VARIABLES
// =================================================================

HINSTANCE ghInstance = NULL;

// =================================================================
// GLOBAL STRINGS
// =================================================================

BYTE gabSymbolPath1 [] =  "_NT_SYMBOL_PATH";
BYTE gabSymbolPath2 [] =  "_NT_ALT_SYMBOL_PATH";
BYTE gabSymbols     [] =  "Symbols\\";
BYTE gabKernel      [] =  "ntoskrnl.exe";
BYTE gabDbg         [] =  ".dbg";
BYTE gabPdb         [] =  ".pdb";
BYTE gabNull        [] =  "";

WORD gawSymbolPath1 [] = L"_NT_SYMBOL_PATH";
WORD gawSymbolPath2 [] = L"_NT_ALT_SYMBOL_PATH";
WORD gawSymbols     [] = L"Symbols\\";
WORD gawKernel      [] = L"ntoskrnl.exe";
WORD gawDbg         [] = L".dbg";
WORD gawPdb         [] = L".pdb";
WORD gawNull        [] = L"";

// =================================================================
// LOWER-CASE CHARACTER TABLE
// =================================================================

BYTE LCase [] =
    {
      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
     16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
     32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
     48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
     64, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
    112,113,114,115,116,117,118,119,120,121,122, 91, 92, 93, 94, 95,
     96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
    112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
    128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
    144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,255,
    160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
    176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
    224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
    240,241,242,243,244,245,246,215,248,249,250,251,252,253,222,223,
    224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
    240,241,242,243,244,245,246,247,248,249,250,251,252,253,222,255
    };

// =================================================================
// OUTPUT FUNCTIONS
// =================================================================

INT WINAPI imgBoxA (HWND  hWnd,
                    UINT  uiType,
                    PBYTE pbCaption,
                    PBYTE pbFormat,
                    ...)
    {
    BYTE abBuffer [1024];

    wvsprintf (abBuffer, pbFormat, (PVOID) (&pbFormat+1));
    return MessageBoxA (hWnd, abBuffer, pbCaption, uiType);
    }

// -----------------------------------------------------------------

INT WINAPI imgBoxW (HWND  hWnd,
                    UINT  uiType,
                    PWORD pwCaption,
                    PWORD pwFormat,
                    ...)
    {
    WORD awBuffer [1024];

    wvsprintfW (awBuffer, pwFormat, (PVOID) (&pwFormat+1));
    return MessageBoxW (hWnd, awBuffer, pwCaption, uiType);
    }

// =================================================================
// MEMORY MANAGEMENT
// =================================================================

PVOID WINAPI imgMemoryCreate (DWORD dBytes)
    {
    return LocalAlloc (LMEM_FIXED, max (dBytes, 1));
    }

// -----------------------------------------------------------------

PVOID WINAPI imgMemoryResize (PVOID pData,
                              DWORD dBytes)
    {
    DWORD dBytes1, dBytes2;
    PVOID pData1 = NULL;

    if (pData != NULL)
        {
        if (dBytes1 = LocalSize (pData))
            {
            if ((dBytes2 = max (dBytes, 1)) != dBytes1)
                {
                if ((pData1 = LocalReAlloc (pData, dBytes2,
                                            LMEM_MOVEABLE))
                    == NULL)
                    {
                    LocalFree (pData);
                    }
                }
            else
                {
                pData1 = pData;
                }
            }
        else
            {
            LocalFree (pData);
            }
        }
    return pData1;
    }

// -----------------------------------------------------------------

PVOID WINAPI imgMemoryDestroy (PVOID pData)
    {
    if (pData != NULL)
        {
        LocalFree (pData);
        }
    return NULL;
    }

// =================================================================
// STRING PATTERN MATCHER
// =================================================================

BOOL WINAPI imgAnsiMatchA (PBYTE pbFilter,
                           PBYTE pbData,
                           BOOL  fIgnoreCase)
    {
    DWORD i = 0;
    DWORD j = 0;

    if (pbData   == NULL) return FALSE;
    if (pbFilter == NULL) return TRUE;

    while (pbFilter [i] && pbData [j])
        {
        if (pbFilter [i] != '?')
            {
            if (pbFilter [i] == '*')
                {
                i++;

                if ((pbFilter [i] != '*') &&
                    (pbFilter [i] != '?'))
                    {
                    if (pbFilter [i])
                        {
                        while (pbData [j]
                               &&
                               (!imgAnsiMatchA (pbFilter + i,
                                                pbData   + j,
                                                fIgnoreCase)))
                            {
                            j++;
                            }
                        }
                    return pbData [j] != 0;
                    }
                }
            if (fIgnoreCase
                ? LCASEA (pbFilter [i]) != LCASEA (pbData [j])
                :         pbFilter [i]  !=         pbData [j] )
                {
                return FALSE;
                }
            }
        i++;
        j++;
        }
    if (pbFilter [i] == '*') i++;
    return !(pbFilter [i] || pbData [j]);
    }

// -----------------------------------------------------------------

BOOL WINAPI imgAnsiMatchW (PWORD pwFilter,
                           PBYTE pbData,
                           BOOL  fIgnoreCase)
    {
    DWORD i = 0;
    DWORD j = 0;

    if (pbData   == NULL) return FALSE;
    if (pwFilter == NULL) return TRUE;

    while (pwFilter [i] && pbData [j])
        {
        if (pwFilter [i] != '?')
            {
            if (pwFilter [i] == '*')
                {
                i++;

                if ((pwFilter [i] != '*') &&
                    (pwFilter [i] != '?'))
                    {
                    if (pwFilter [i])
                        {
                        while (pbData [j]
                               &&
                               (!imgAnsiMatchW (pwFilter + i,
                                                pbData   + j,
                                                fIgnoreCase)))
                            {
                            j++;
                            }
                        }
                    return pbData [j] != 0;
                    }
                }
            if (fIgnoreCase
                ? LCASEW (pwFilter [i]) != LCASEA (pbData [j])
                :         pwFilter [i]  !=         pbData [j] )
                {
                return FALSE;
                }
            }
        i++;
        j++;
        }
    if (pwFilter [i] == '*') i++;
    return !(pwFilter [i] || pbData [j]);
    }

// =================================================================
// DATE/TIME CONVERSION
// =================================================================

DWORD adDaysPerMonth [] = {31,28,31,30,31,30,31,31,30,31,30,31};

// -----------------------------------------------------------------

IMG_TIME WINAPI imgTimeNow (BOOL fLocal)
    {
    SYSTEMTIME st;
    IMG_TIME   it;

    if (fLocal) GetLocalTime  (&st);
    else        GetSystemTime (&st);

    it.wYear      = (WORD) st.wYear;
    it.bMonth     = (BYTE) st.wMonth;
    it.bDay       = (BYTE) st.wDay;
    it.bHour      = (BYTE) st.wHour;
    it.bMinute    = (BYTE) st.wMinute;
    it.bSecond    = (BYTE) st.wSecond;
    it.bDayOfWeek =
        (BYTE) (((((imgTimePack (it) / 60) / 60) / 24) + 4) % 7);

    return it;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgTimePack (IMG_TIME it)
    {
    DWORD dYear, dMonth, dDay, i;
    DWORD dTime = 0;

    if (it.wYear >= 1970)
        {
        dMonth = (it.bMonth ? it.bMonth-1 : 0);

        dYear  = (DWORD) it.wYear - 1600 + (dMonth / 12);
        dMonth = dMonth % 12;
        dDay   = (dYear / 400) * DAYS_PER_400_YEARS;

        for (i = 0; i < dMonth; i++)
            {
            dDay += adDaysPerMonth [i];
            }
        if ((dMonth > 1) && (!(dYear % 4)) &&
            ((dYear % 100) || (!(dYear % 400))))
            {
            dDay += 1;
            }
        if (it.bDay)
            {
            dDay += it.bDay - 1;
            }
        if (dYear = dYear % 400)
            {
            dDay += ((dYear / 100) * (DAYS_PER_100_YEARS-1)) + 1;

            if (dYear = dYear % 100)
                {
                dDay += ((dYear / 4) * DAYS_PER_4_YEARS) - 1;

                if (dYear = dYear % 4)
                    {
                    dDay += (dYear * DAYS_PER_YEAR) + 1;
                    }
                }
            }
        dDay -= DAYS_1600_TO_1970;

        dTime  = (dDay               * 60 * 60 * 24) +
                 ((DWORD) it.bHour   * 60 * 60     ) +
                 ((DWORD) it.bMinute * 60          ) +
                 ((DWORD) it.bSecond               );
        }
    return dTime;
    }

// -----------------------------------------------------------------

IMG_TIME WINAPI imgTimeUnpack (DWORD dTime)
    {
    IMG_TIME it;

    DWORD dDaySince1600, dDayIn100Years, dDayIn4Years;
    DWORD d400Years, d100In400Years, d4In100Years, d1In4Years;
    DWORD dDay, dMonth, dYear, dDaysPerMonth;
    BOOL  fLeap;

    it.bSecond    = (BYTE) ((dTime        ) % 60);
    it.bMinute    = (BYTE) ((dTime /    60) % 60);
    it.bHour      = (BYTE) ((dTime /  3600) % 24);
    dDaySince1600 =         (dTime / 86400) + DAYS_1600_TO_1970;

    dDayIn100Years = dDaySince1600 % DAYS_PER_400_YEARS;
    d400Years      = dDaySince1600 / DAYS_PER_400_YEARS;
    d100In400Years = 0;

    while (dDayIn100Years >= DAYS_PER_100_YEARS)
        {
        dDayIn100Years -= (DAYS_PER_100_YEARS-1);
        d100In400Years++;
        }
    dDayIn4Years = dDayIn100Years % DAYS_PER_4_YEARS;
    d4In100Years = dDayIn100Years / DAYS_PER_4_YEARS;

    if (dDayIn4Years)
        {
        dDay       = (dDayIn4Years-1) % DAYS_PER_YEAR;
        d1In4Years = (dDayIn4Years-1) / DAYS_PER_YEAR;
        if (!d1In4Years) dDay++;
        }
    else
        {
        dDay       = 0;
        d1In4Years = 0;
        }
    fLeap = (d1In4Years ? FALSE
                        : (d4In100Years ? TRUE
                                        : !d100In400Years));

    for (dMonth = 0; dMonth < 12; dMonth++)
        {
        dDaysPerMonth = adDaysPerMonth [dMonth];
        if ((dMonth == 2) && fLeap) dDaysPerMonth++;
        if (dDay < dDaysPerMonth) break;
        dDay -= dDaysPerMonth;
        }
    dYear = (d1In4Years          ) +
            (d4In100Years   *   4) +
            (d100In400Years * 100) +
            (d400Years      * 400) + 1600;

    it.bDay       = (BYTE) (dDay + 1);
    it.bMonth     = (BYTE) (dMonth + 1);
    it.wYear      = (WORD) dYear;
    it.bDayOfWeek = (BYTE) ((dDaySince1600 + 6) % 7);
    return it;
    }

// -----------------------------------------------------------------

PBYTE WINAPI imgTimeDayA (IMG_TIME it)
    {
    PBYTE pbDay = NULL;

    switch (it.bDayOfWeek % 7)
        {
        case 0: pbDay = "Sunday";    break;
        case 1: pbDay = "Monday";    break;
        case 2: pbDay = "Tuesday";   break;
        case 3: pbDay = "Wednesday"; break;
        case 4: pbDay = "Thursday";  break;
        case 5: pbDay = "Friday";    break;
        case 6: pbDay = "Saturday";  break;
        }
    return pbDay;
    }

// -----------------------------------------------------------------

PWORD WINAPI imgTimeDayW (IMG_TIME it)
    {
    PWORD pwDay = NULL;

    switch (it.bDayOfWeek % 7)
        {
        case 0: pwDay = L"Sunday";    break;
        case 1: pwDay = L"Monday";    break;
        case 2: pwDay = L"Tuesday";   break;
        case 3: pwDay = L"Wednesday"; break;
        case 4: pwDay = L"Thursday";  break;
        case 5: pwDay = L"Friday";    break;
        case 6: pwDay = L"Saturday";  break;
        }
    return pwDay;
    }

// =================================================================
// FILE PATH MANAGEMENT
// =================================================================

DWORD WINAPI imgPathRootA (PBYTE pbPath)
    {
    DWORD dRoot = 0;

    if ((pbPath != NULL) && pbPath [0])
        {
        if (pbPath [0] == '\\')
            {
            if (pbPath [1] == '\\')
                {
                for (dRoot = 2;
                     pbPath [dRoot] && (pbPath [dRoot] != '\\');
                     dRoot++);
                }
            }
        else
            {
            if (pbPath [1] == ':') dRoot = 2;
            }
        }
    return dRoot;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathRootW (PWORD pwPath)
    {
    DWORD dRoot = 0;

    if ((pwPath != NULL) && pwPath [0])
        {
        if (pwPath [0] == '\\')
            {
            if (pwPath [1] == '\\')
                {
                for (dRoot = 2;
                     pwPath [dRoot] && (pwPath [dRoot] != '\\');
                     dRoot++);
                }
            }
        else
            {
            if (pwPath [1] == ':') dRoot = 2;
            }
        }
    return dRoot;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathNameA (PBYTE  pbPath,
                           PDWORD pdExtension)
    {
    DWORD dRoot, dEnd;
    DWORD dExtension = 0;
    DWORD dName      = 0;

    if (pbPath != NULL)
        {
        dRoot = imgPathRootA (pbPath);
        dEnd  = dRoot + lstrlenA (pbPath + dRoot);

        for (dName = dEnd;
             (dName > dRoot) && (pbPath [dName-1] != '\\')
                             && (pbPath [dName-1] != ':' );
             dName--);

        for (dExtension = dEnd;
             (dExtension > dName) && (pbPath [dExtension-1] != '.');
             dExtension--);

        dExtension = (dExtension == dName ? dEnd : dExtension - 1);
        }
    if (pdExtension != NULL) *pdExtension = dExtension;
    return dName;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathNameW (PWORD  pwPath,
                           PDWORD pdExtension)
    {
    DWORD dRoot, dEnd;
    DWORD dExtension = 0;
    DWORD dName      = 0;

    if (pwPath != NULL)
        {
        dRoot = imgPathRootW (pwPath);
        dEnd  = dRoot + lstrlenW (pwPath + dRoot);

        for (dName = dEnd;
             (dName > dRoot) && (pwPath [dName-1] != '\\')
                             && (pwPath [dName-1] != ':' );
             dName--);

        for (dExtension = dEnd;
             (dExtension > dName) && (pwPath [dExtension-1] != '.');
             dExtension--);

        dExtension = (dExtension == dName ? dEnd : dExtension - 1);
        }
    if (pdExtension != NULL) *pdExtension = dExtension;
    return dName;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathCanonicalA (PBYTE pbPath,   // NULL: current dir
                                PBYTE pbBuffer, // can be == pbPath
                                DWORD dBuffer)
    {
    BYTE  abBuffer [MAX_PATH];
    PBYTE pb;
    DWORD n = 0;

    if ((pbBuffer != NULL) && dBuffer)
        {
        n = (pbPath == NULL
             ? GetCurrentDirectoryA (MAX_PATH, abBuffer)
             : (pbPath [0]
                ? GetFullPathNameA (pbPath, MAX_PATH, abBuffer, &pb)
                : 0));

        if (n && (n < MAX_PATH))
            {
            if (abBuffer [n-1] != '\\')
                {
                if (n+1 < MAX_PATH)
                    {
                    abBuffer [n++] = '\\';
                    }
                else
                    {
                    n = 0;
                    }
                }
            }
        else
            {
            n = 0;
            }
        if (n >= dBuffer) n = 0;
        abBuffer [n] = 0;
        lstrcpyA (pbBuffer, abBuffer);
        }
    return n;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathCanonicalW (PWORD pwPath,   // NULL: current dir
                                PWORD pwBuffer, // can be == pwPath
                                DWORD dBuffer)
    {
    WORD  awBuffer [MAX_PATH];
    PWORD pw;
    DWORD n = 0;

    if ((pwBuffer != NULL) && dBuffer)
        {
        n = (pwPath == NULL
             ? GetCurrentDirectoryW (MAX_PATH, awBuffer)
             : (pwPath [0]
                ? GetFullPathNameW (pwPath, MAX_PATH, awBuffer, &pw)
                : 0));

        if (n && (n < MAX_PATH))
            {
            if (awBuffer [n-1] != '\\')
                {
                if (n+1 < MAX_PATH)
                    {
                    awBuffer [n++] = '\\';
                    }
                else
                    {
                    n = 0;
                    }
                }
            }
        else
            {
            n = 0;
            }
        if (n >= dBuffer) n = 0;
        awBuffer [n] = 0;
        lstrcpyW (pwBuffer, awBuffer);
        }
    return n;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathCurrentA (PBYTE pbBuffer,
                              DWORD dBuffer)
    {
    return imgPathCanonicalA (NULL, pbBuffer, dBuffer);
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathCurrentW (PWORD pwBuffer,
                              DWORD dBuffer)
    {
    return imgPathCanonicalW (NULL, pwBuffer, dBuffer);
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathWindowsA (PBYTE pbBuffer,
                              DWORD dBuffer)
    {
    BYTE  abBuffer [MAX_PATH];
    DWORD n;

    n = GetWindowsDirectoryA (abBuffer, MAX_PATH);
    if (n >= MAX_PATH) n = 0;
    abBuffer [n] = 0;
    return imgPathCanonicalA (abBuffer, pbBuffer, dBuffer);
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathWindowsW (PWORD pwBuffer,
                              DWORD dBuffer)
    {
    WORD  awBuffer [MAX_PATH];
    DWORD n;

    n = GetWindowsDirectoryW (awBuffer, MAX_PATH);
    if (n >= MAX_PATH) n = 0;
    awBuffer [n] = 0;
    return imgPathCanonicalW (awBuffer, pwBuffer, dBuffer);
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathVariableA (PBYTE pbVariable,
                               PBYTE pbBuffer,
                               DWORD dBuffer,
                               DWORD dIndex)
    {
    BYTE  abBuffer [MAX_PATH_EX];
    DWORD i, j, k;
    DWORD n = 0;

    n = GetEnvironmentVariableA (pbVariable, abBuffer, MAX_PATH_EX);
    if (n >= MAX_PATH_EX) n = 0;

    for (i = j = 0; (i < dIndex) && (j < n); i++)
        {
        while ((j < n) && (abBuffer [j++] != ';'));
        }
    while ((j < n) && (abBuffer [j] == ' ')) j++;
    for (k = j; (k < n) && (abBuffer [k] != ';'); k++);
    while ((k > j) && (abBuffer [k-1] == ' ')) k--;

    if (j < n)
        {
        i = 0;

        if (k - j < MAX_PATH)
            {
            if (j)
                {
                while (j < k) abBuffer [i++] = abBuffer [j++];
                }
            else
                {
                i = k - j;
                }
            }
        abBuffer [i] = 0;

        n = imgPathCanonicalA (abBuffer, pbBuffer, dBuffer);
        }
    else
        {
        if ((pbBuffer != NULL) && dBuffer) pbBuffer [0] = 0;
        n = -1;
        }
    return n;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathVariableW (PWORD pwVariable,
                               PWORD pwBuffer,
                               DWORD dBuffer,
                               DWORD dIndex)
    {
    WORD  awBuffer [MAX_PATH_EX];
    DWORD i, j, k;
    DWORD n = 0;

    n = GetEnvironmentVariableW (pwVariable, awBuffer, MAX_PATH_EX);
    if (n >= MAX_PATH_EX) n = 0;

    for (i = j = 0; (i < dIndex) && (j < n); i++)
        {
        while ((j < n) && (awBuffer [j++] != ';'));
        }
    while ((j < n) && (awBuffer [j] == ' ')) j++;
    for (k = j; (k < n) && (awBuffer [k] != ';'); k++);
    while ((k > j) && (awBuffer [k-1] == ' ')) k--;

    if (j < n)
        {
        i = 0;

        if (k - j < MAX_PATH)
            {
            if (j)
                {
                while (j < k) awBuffer [i++] = awBuffer [j++];
                }
            else
                {
                i = k - j;
                }
            }
        awBuffer [i] = 0;

        n = imgPathCanonicalW (awBuffer, pwBuffer, dBuffer);
        }
    else
        {
        if ((pwBuffer != NULL) && dBuffer) pwBuffer [0] = 0;
        n = -1;
        }
    return n;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathEnumerateA (IMG_CALLBACKA CallbackA,
                                PBYTE         pbModule,
                                PVOID         pContext)
    {
    BYTE  abPath [MAX_PATH];
    DWORD i, j;
    DWORD n = 0;

    if (CallbackA != NULL)
        {
        if ((pbModule != NULL) &&
            ((i = imgPathNameA (pbModule, NULL)) < MAX_PATH))
            {
            lstrcpynA (abPath, pbModule, i+1);

            if (j = imgPathCanonicalA (abPath, abPath, MAX_PATH))
                {
                if (n = CallbackA (pbModule, abPath, j, pContext))
                    return n;
                }
            }
        if (j = imgPathCurrentA (abPath, MAX_PATH))
            {
            if (n = CallbackA (pbModule, abPath, j, pContext))
                return n;
            }
        i = 0;
        while ((j = imgPathVariableA (gabSymbolPath1,
                                      abPath, MAX_PATH, i++))
               != -1)
            {
            if (j)
                {
                if (n = CallbackA (pbModule, abPath, j, pContext))
                    return n;
                }
            }
        i = 0;
        while ((j = imgPathVariableA (gabSymbolPath2,
                                      abPath, MAX_PATH, i++))
               != -1)
            {
            if (j)
                {
                if (n = CallbackA (pbModule, abPath, j, pContext))
                    return n;
                }
            }
        if (j = imgPathWindowsA (abPath, MAX_PATH))
            {
            if (n = CallbackA (pbModule, abPath, j, pContext))
                return n;
            }
        n = CallbackA (pbModule, NULL, 0, pContext);
        }
    return n;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathEnumerateW (IMG_CALLBACKW CallbackW,
                                PWORD         pwModule,
                                PVOID         pContext)
    {
    WORD  awPath [MAX_PATH];
    DWORD i, j;
    DWORD n = 0;

    if (CallbackW != NULL)
        {
        if ((pwModule != NULL) &&
            ((i = imgPathNameW (pwModule, NULL)) < MAX_PATH))
            {
            lstrcpynW (awPath, pwModule, i+1);

            if (j = imgPathCanonicalW (awPath, awPath, MAX_PATH))
                {
                if (n = CallbackW (pwModule, awPath, j, pContext))
                    return n;
                }
            }
        if (j = imgPathCurrentW (awPath, MAX_PATH))
            {
            if (n = CallbackW (pwModule, awPath, j, pContext))
                return n;
            }
        i = 0;
        while ((j = imgPathVariableW (gawSymbolPath1,
                                      awPath, MAX_PATH, i++))
               != -1)
            {
            if (j)
                {
                if (n = CallbackW (pwModule, awPath, j, pContext))
                    return n;
                }
            }
        i = 0;
        while ((j = imgPathVariableW (gawSymbolPath2,
                                      awPath, MAX_PATH, i++))
               != -1)
            {
            if (j)
                {
                if (n = CallbackW (pwModule, awPath, j, pContext))
                    return n;
                }
            }
        if (j = imgPathWindowsW (awPath, MAX_PATH))
            {
            if (n = CallbackW (pwModule, awPath, j, pContext))
                return n;
            }
        n = CallbackW (pwModule, NULL, 0, pContext);
        }
    return n;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathSymbolsA (PBYTE pbModule,   // NULL: ntoskrnl
                              PBYTE pbExtension,// NULL: .dbg
                              PBYTE pbPath,     // NULL: current dir
                              PBYTE pbBuffer,   // can be == pbPath
                              DWORD dBuffer,
                              BOOL  fSymbols)
    {
    BYTE  abBuffer [MAX_PATH];
    PBYTE pbModule1, pbExtension1, pbSymbols;
    DWORD dNext, dName, dExtension, n1, n2, n3, n4;
    DWORD n = 0;

    pbModule1    = (pbModule    != NULL ? pbModule    : gabKernel);
    pbExtension1 = (pbExtension != NULL ? pbExtension : gabDbg);
    pbSymbols    = (fSymbols            ? gabSymbols  : gabNull);

    dNext = imgPathCanonicalA (pbPath, abBuffer, MAX_PATH);
    dName = imgPathNameA (pbModule1, &dExtension);

    if (dNext && (pbModule1 [dExtension  ] == '.')
              &&  pbModule1 [dExtension+1]
        &&
        (dNext + (n1 = lstrlenA (pbSymbols))
               + (n2 = lstrlenA (pbModule1 + (dExtension+1))) + 1
               + (n3 = dExtension - dName)
               + (n4 = lstrlenA (pbExtension1))
         < MAX_PATH))
        {
        n = dNext;

        lstrcpyA (abBuffer + n, pbSymbols);
        n += n1;

        lstrcpyA (abBuffer + n, pbModule1 + (dExtension+1));
        n += n2;
        abBuffer [n++] = '\\';

        lstrcpynA (abBuffer + n, pbModule1 + dName, n3 + 1);
        n += n3;

        lstrcpyA (abBuffer + n, pbExtension1);
        n += n4;
        }
    if ((pbBuffer != NULL) && dBuffer)
        {
        if (n >= dBuffer) n = 0;
        abBuffer [n] = 0;
        lstrcpyA (pbBuffer, abBuffer);
        }
    return n;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathSymbolsW (PWORD pwModule,   // NULL: ntoskrnl
                              PWORD pwExtension,// NULL: .dbg
                              PWORD pwPath,     // NULL: current dir
                              PWORD pwBuffer,   // can be == pwPath
                              DWORD dBuffer,
                              BOOL  fSymbols)
    {
    WORD  awBuffer [MAX_PATH];
    PWORD pwModule1, pwExtension1, pwSymbols;
    DWORD dNext, dName, dExtension, n1, n2, n3, n4;
    DWORD n = 0;

    pwModule1    = (pwModule    != NULL ? pwModule    : gawKernel);
    pwExtension1 = (pwExtension != NULL ? pwExtension : gawDbg);
    pwSymbols    = (fSymbols            ? gawSymbols  : gawNull);

    dNext = imgPathCanonicalW (pwPath, awBuffer, MAX_PATH);
    dName = imgPathNameW (pwModule1, &dExtension);

    if (dNext && (pwModule1 [dExtension  ] == '.')
              &&  pwModule1 [dExtension+1]
        &&
        (dNext + (n1 = lstrlenW (pwSymbols))
               + (n2 = lstrlenW (pwModule1 + (dExtension+1))) + 1
               + (n3 = dExtension - dName)
               + (n4 = lstrlenW (pwExtension1))
         < MAX_PATH))
        {
        n = dNext;

        lstrcpyW (awBuffer + n, pwSymbols);
        n += n1;

        lstrcpyW (awBuffer + n, pwModule1 + (dExtension+1));
        n += n2;
        awBuffer [n++] = '\\';

        lstrcpynW (awBuffer + n, pwModule1 + dName, n3 + 1);
        n += n3;

        lstrcpyW (awBuffer + n, pwExtension1);
        n += n4;
        }
    if ((pwBuffer != NULL) && dBuffer)
        {
        if (n >= dBuffer) n = 0;
        awBuffer [n] = 0;
        lstrcpyW (pwBuffer, awBuffer);
        }
    return n;
    }

// -----------------------------------------------------------------

DWORD CALLBACK imgPathCallbackA (PBYTE        pbModule,
                                 PBYTE        pbPath,
                                 DWORD        dPath,
                                 PIMG_CONTEXT pic)
    {
    BYTE  abBuffer [MAX_PATH];
    PBYTE pbBuffer, pbExtension;
    DWORD dBuffer;
    DWORD n = 0;

    if (pic != NULL)
        {
        pbExtension = pic->pbExtension;
        pbBuffer    = pic->pbBuffer;
        dBuffer     = pic->dBuffer;
        }
    else
        {
        pbExtension = NULL;
        pbBuffer    = NULL;
        dBuffer     = 0;
        }
    if (pbPath != NULL)
        {
        if (((n = imgPathSymbolsA (pbModule, pbExtension,
                                   pbPath, abBuffer, MAX_PATH,
                                   TRUE))
             &&
             imgFileTestA (abBuffer))
            ||
            ((n = imgPathSymbolsA (pbModule, pbExtension,
                                   pbPath, abBuffer, MAX_PATH,
                                   FALSE))
             &&
             imgFileTestA (abBuffer)))
            {
            if ((pbBuffer != NULL) && dBuffer)
                {
                if (n >= dBuffer)
                    {
                    abBuffer [0] = 0;
                    n = -1;
                    }
                lstrcpyA (pbBuffer, abBuffer);
                }
            }
        else
            {
            n = 0;
            }
        }
    else
        {
        if ((pbBuffer != NULL) && dBuffer) pbBuffer [0] = 0;
        }
    return n;
    }

// -----------------------------------------------------------------

DWORD CALLBACK imgPathCallbackW (PWORD        pwModule,
                                 PWORD        pwPath,
                                 DWORD        dPath,
                                 PIMG_CONTEXT pic)
    {
    WORD  awBuffer [MAX_PATH];
    PWORD pwBuffer, pwExtension;
    DWORD dBuffer;
    DWORD n = 0;

    if (pic != NULL)
        {
        pwExtension = pic->pwExtension;
        pwBuffer    = pic->pwBuffer;
        dBuffer     = pic->dBuffer;
        }
    else
        {
        pwExtension = NULL;
        pwBuffer    = NULL;
        dBuffer     = 0;
        }
    if (pwPath != NULL)
        {
        if (((n = imgPathSymbolsW (pwModule, pwExtension,
                                   pwPath, awBuffer, MAX_PATH,
                                   TRUE))
             &&
             imgFileTestW (awBuffer))
            ||
            ((n = imgPathSymbolsW (pwModule, pwExtension,
                                   pwPath, awBuffer, MAX_PATH,
                                   FALSE))
             &&
             imgFileTestW (awBuffer)))
            {
            if ((pwBuffer != NULL) && dBuffer)
                {
                if (n >= dBuffer)
                    {
                    awBuffer [0] = 0;
                    n = -1;
                    }
                lstrcpyW (pwBuffer, awBuffer);
                }
            }
        else
            {
            n = 0;
            }
        }
    else
        {
        if ((pwBuffer != NULL) && dBuffer) pwBuffer [0] = 0;
        }
    return n;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathSymbolsExA (PBYTE pbModule,
                                PBYTE pbExtension,
                                PBYTE pbBuffer,
                                DWORD dBuffer)
    {
    IMG_CONTEXT ic;
    DWORD       n = 0;

    ic.pbExtension = pbExtension;
    ic.pbBuffer    = pbBuffer;
    ic.dBuffer     = dBuffer;

    n = imgPathEnumerateA (imgPathCallbackA, pbModule, &ic);
    return (n != -1 ? n : 0);
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathSymbolsExW (PWORD pwModule,
                                PWORD pwExtension,
                                PWORD pwBuffer,
                                DWORD dBuffer)
    {
    IMG_CONTEXT ic;
    DWORD       n = 0;

    ic.pwExtension = pwExtension;
    ic.pwBuffer    = pwBuffer;
    ic.dBuffer     = dBuffer;

    n = imgPathEnumerateW (imgPathCallbackW, pwModule, &ic);
    return (n != -1 ? n : 0);
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathDbgA (PBYTE pbModule,
                          PBYTE pbBuffer,
                          DWORD dBuffer)
    {
    return imgPathSymbolsExA (pbModule, gabDbg, pbBuffer, dBuffer);
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathDbgW (PWORD pwModule,
                          PWORD pwBuffer,
                          DWORD dBuffer)
    {
    return imgPathSymbolsExW (pwModule, gawDbg, pwBuffer, dBuffer);
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathPdbA (PBYTE pbModule,
                          PBYTE pbBuffer,
                          DWORD dBuffer)
    {
    return imgPathSymbolsExA (pbModule, gabPdb, pbBuffer, dBuffer);
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPathPdbW (PWORD pwModule,
                          PWORD pwBuffer,
                          DWORD dBuffer)
    {
    return imgPathSymbolsExW (pwModule, gawPdb, pwBuffer, dBuffer);
    }

// =================================================================
// FILE MANAGEMENT
// =================================================================

HANDLE WINAPI imgFileClose (HANDLE hf)
    {
    if (hf != INVALID_HANDLE_VALUE) CloseHandle (hf);
    return INVALID_HANDLE_VALUE;
    }

// -----------------------------------------------------------------

HANDLE WINAPI imgFileOpenA (PBYTE pbPath)
    {
    HANDLE hf = INVALID_HANDLE_VALUE;

    if ((pbPath != NULL) && pbPath [0])
        {
        hf = CreateFileA (pbPath, GENERIC_READ,
                          FILE_SHARE_READ, NULL, OPEN_EXISTING,
                          FILE_FLAG_SEQUENTIAL_SCAN,
                          NULL);
        }
    return hf;
    }

// -----------------------------------------------------------------

HANDLE WINAPI imgFileOpenW (PWORD pwPath)
    {
    HANDLE hf = INVALID_HANDLE_VALUE;

    if ((pwPath != NULL) && pwPath [0])
        {
        hf = CreateFileW (pwPath, GENERIC_READ,
                          FILE_SHARE_READ, NULL, OPEN_EXISTING,
                          FILE_FLAG_SEQUENTIAL_SCAN,
                          NULL);
        }
    return hf;
    }

// -----------------------------------------------------------------

HANDLE WINAPI imgFileNewA (PBYTE pbPath)
    {
    HANDLE hf = INVALID_HANDLE_VALUE;

    if ((pbPath != NULL) && pbPath [0])
        {
        hf = CreateFileA (pbPath, GENERIC_READ | GENERIC_WRITE,
                          FILE_SHARE_READ, NULL, CREATE_ALWAYS,
                          FILE_FLAG_SEQUENTIAL_SCAN |
                          FILE_ATTRIBUTE_NORMAL,
                          NULL);
        }
    return hf;
    }

// -----------------------------------------------------------------

HANDLE WINAPI imgFileNewW (PWORD pwPath)
    {
    HANDLE hf = INVALID_HANDLE_VALUE;

    if ((pwPath != NULL) && pwPath [0])
        {
        hf = CreateFileW (pwPath, GENERIC_READ | GENERIC_WRITE,
                          FILE_SHARE_READ, NULL, CREATE_ALWAYS,
                          FILE_FLAG_SEQUENTIAL_SCAN |
                          FILE_ATTRIBUTE_NORMAL,
                          NULL);
        }
    return hf;
    }

// -----------------------------------------------------------------

BOOL WINAPI imgFileTestA (PBYTE pbPath)
    {
    HANDLE           hff;
    WIN32_FIND_DATAA wfd;
    BOOL             fOk = FALSE;

    if ((hff = FindFirstFileA (pbPath, &wfd))
        != INVALID_HANDLE_VALUE)
        {
        fOk = !(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
        FindClose (hff);
        }
    return fOk;
    }

// -----------------------------------------------------------------

BOOL WINAPI imgFileTestW (PWORD pwPath)
    {
    HANDLE           hff;
    WIN32_FIND_DATAW wfd;
    BOOL             fOk = FALSE;

    if ((hff = FindFirstFileW (pwPath, &wfd))
        != INVALID_HANDLE_VALUE)
        {
        fOk = !(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
        FindClose (hff);
        }
    return fOk;
    }

// -----------------------------------------------------------------

PVOID WINAPI imgFileLoadA (PBYTE  pbPath,
                           PDWORD pdSize)
    {
    HANDLE hf;
    DWORD  n;
    DWORD  dOffset = (pdSize != NULL ? *pdSize : 0);
    DWORD  dSize   = 0;
    PBYTE  pbData  = NULL;

    if ((hf = imgFileOpenA (pbPath)) != INVALID_HANDLE_VALUE)
        {
        if ((dSize = GetFileSize (hf, NULL)) != INVALID_FILE_SIZE)
            {
            if ((dOffset + dSize + 1 > dSize)
                &&
                ((pbData = imgMemoryCreate (dOffset + dSize + 1))
                 != NULL))
                {
                n = 0;

                if ((!dSize)
                    ||
                    (ReadFile (hf, pbData + dOffset, dSize,
                               &n, NULL) &&
                     (dSize == n)))
                    {
                    if (dOffset) ZeroMemory (pbData, dOffset);
                    pbData [dOffset + dSize] = 0;
                    }
                else
                    {
                    pbData = imgMemoryDestroy (pbData);
                    }
                }
            }
        else
            {
            dSize = 0;
            }
        imgFileClose (hf);
        }
    if (pdSize != NULL) *pdSize = dSize;
    return pbData;
    }

// -----------------------------------------------------------------

PVOID WINAPI imgFileLoadW (PWORD  pwPath,
                           PDWORD pdSize)
    {
    HANDLE hf;
    DWORD  n;
    DWORD  dOffset = (pdSize != NULL ? *pdSize : 0);
    DWORD  dSize   = 0;
    PBYTE  pbData  = NULL;

    if ((hf = imgFileOpenW (pwPath)) != INVALID_HANDLE_VALUE)
        {
        if ((dSize = GetFileSize (hf, NULL)) != INVALID_FILE_SIZE)
            {
            if ((dOffset + dSize + 1 > dSize)
                &&
                ((pbData = imgMemoryCreate (dOffset + dSize + 1))
                 != NULL))
                {
                n = 0;

                if ((!dSize)
                    ||
                    (ReadFile (hf, pbData + dOffset, dSize,
                               &n, NULL) &&
                     (dSize == n)))
                    {
                    if (dOffset) ZeroMemory (pbData, dOffset);
                    pbData [dOffset + dSize] = 0;
                    }
                else
                    {
                    pbData = imgMemoryDestroy (pbData);
                    }
                }
            }
        else
            {
            dSize = 0;
            }
        imgFileClose (hf);
        }
    if (pdSize != NULL) *pdSize = dSize;
    return pbData;
    }

// -----------------------------------------------------------------

BOOL WINAPI imgFileSaveA (PBYTE pbPath,
                          PVOID pData,
                          DWORD dData)
    {
    HANDLE hf;
    DWORD  n;
    BOOL   fOk = FALSE;

    if ((hf = imgFileNewA (pbPath)) != INVALID_HANDLE_VALUE)
        {
        n = 0;
        if ((pData != NULL) && dData)
            {
            if (!WriteFile (hf, pData, dData, &n, NULL)) n = 0;
            }
        fOk = (n == dData) && SetEndOfFile (hf);
        imgFileClose (hf);

        if (!fOk) DeleteFileA (pbPath);
        }
    return fOk;
    }

// -----------------------------------------------------------------

BOOL WINAPI imgFileSaveW (PWORD pwPath,
                          PVOID pData,
                          DWORD dData)
    {
    HANDLE hf;
    DWORD  n;
    BOOL   fOk = FALSE;

    if ((hf = imgFileNewW (pwPath)) != INVALID_HANDLE_VALUE)
        {
        n = 0;
        if ((pData != NULL) && dData)
            {
            if (!WriteFile (hf, pData, dData, &n, NULL)) n = 0;
            }
        fOk = (n == dData) && SetEndOfFile (hf);
        imgFileClose (hf);

        if (!fOk) DeleteFileW (pwPath);
        }
    return fOk;
    }

// =================================================================
// CodeView DATA MANAGEMENT
// =================================================================

PCV_ENTRY WINAPI imgCvEntry (PCV_NB09 pc09,
                             DWORD    dType,
                             DWORD    dIndex)
    {
    DWORD     i, j;
    PCV_ENTRY pce = NULL;

    if ((pc09 != NULL) &&
        (pc09->Header.Signature.dVersion == CV_SIGNATURE_NB09))
        {
        for (i = j = 0; i < pc09->Directory.dEntries; i++)
            {
            if ((pc09->Entries [i].wSubSectionType == dType) &&
                (j++ == dIndex))
                {
                pce = pc09->Entries + i;
                break;
                }
            }
        }
    return pce;
    }

// -----------------------------------------------------------------

PCV_MODULE WINAPI imgCvModule (PCV_NB09 pc09,
                               DWORD    dIndex,
                               PDWORD   pdSize)
    {
    PCV_ENTRY  pce;
    DWORD      dSize = 0;
    PCV_MODULE pcm   = NULL;

    if ((pce = imgCvEntry (pc09, sstModule, dIndex)) != NULL)
        {
        pcm = (PCV_MODULE)
              ((PBYTE) pc09 + pce->lSubSectionOffset);

        dSize = pce->dSubSectionSize;
        }
    if (pdSize != NULL) *pdSize = dSize;
    return pcm;
    }

// -----------------------------------------------------------------

PCV_PUBSYM WINAPI imgCvSymbols (PCV_NB09 pc09,
                                PDWORD   pdCount,
                                PDWORD   pdSize)
    {
    PCV_ENTRY  pce;
    PCV_PUBSYM pcp1;
    DWORD      i;
    DWORD      dCount = 0;
    DWORD      dSize  = 0;
    PCV_PUBSYM pcp    = NULL;

    if ((pce = imgCvEntry (pc09, sstGlobalPub, 0)) != NULL)
        {
        pcp = CV_PUBSYM_DATA ((PBYTE) pc09
                              + pce->lSubSectionOffset);

        dSize = pce->dSubSectionSize;

        for (i  = 0; dSize - i >= CV_PUBSYM_;
             i += CV_PUBSYM_SIZE (pcp1))
            {
            pcp1 = (PCV_PUBSYM) ((PBYTE) pcp + i);
            if (dSize - i < CV_PUBSYM_SIZE (pcp1)) break;
            if (pcp1->Header.wRecordType == CV_PUB32) dCount++;
            }
        }
    if (pdCount != NULL) *pdCount = dCount;
    if (pdSize  != NULL) *pdSize  = dSize;
    return pcp;
    }

// -----------------------------------------------------------------

PCV_SEGMAP WINAPI imgCvSegments (PCV_NB09 pc09,
                                 PDWORD   pdCount)
    {
    PCV_ENTRY  pce;
    DWORD      dCount = 0;
    PCV_SEGMAP pcs    = NULL;

    if ((pce = imgCvEntry (pc09, sstSegMap, 0)) != NULL)
        {
        pcs = (PCV_SEGMAP)
              ((PBYTE) pc09 + pce->lSubSectionOffset);

        dCount = pcs->wTotal;
        }
    if (pdCount != NULL) *pdCount = dCount;
    return pcs;
    }

// -----------------------------------------------------------------

PVOID WINAPI imgCvPdbA (PCV_NB10 pc10,
                        PBYTE    pbPath,
                        PDWORD   pdSize)
    {
    BYTE  abPath [MAX_PATH];
    DWORD dName, i, n;
    DWORD dSize = 0;
    PVOID pData = NULL;

    if ((pc10 != NULL) &&
        (pc10->Header.Signature.dVersion == CV_SIGNATURE_NB10))
        {
        dName = imgPathNameA (pbPath, NULL);

        if (dName + lstrlenA (pc10->abPdbName) < MAX_PATH)
            {
            for (i = n = 0; i < dName; i++)
                {
                abPath [n++] = pbPath [i];
                }
            for (i = 0; pc10->abPdbName [i]; i++)
                {
                abPath [n++] = pc10->abPdbName [i];
                }
            abPath [n] = 0;

            dSize = (pdSize != NULL ? *pdSize : 0);
            pData = imgPdbLoadA (abPath, &dSize);
            }
        }
    if (pdSize != NULL) *pdSize = dSize;
    return pData;
    }

// -----------------------------------------------------------------

PVOID WINAPI imgCvPdbW (PCV_NB10 pc10,
                        PWORD    pwPath,
                        PDWORD   pdSize)
    {
    WORD  awPath [MAX_PATH];
    DWORD dName, i, n;
    DWORD dSize = 0;
    PVOID pData = NULL;

    if ((pc10 != NULL) &&
        (pc10->Header.Signature.dVersion == CV_SIGNATURE_NB10))
        {
        dName = imgPathNameW (pwPath, NULL);

        if (dName + lstrlenA (pc10->abPdbName) < MAX_PATH)
            {
            for (i = n = 0; i < dName; i++)
                {
                awPath [n++] = pwPath [i];
                }
            for (i = 0; pc10->abPdbName [i]; i++)
                {
                awPath [n++] = pc10->abPdbName [i];
                }
            awPath [n] = 0;

            dSize = (pdSize != NULL ? *pdSize : 0);
            pData = imgPdbLoadW (awPath, &dSize);
            }
        }
    if (pdSize != NULL) *pdSize = dSize;
    return pData;
    }

// =================================================================
// DBG FILE MANAGEMENT
// =================================================================

BOOL WINAPI imgDbgVerify (PIMG_DBG pid,
                          DWORD    dSize)
    {
    PIMAGE_DEBUG_DIRECTORY pidd;
    DWORD                  i, n, n1, n2;
    BOOL                   fOk = FALSE;

    if ((pid != NULL) && (dSize >= IMG_DBG_)
        &&
        (pid->Header.Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE)
        &&
        (dSize >= IMG_DBG__ (pid->Header.NumberOfSections) +
                  pid->Header.ExportedNamesSize +
                  pid->Header.DebugDirectorySize)
        &&
        (!(pid->Header.DebugDirectorySize % IMAGE_DEBUG_DIRECTORY_))
        &&
        ((pidd = imgDbgDirectories (pid, &n)) != NULL))
        {
        fOk = TRUE;

        for (i = 0; i < n; i++)
            {
            n1 = pidd [i].PointerToRawData;
            n2 = pidd [i].SizeOfData;

            if ((n1 + n2 < n1) || (n1 + n2 > dSize))
                {
                fOk = FALSE;
                break;
                }
            }
        }
    return fOk;
    }

// -----------------------------------------------------------------

PVOID WINAPI imgDbgLoadA (PBYTE  pbPath,
                          PDWORD pdSize)
    {
    DWORD dOffset = (pdSize != NULL ? *pdSize : 0);
    DWORD dSize   = dOffset;
    PBYTE pbData  = imgFileLoadA (pbPath, &dSize);

    if ((pbData != NULL) &&
        (!imgDbgVerify ((PIMG_DBG) (pbData + dOffset), dSize)))
        {
        pbData = imgMemoryDestroy (pbData);
        }
    if (pdSize != NULL) *pdSize = dSize;
    return pbData;
    }

// -----------------------------------------------------------------

PVOID WINAPI imgDbgLoadW (PWORD  pwPath,
                          PDWORD pdSize)
    {
    DWORD dOffset = (pdSize != NULL ? *pdSize : 0);
    DWORD dSize   = dOffset;
    PBYTE pbData  = imgFileLoadW (pwPath, &dSize);

    if ((pbData != NULL) &&
        (!imgDbgVerify ((PIMG_DBG) (pbData + dOffset), dSize)))
        {
        pbData = imgMemoryDestroy (pbData);
        }
    if (pdSize != NULL) *pdSize = dSize;
    return pbData;
    }

// -----------------------------------------------------------------

PBYTE WINAPI imgDbgExports (PIMG_DBG pid,
                            PDWORD   pdCount)
    {
    DWORD i, j;
    DWORD dCount    = 0;
    PBYTE pbExports = NULL;

    if (pid != NULL)
        {
        pbExports = (PBYTE) pid->aSections
                    + (pid->Header.NumberOfSections
                       * IMAGE_SECTION_HEADER_);

        for (i = 0; i < pid->Header.ExportedNamesSize; i = j)
            {
            if (!pbExports [j = i]) break;

            while ((j < pid->Header.ExportedNamesSize) &&
                   pbExports [j++]);

            if ((j > i) && (!pbExports [j-1])) dCount++;
            }
        }
    if (pdCount != NULL) *pdCount = dCount;
    return pbExports;
    }

// -----------------------------------------------------------------

PIMAGE_DEBUG_DIRECTORY WINAPI imgDbgDirectories (PIMG_DBG pid,
                                                 PDWORD   pdCount)
    {
    DWORD                  dCount = 0;
    PIMAGE_DEBUG_DIRECTORY pidd   = NULL;

    if (pid != NULL)
        {
        pidd   = (PIMAGE_DEBUG_DIRECTORY)
                 ((PBYTE) pid
                  + IMG_DBG__ (pid->Header.NumberOfSections)
                  + pid->Header.ExportedNamesSize);

        dCount = pid->Header.DebugDirectorySize
                 / IMAGE_DEBUG_DIRECTORY_;
        }
    if (pdCount != NULL) *pdCount = dCount;
    return pidd;
    }

// -----------------------------------------------------------------

PIMAGE_DEBUG_DIRECTORY WINAPI imgDbgDirectory (PIMG_DBG pid,
                                               DWORD    dType)
    {
    DWORD                  dCount, i;
    PIMAGE_DEBUG_DIRECTORY pidd = NULL;

    if ((pidd = imgDbgDirectories (pid, &dCount)) != NULL)
        {
        for (i = 0; i < dCount; i++, pidd++)
            {
            if (pidd->Type == dType) break;
            }
        if (i == dCount) pidd = NULL;
        }
    return pidd;
    }

// -----------------------------------------------------------------

PCV_DATA WINAPI imgDbgCv (PIMG_DBG pid,
                          PDWORD   pdSize)
    {
    PIMAGE_DEBUG_DIRECTORY pidd;
    DWORD                  dSize = 0;
    PCV_DATA               pcd   = NULL;

    if ((pidd = imgDbgDirectory (pid, IMAGE_DEBUG_TYPE_CODEVIEW))
        != NULL)
        {
        pcd   = IMG_DBG_DATA (pid, pidd);
        dSize = pidd->SizeOfData;
        }
    if (pdSize != NULL) *pdSize = dSize;
    return pcd;
    }

// -----------------------------------------------------------------

PFPO_DATA WINAPI imgDbgFpo (PIMG_DBG pid,
                            PDWORD   pdCount)
    {
    PIMAGE_DEBUG_DIRECTORY pidd;
    DWORD                  dCount = 0;
    PFPO_DATA              pfd    = NULL;

    if ((pidd = imgDbgDirectory (pid, IMAGE_DEBUG_TYPE_FPO))
        != NULL)
        {
        pfd    = IMG_DBG_DATA (pid, pidd);
        dCount = pidd->SizeOfData / FPO_DATA_;
        }
    if (pdCount != NULL) *pdCount = dCount;
    return pfd;
    }

// -----------------------------------------------------------------

PIMAGE_DEBUG_MISC WINAPI imgDbgMisc (PIMG_DBG pid,
                                     PDWORD   pdCount)
    {
    PIMAGE_DEBUG_DIRECTORY pidd;
    PIMAGE_DEBUG_MISC      pidm1;
    DWORD                  i;
    DWORD                  dCount = 0;
    PIMAGE_DEBUG_MISC      pidm   = NULL;

    if ((pidd = imgDbgDirectory (pid, IMAGE_DEBUG_TYPE_MISC))
        != NULL)
        {
        pidm = IMG_DBG_DATA (pid, pidd);

        for (i = 0; i < pidd->SizeOfData; i += pidm1->Length)
            {
            pidm1 = (PIMAGE_DEBUG_MISC) ((PBYTE) pidm + i);

            if ((pidd->SizeOfData - i < IMAGE_DEBUG_MISC_) ||
                (pidd->SizeOfData - i < pidm1->Length    )) break;

            dCount++;
            }
        }
    if (pdCount != NULL) *pdCount = dCount;
    return pidm;
    }

// -----------------------------------------------------------------

POMAP_TO_SRC WINAPI imgDbgOmapToSrc (PIMG_DBG pid,
                                     PDWORD   pdCount)
    {
    PIMAGE_DEBUG_DIRECTORY pidd;
    DWORD                  dCount = 0;
    POMAP_TO_SRC           pots   = NULL;

    if ((pidd = imgDbgDirectory (pid,
                                 IMAGE_DEBUG_TYPE_OMAP_TO_SRC))
        != NULL)
        {
        pots   = IMG_DBG_DATA (pid, pidd);
        dCount = pidd->SizeOfData / OMAP_TO_SRC_;
        }
    if (pdCount != NULL) *pdCount = dCount;
    return pots;
    }

// -----------------------------------------------------------------

POMAP_FROM_SRC WINAPI imgDbgOmapFromSrc (PIMG_DBG pid,
                                         PDWORD   pdCount)
    {
    PIMAGE_DEBUG_DIRECTORY pidd;
    DWORD                  dCount = 0;
    POMAP_FROM_SRC         pofs   = NULL;

    if ((pidd = imgDbgDirectory (pid,
                                 IMAGE_DEBUG_TYPE_OMAP_FROM_SRC))
        != NULL)
        {
        pofs   = IMG_DBG_DATA (pid, pidd);
        dCount = pidd->SizeOfData / OMAP_FROM_SRC_;
        }
    if (pdCount != NULL) *pdCount = dCount;
    return pofs;
    }

// =================================================================
// PDB FILE MANAGEMENT
// =================================================================

BOOL WINAPI imgPdbVerify (PIMG_PDB pip,
                          DWORD    dSize)
    {
    DWORD i, n;
    BOOL  fOk = FALSE;

    if ((pip != NULL) && (dSize >= IMG_PDB_)
        &&
        (!lstrcmpA (pip->Header.Signature.abSignature,
                    PDB_SIGNATURE_200))
        &&
        pip->Header.dPageSize
        &&
        (dSize >= pip->Header.wFilePages * pip->Header.dPageSize))
        {
        fOk = TRUE;

        n = imgPdbPages (pip, pip->Header.RootStream.dStreamSize);

        for (i = 0; i < n; i++)
            {
            if (pip->Header.awRootPages [i] >=
                pip->Header.wFilePages)
                {
                fOk = FALSE;
                break;
                }
            }
        if (fOk)
            {
            pip->Header.RootStream.pwStreamPages =
                pip->Header.awRootPages;
            }
        }
    return fOk;
    }

// -----------------------------------------------------------------

PVOID WINAPI imgPdbLoadA (PBYTE  pbPath,
                          PDWORD pdSize)
    {
    DWORD dOffset = (pdSize != NULL ? *pdSize : 0);
    DWORD dSize   = dOffset;
    PBYTE pbData  = imgFileLoadA (pbPath, &dSize);

    if ((pbData != NULL) &&
        (!imgPdbVerify ((PIMG_PDB) (pbData + dOffset), dSize)))
        {
        pbData = imgMemoryDestroy (pbData);
        }
    if (pdSize != NULL) *pdSize = dSize;
    return pbData;
    }

// -----------------------------------------------------------------

PVOID WINAPI imgPdbLoadW (PWORD  pwPath,
                          PDWORD pdSize)
    {
    DWORD dOffset = (pdSize != NULL ? *pdSize : 0);
    DWORD dSize   = dOffset;
    PBYTE pbData  = imgFileLoadW (pwPath, &dSize);

    if ((pbData != NULL) &&
        (!imgPdbVerify ((PIMG_PDB) (pbData + dOffset), dSize)))
        {
        pbData = imgMemoryDestroy (pbData);
        }
    if (pdSize != NULL) *pdSize = dSize;
    return pbData;
    }

// -----------------------------------------------------------------

PVOID WINAPI imgPdbPage (PIMG_PDB pip,
                         DWORD    dPage)
    {
    PVOID pPage = NULL;

    if ((pip != NULL) && (dPage < pip->Header.wFilePages))
        {
        pPage = (PBYTE) pip + (dPage * pip->Header.dPageSize);
        }
    return pPage;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgPdbPages (PIMG_PDB pip,
                          DWORD    dBytes)
    {
    DWORD dPages = 0;

    if ((pip != NULL) && dBytes)
        {
        dPages = ((dBytes - 1) / pip->Header.dPageSize) + 1;
        }
    return dPages;
    }

// -----------------------------------------------------------------

PVOID WINAPI imgPdbRead (PIMG_PDB    pip,
                         PPDB_STREAM pps)
    {
    DWORD i, j, n;
    PVOID pPage;
    PBYTE pbData = NULL;

    if ((pip != NULL) && (pps != NULL) &&
        ((pbData = imgMemoryCreate (pps->dStreamSize)) != NULL))
        {
        for (i = j = 0; i < pps->dStreamSize; i += n)
            {
            if ((pPage = imgPdbPage (pip, pps->pwStreamPages [j++]))
                == NULL)
                {
                pbData = imgMemoryDestroy (pbData);
                break;
                }
            n = min (pps->dStreamSize - i, pip->Header.dPageSize);
            CopyMemory (pbData + i, pPage, n);
            }
        }
    return pbData;
    }

// -----------------------------------------------------------------

PPDB_ROOT WINAPI imgPdbRoot (PIMG_PDB pip)
    {
    DWORD     i;
    PWORD     pwPages;
    PPDB_ROOT ppr = NULL;

    if ((pip != NULL) &&
        ((ppr = imgPdbRead (pip, &pip->Header.RootStream)) != NULL))
        {
        pwPages = PDB_PAGES (ppr);

        for (i = 0; i < ppr->wCount; i++)
            {
            if (ppr->aStreams [i].dStreamSize != PDB_STREAM_FREE)
                {
                ppr->aStreams [i].pwStreamPages = pwPages;

                pwPages +=
                   imgPdbPages (pip, ppr->aStreams [i].dStreamSize);
                }
            else
                {
                ppr->aStreams [i].pwStreamPages = NULL;
                }
            }
        }
    return ppr;
    }

// -----------------------------------------------------------------

PVOID WINAPI imgPdbStream (PIMG_PDB pip,
                           DWORD    dStream,
                           PDWORD   pdSize)
    {
    PPDB_ROOT ppr;
    DWORD     dSize = 0;
    PVOID     pData = NULL;

    if ((ppr = imgPdbRoot (pip)) != NULL)
        {
        if (dStream < ppr->wCount)
            {
            pData = imgPdbRead (pip, ppr->aStreams + dStream);
            dSize = ppr->aStreams [dStream].dStreamSize;
            }
        imgMemoryDestroy (ppr);
        }
    if (pdSize != NULL) *pdSize = dSize;
    return pData;
    }

// -----------------------------------------------------------------

PVOID WINAPI imgPdbStreamExA (PBYTE  pbPath,
                              DWORD  dStream,
                              PDWORD pdSize)
    {
    PIMG_PDB pip;
    DWORD    dSize = 0;
    PVOID    pData = NULL;

    if ((pip = imgPdbLoadA (pbPath, NULL)) != NULL)
        {
        pData = imgPdbStream (pip, dStream, &dSize);
        imgMemoryDestroy (pip);
        }
    if (pdSize != NULL) *pdSize = dSize;
    return pData;
    }

// -----------------------------------------------------------------

PVOID WINAPI imgPdbStreamExW (PWORD  pwPath,
                              DWORD  dStream,
                              PDWORD pdSize)
    {
    PIMG_PDB pip;
    DWORD    dSize = 0;
    PVOID    pData = NULL;

    if ((pip = imgPdbLoadW (pwPath, NULL)) != NULL)
        {
        pData = imgPdbStream (pip, dStream, &dSize);
        imgMemoryDestroy (pip);
        }
    if (pdSize != NULL) *pdSize = dSize;
    return pData;
    }

// -----------------------------------------------------------------

PPDB_PUBSYM WINAPI imgPdbSymbols (PIMG_PDB pip,
                                  PDWORD   pdCount,
                                  PDWORD   pdSize)
    {
    PPDB_PUBSYM ppp1;
    DWORD       i;
    DWORD       dCount = 0;
    DWORD       dSize  = 0;
    PPDB_PUBSYM ppp    = NULL;

    if ((ppp = imgPdbStream (pip, PDB_STREAM_PUBSYM, &dSize))
        != NULL)
        {
        for (i  = 0; dSize - i >= PDB_PUBSYM_;
             i += PDB_PUBSYM_SIZE (ppp1))
            {
            ppp1 = (PPDB_PUBSYM) ((PBYTE) ppp + i);
            if (dSize - i < PDB_PUBSYM_SIZE (ppp1)) break;
            if (ppp1->Header.wRecordType == PDB_PUB32) dCount++;
            }
        }
    if (pdCount != NULL) *pdCount = dCount;
    if (pdSize  != NULL) *pdSize  = dSize;
    return ppp;
    }

// =================================================================
// MODULE INFO MANAGEMENT
// =================================================================

BOOL WINAPI imgInfoInitialize (PIMG_INFO pii,
                               PVOID     pBase,
                               DWORD     dSize)
    {
    PIMG_DBG pid;
    DWORD    i;
    BOOL     fOk = FALSE;

    if (pii != NULL)
        {
        pid = &pii->DbgFile;

        pii->pBase        =  (pBase != NULL
                              ? pBase
                              : (PVOID) pid->Header.ImageBase);

        pii->pHeader      = &pid->Header;
        pii->pSections    =  pid->aSections;

        pii->pbExports    = imgDbgExports
                                (pid, &pii->dExports);

        pii->pDirectories = imgDbgDirectories
                                (pid, &pii->dDirectories);

        pii->pCvData      = imgDbgCv
                                (pid, &pii->dCvData);

        pii->pFpoEntries  = imgDbgFpo
                                (pid, &pii->dFpoEntries);

        pii->pMiscEntries = imgDbgMisc
                                (pid, &pii->dMiscEntries);

        pii->pOmapToSrc   = imgDbgOmapToSrc
                                (pid, &pii->dOmapToSrc);

        pii->pOmapFromSrc = imgDbgOmapFromSrc
                                (pid, &pii->dOmapFromSrc);

        pii->dSize        = dSize;
        pii->dSections    = pii->pHeader->NumberOfSections;

        for (i = 0; i < pii->dSections; i++)
            {
            pii->pSections [i].PointerToRawData =
                imgInfoOmapSection (pii, i+1);
            }
        fOk = TRUE;
        }
    return fOk;
    }

// -----------------------------------------------------------------

PIMG_INFO WINAPI imgInfoLoadA (PBYTE pbPath,
                               PVOID pBase)
    {
    DWORD     dSize = IMG_INFO_PREFIX;
    PIMG_INFO pii   = NULL;

    if (((pii = imgDbgLoadA (pbPath, &dSize)) != NULL) &&
        imgInfoInitialize (pii, pBase, dSize) &&
        (lstrlenA (pbPath) < MAX_PATH))
        {
        pii->fUnicode = FALSE;
        lstrcpyA (pii->abPath, pbPath);
        }
    else
        {
        pii = imgMemoryDestroy (pii);
        }
    return pii;
    }

// -----------------------------------------------------------------

PIMG_INFO WINAPI imgInfoLoadW (PWORD pwPath,
                               PVOID pBase)
    {
    DWORD     dSize = IMG_INFO_PREFIX;
    PIMG_INFO pii   = NULL;

    if (((pii = imgDbgLoadW (pwPath, &dSize)) != NULL) &&
        imgInfoInitialize (pii, pBase, dSize)          &&
        (lstrlenW (pwPath) < MAX_PATH))
        {
        pii->fUnicode = TRUE;
        lstrcpyW (pii->awPath, pwPath);
        }
    else
        {
        pii = imgMemoryDestroy (pii);
        }
    return pii;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgInfoOmapToSrc (PIMG_INFO pii,
                               DWORD     dTarget,
                               PDWORD    pdOffset)
    {
    POMAP_TO_SRC potc;
    DWORD        i, n;
    DWORD        dOffset = 0;
    DWORD        dSource = 0;

    if (pii != NULL)
        {
        if (n = pii->dOmapToSrc)
            {
            i = (n /= 2);

            while (TRUE)
                {
                potc = NULL;
                if (i >= pii->dOmapToSrc) break;

                potc = pii->pOmapToSrc + i;
                if (dTarget == potc->dTarget) break;

                if (n > 1) n /= 2;

                if (dTarget < potc->dTarget)
                    {
                    i -= n;
                    }
                else
                    {
                    if ((i + 1 == pii->dOmapToSrc) ||
                        (dTarget < (potc+1)->dTarget)) break;

                    i += n;
                    }
                }
            if (potc != NULL)
                {
                dSource = potc->dSource;
                dOffset = dTarget - potc->dTarget;
                }
            }
        else
            {
            dSource = dTarget;
            }
        }
    if (pdOffset != NULL) *pdOffset = dOffset;
    return dSource;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgInfoOmapFromSrc (PIMG_INFO pii,
                                 DWORD     dSource,
                                 PDWORD    pdOffset)
    {
    POMAP_FROM_SRC pofs;
    DWORD          i, n;
    DWORD          dOffset = 0;
    DWORD          dTarget = 0;

    if (pii != NULL)
        {
        if (n = pii->dOmapFromSrc)
            {
            i = (n /= 2);

            while (TRUE)
                {
                pofs = NULL;
                if (i >= pii->dOmapFromSrc) break;

                pofs = pii->pOmapFromSrc + i;
                if (dSource == pofs->dSource) break;

                if (n > 1) n /= 2;

                if (dSource < pofs->dSource)
                    {
                    i -= n;
                    }
                else
                    {
                    if ((i + 1 == pii->dOmapFromSrc) ||
                        (dSource < (pofs+1)->dSource)) break;

                    i += n;
                    }
                }
            if (pofs != NULL)
                {
                dTarget = pofs->dTarget;
                dOffset = dSource - pofs->dSource;
                }
            }
        else
            {
            dTarget = dSource;
            }
        }
    if (pdOffset != NULL) *pdOffset = dOffset;
    return dTarget;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgInfoOmapSection (PIMG_INFO pii,
                                 DWORD     dSection)
    {
    POMAP_TO_SRC          potc;
    PIMAGE_SECTION_HEADER pish;
    DWORD                 i;
    DWORD                 dBase = 0;

    if ((pii != NULL) &&
        dSection && (dSection <= pii->dSections))
        {
        pish = pii->pSections + (dSection-1);

        if (pii->pOmapToSrc)
            {
            for (i = 0; i < pii->dOmapToSrc; i++)
                {
                potc = pii->pOmapToSrc + i;

                if (potc->dTarget >= pish->VirtualAddress +
                                     pish->Misc.VirtualSize) break;

                if ((potc->dTarget >= pish->VirtualAddress) &&
                    potc->dSource)
                    {
                    dBase = (dBase ? min (dBase, potc->dSource)
                                   : potc->dSource);
                    }
                }
            }
        else
            {
            dBase = pish->VirtualAddress;
            }
        }
    return dBase;
    }

// -----------------------------------------------------------------

PIMG_PUBSYM WINAPI imgInfoSymbols (PIMG_INFO pii,
                                   PDWORD    pdCount,
                                   PDWORD    pdSize,
                                   PDWORD    pdVersion)
    {
    PCV_PUBSYM  pcp;
    PIMG_PDB    pPdbFile;
    DWORD       dCount   = 0;
    DWORD       dSize    = 0;
    DWORD       dVersion = 0;
    PIMG_PUBSYM pip      = NULL;

    if ((pii != NULL) && (pii->pCvData != NULL))
        {
        switch (dVersion = pii->pCvData->Header.Signature.dVersion)
            {
            case CV_SIGNATURE_NB09:
                {
                if ((pcp = imgCvSymbols (&pii->pCvData->NB09,
                                         &dCount, &dSize))
                    != NULL)
                    {
                    if (((pip = imgMemoryCreate (dSize)) != NULL) &&
                        dSize)
                        {
                        CopyMemory (pip, pcp, dSize);
                        }
                    }
                break;
                }
            case CV_SIGNATURE_NB10:
                {
                if ((pPdbFile = (pii->fUnicode

                                 ? imgCvPdbW (&pii->pCvData->NB10,
                                              pii->awPath, NULL)

                                 : imgCvPdbA (&pii->pCvData->NB10,
                                              pii->abPath, NULL)))
                    != NULL)
                    {
                    pip = (PIMG_PUBSYM)
                          imgPdbSymbols (pPdbFile, &dCount, &dSize);

                    imgMemoryDestroy (pPdbFile);
                    }
                break;
                }
            }
        }
    if (pdCount   != NULL) *pdCount   = dCount;
    if (pdSize    != NULL) *pdSize    = dSize;
    if (pdVersion != NULL) *pdVersion = dVersion;
    return pip;
    }

// -----------------------------------------------------------------

PBYTE WINAPI imgInfoTypeA (PIMG_INFO pii,
                           DWORD     dType)
    {
    PBYTE pbType = "";

    if ((pii != NULL) && (dType < pii->dDirectories))
        {
        switch (pii->pDirectories [dType].Type)
            {
            case IMAGE_DEBUG_TYPE_UNKNOWN:
                {
                pbType = "Unknown";
                break;
                }
            case IMAGE_DEBUG_TYPE_COFF:
                {
                pbType = "COFF";
                break;
                }
            case IMAGE_DEBUG_TYPE_CODEVIEW:
                {
                pbType = "CodeView";
                break;
                }
            case IMAGE_DEBUG_TYPE_FPO:
                {
                pbType = "Frame Pointer Omission (FPO)";
                break;
                }
            case IMAGE_DEBUG_TYPE_MISC:
                {
                pbType = "Miscellaneous Information";
                break;
                }
            case IMAGE_DEBUG_TYPE_EXCEPTION:
                {
                pbType = "Exception Information";
                break;
                }
            case IMAGE_DEBUG_TYPE_FIXUP:
                {
                pbType = "Fixup Information";
                break;
                }
            case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:
                {
                pbType = "OMAP_TO_SRC";
                break;
                }
            case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:
                {
                pbType = "OMAP_FROM_SRC";
                break;
                }
            case IMAGE_DEBUG_TYPE_BORLAND:
                {
                pbType = "Borland debugging information";
                break;
                }
            case IMAGE_DEBUG_TYPE_RESERVED10:
                {
                pbType = "Reserved #10";
                break;
                }
            case IMAGE_DEBUG_TYPE_CLSID:
                {
                pbType = "Class ID (CLSID)";
                break;
                }
            default:
                {
                pbType = "Undefined";
                break;
                }
            }
        }
    return pbType;
    }

// -----------------------------------------------------------------

PWORD WINAPI imgInfoTypeW (PIMG_INFO pii,
                           DWORD     dType)
    {
    PWORD pwType = L"";

    if ((pii != NULL) && (dType < pii->dDirectories))
        {
        switch (pii->pDirectories [dType].Type)
            {
            case IMAGE_DEBUG_TYPE_UNKNOWN:
                {
                pwType = L"Unknown";
                break;
                }
            case IMAGE_DEBUG_TYPE_COFF:
                {
                pwType = L"COFF";
                break;
                }
            case IMAGE_DEBUG_TYPE_CODEVIEW:
                {
                pwType = L"CodeView";
                break;
                }
            case IMAGE_DEBUG_TYPE_FPO:
                {
                pwType = L"Frame Pointer Omission (FPO)";
                break;
                }
            case IMAGE_DEBUG_TYPE_MISC:
                {
                pwType = L"Miscellaneous Information";
                break;
                }
            case IMAGE_DEBUG_TYPE_EXCEPTION:
                {
                pwType = L"Exception Information";
                break;
                }
            case IMAGE_DEBUG_TYPE_FIXUP:
                {
                pwType = L"Fixup Information";
                break;
                }
            case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:
                {
                pwType = L"OMAP_TO_SRC";
                break;
                }
            case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:
                {
                pwType = L"OMAP_FROM_SRC";
                break;
                }
            case IMAGE_DEBUG_TYPE_BORLAND:
                {
                pwType = L"Borland debugging information";
                break;
                }
            case IMAGE_DEBUG_TYPE_RESERVED10:
                {
                pwType = L"Reserved #10";
                break;
                }
            case IMAGE_DEBUG_TYPE_CLSID:
                {
                pwType = L"Class ID (CLSID)";
                break;
                }
            default:
                {
                pwType = L"Undefined";
                break;
                }
            }
        }
    return pwType;
    }

// =================================================================
// SYMBOL MANAGEMENT
// =================================================================

PIMG_PUBSYM WINAPI imgSymbolNext (PIMG_PUBSYM pip)
    {
    return (pip != NULL ? IMG_PUBSYM_NEXT (pip) : NULL);
    }

// -----------------------------------------------------------------

DWORD WINAPI imgSymbolTest (PIMG_PUBSYM pip)
    {
    return (pip != NULL)
           && 
           ((pip->Header.wRecordType == CV_PUB32 ) ||
            (pip->Header.wRecordType == PDB_PUB32));
    }

// -----------------------------------------------------------------

DWORD WINAPI imgSymbolUndecorate (PBYTE  pbSymbol,
                                  PBYTE  pbBuffer,
                                  PDWORD pdConvention)
    {
    PBYTE apbPrefixes [] = {"__imp__", "__imp_@", "__imp_",
                            "_", "@", "\x7F",
                            NULL};

    BYTE  abBuffer [256] = "";
    DWORD i, j, k, l;
    DWORD dConvention = IMG_CONVENTION_UNDEFINED;
    DWORD dStack      = -1;

    if (pbSymbol != NULL)
        {
        // skip common prefixes
        for (i = j = 0; apbPrefixes [i] != NULL; i++)
            {
            for (j = 0; apbPrefixes [i] [j]; j++)
                {
                if (apbPrefixes [i] [j] != pbSymbol [j]) break;
                }
            if (!apbPrefixes [i] [j]) break;
            j = 0;
            }
        // test for multiple '@'
        for (k = j, l = 0; (l < 2) && pbSymbol [k]; k++)
            {
            if (pbSymbol [k] == '@') l++;
            }
        // don't undecorate if multiple '@', or C++ symbol
        if ((l == 2) || (pbSymbol [0] == '?'))
            {
            j = 0;        // keep prefix
            k = MAXDWORD; // keep length
            }
        else
            {
            // search for next '@'
            for (k = j; pbSymbol [k] && (pbSymbol [k] != '@'); k++);

            // read number of argument stack bytes if '@' found
            if (pbSymbol [k] == '@')
                {
                dStack = 0;

                for (l = k + 1; (pbSymbol [l] >= '0') &&
                                (pbSymbol [l] <= '9'); l++)
                    {
                    dStack *= 10;
                    dStack += pbSymbol [l] - '0';
                    }
                // don't undecorate if non-numeric or empty trailer
                if (pbSymbol [l] || (l == k + 1))
                    {
                    dStack = -1;  // no stack size info

                    j = 0;        // keep prefix
                    k = MAXDWORD; // keep length
                    }
                }
            }
        // determine calling convention if single-char prefix
        if (j == 1)
            {
            switch (pbSymbol [0])
                {
                case '@':
                    {
                    dConvention = IMG_CONVENTION_FASTCALL;
                    break;
                    }
                case '_':
                    {
                    dConvention = (dStack != -1
                                   ? IMG_CONVENTION_STDCALL
                                   : IMG_CONVENTION_CDECL);
                    break;
                    }
                }
            }
        // copy selected name portion
        k = min (k - j, sizeof (abBuffer) - 1);
        lstrcpynA (abBuffer, pbSymbol + j, k + 1);
        }
    if (pbBuffer != NULL)
        {
        lstrcpyA (pbBuffer, abBuffer);
        }
    if (pdConvention != NULL) *pdConvention = dConvention;
    return dStack;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgSymbolExported (PIMG_PUBSYM pip,
                                PIMG_INFO   pii)
    {
    POMF_NAME pon;
    BYTE      abName [256];
    DWORD     i, j;
    DWORD     dId = 0;

    if ((pip != NULL) && (pii != NULL) && pii->dExports)
        {
        switch (pip->Header.wRecordType)
            {
            case CV_PUB32:
                {
                pon = &pip->CvPubSym.Name;
                break;
                }
            case PDB_PUB32:
                {
                pon = &pip->PdbPubSym.Name;
                break;
                }
            default:
                {
                pon = NULL;
                break;
                }
            }
        if (pon != NULL)
            {
            for (i = 0; i < pon->bLength; i++)
                {
                abName [i] = pon->abName [i];
                }
            abName [i] = 0;

            imgSymbolUndecorate (abName, abName, NULL);

            for (i = j = 0; i < pii->dExports; i++)
                {
                if (!lstrcmpA (abName, pii->pbExports + j))
                    {
                    dId = i + 1;
                    break;
                    }
                j += (lstrlenA (pii->pbExports + j) + 1);
                }
            }
        }
    return dId;
    }

// -----------------------------------------------------------------

PVOID WINAPI imgSymbolInfo (PIMG_PUBSYM pip,
                            PIMG_INFO   pii,
                            PIMG_SYMBOL pis,
                            BOOL        fUndecorate)
    {
    DWORD      i;
    IMG_SYMBOL is;
    POMF_NAME  pon = NULL;

    is.pip        = pip;
    is.dSection   = 0;
    is.dRaw       = 0;
    is.dBias      = 0;
    is.dSource    = 0;
    is.dTarget    = 0;
    is.dOffset    = 0;
    is.pBase      = NULL;
    is.pAddress   = NULL;
    is.dStack     = -1;
    is.abName [0] = 0;

    if (pip != NULL)
        {
        switch (pip->Header.wRecordType)
            {
            case CV_PUB32:
                {
                is.dSection =  pip->CvPubSym.wSegment;
                is.dRaw     =  pip->CvPubSym.dOffset;
                pon         = &pip->CvPubSym.Name;
                break;
                }
            case PDB_PUB32:
                {
                is.dSection =  pip->PdbPubSym.wSegment;
                is.dRaw     =  pip->PdbPubSym.dOffset;
                pon         = &pip->PdbPubSym.Name;
                break;
                }
            }
        }
    if ((pii != NULL) &&
        is.dSection && (is.dSection <= pii->dSections) &&
        (is.dBias = pii->pSections[is.dSection-1].PointerToRawData))
        {
        is.dSource   = is.dBias + is.dRaw;
        is.dTarget   = imgInfoOmapFromSrc (pii, is.dSource,
                                           &is.dOffset);

        is.dRelative = (is.dTarget ? is.dTarget + is.dOffset : 0);
        is.pBase     = pii->pBase;
        is.pAddress  = (is.dRelative
                        ? (PBYTE) pii->pBase + is.dRelative
                        : NULL);
        }
    if (pon != NULL)
        {
        for (i = 0; i < pon->bLength; i++)
            {
            is.abName [i] = pon->abName [i];
            }
        is.abName [i] = 0;

        is.dStack = imgSymbolUndecorate
                        (is.abName,
                         (fUndecorate ? is.abName : NULL),
                         &is.dConvention);
        }
    if (pis != NULL) *pis = is;
    return is.pAddress;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgSymbolLookup (PVOID       pAddress,
                              DWORD       dCount,
                              PIMG_PUBSYM pip,
                              PIMG_INFO   pii,
                              PIMG_SYMBOL pis,
                              BOOL        fUndecorate)
    {
    IMG_SYMBOL  is, is1;
    PIMG_PUBSYM pip1;
    DWORD       dOffset1, dIndex;
    DWORD       dOffset = MAXDWORD;

    imgSymbolInfo (NULL, NULL, &is, FALSE);

    if ((pAddress != NULL) && (pip != NULL) && (pii != NULL))
        {
        pip1   = pip;
        dIndex = 0;

        while (dIndex < dCount)
            {
            if (imgSymbolTest (pip1))
                {
                if ((imgSymbolInfo (pip1, pii, &is1, fUndecorate)
                     != NULL)
                    &&
                    ((DWORD_PTR) pAddress
                     >= (DWORD_PTR) is1.pAddress))
                    {
                    dOffset1 = (DWORD_PTR)     pAddress -
                               (DWORD_PTR) is1.pAddress;

                    if ((is.pAddress == NULL) ||
                        (dOffset > dOffset1))
                        {
                        dOffset = dOffset1;
                        is      = is1;
                        }
                    }
                dIndex++;
                }
            pip1 = imgSymbolNext (pip1);
            }
        }
    if (pis != NULL) *pis = is;
    return dOffset;
    }

// -----------------------------------------------------------------

PIMG_TABLE WINAPI imgSymbolTable (DWORD       dCount,
                                  PIMG_PUBSYM pip,
                                  PIMG_INFO   pii)
    {
    DWORD       dSize, i, j;
    IMG_SYMBOL  is;
    PIMG_PUBSYM pip1;
    PIMG_ENTRY  pie;
    PIMG_TABLE  pit = NULL;

    dSize = IMG_TABLE__ (dCount);

    if ((pip != NULL) && (pii != NULL) &&
        ((pit = imgMemoryCreate (dSize)) != NULL))
        {
        pit->dSize        = dSize;
        pit->dSections    = pii->dSections;
        pit->dSymbols     = 0;
        pit->dTimeStamp   = pii->DbgFile.Header.TimeDateStamp;
        pit->dCheckSum    = pii->DbgFile.Header.CheckSum;
        pit->pBase        = pii->pBase;

        pit->piiAddress   = (PIMG_INDEX)
                            (pit->aEntries              + dCount);

        pit->piiName      = (PIMG_INDEX)
                            (pit->piiAddress->apEntries + dCount);

        pit->piiNameIC    = (PIMG_INDEX)
                            (pit->piiName   ->apEntries + dCount);

        if (pit->fUnicode = pii->fUnicode)
            {
            lstrcpyW (pit->awPath, pii->awPath);
            }
        else
            {
            lstrcpyA (pit->abPath, pii->abPath);
            }
        pip1 = pip;

        while (pit->dSymbols < dCount)
            {
            if (imgSymbolTest (pip1))
                {
                imgSymbolInfo (pip1, pii, &is, FALSE);

                pie = pit->aEntries + pit->dSymbols;

                pie->dSection    = is.dSection;
                pie->pAddress    = is.pAddress;
                pie->dConvention = is.dConvention;
                pie->dStack      = is.dStack;
                pie->fExported   = FALSE;

                ZeroMemory (pie->abSection,
                            sizeof (pie->abSection));

                if (is.dSection && (is.dSection <= pii->dSections))
                    {
                    CopyMemory (pie->abSection,
                                pii->pSections [is.dSection-1].Name,
                                IMAGE_SIZEOF_SHORT_NAME);
                    }
                ZeroMemory (pie->abSymbol,
                            sizeof (pie->abDecorated));

                lstrcpyA (pie->abDecorated, is.abName);

                ZeroMemory (pie->abSymbol,
                            sizeof (pie->abSymbol));

                imgSymbolUndecorate (pie->abDecorated,
                                     pie->abSymbol, NULL);

                if (!(pie->fSpecial = (pie->abSymbol [0] == '?')))
                    {
                    for (i = 0; pie->abSymbol [i]; i++)
                        {
                        if (pie->abSymbol [i] == '@')
                            {
                            pie->fSpecial = TRUE;
                            break;
                            }
                        }
                    }
                pit->piiAddress->apEntries [pit->dSymbols] =
                pit->piiName   ->apEntries [pit->dSymbols] =
                pit->piiNameIC ->apEntries [pit->dSymbols] = pie;

                pit->dSymbols++;
                }
            pip1 = imgSymbolNext (pip1);
            }
        if (pit->dSymbols)
            {
            imgSymbolSort (pit->dSymbols,
                           pit->piiAddress, FALSE, FALSE);

            CopyMemory (pit->piiName, pit->piiAddress,
                        IMG_INDEX__ (pit->dSymbols));

            imgSymbolSort (pit->dSymbols,
                           pit->piiName, TRUE, FALSE);

            CopyMemory (pit->piiNameIC, pit->piiName,
                        IMG_INDEX__ (pit->dSymbols));

            imgSymbolSort (pit->dSymbols,
                           pit->piiNameIC, TRUE, TRUE);
            }
        for (i = j = 0; i < pii->dExports; i++)
            {
            if ((pie = imgTableResolve (pit, pii->pbExports + j))
                != NULL)
                {
                pie->fExported = TRUE;
                }
            j += (lstrlenA (pii->pbExports + j) + 1);
            }
        }
    return pit;
    }

// -----------------------------------------------------------------

INT WINAPI imgSymbolCompare (PIMG_ENTRY pie1,
                             PIMG_ENTRY pie2,
                             BOOL       fCompareNames,
                             BOOL       fIgnoreCase)
    {
    DWORD i;
    BYTE  b1, b2;
    INT   iCompare = 0;

    if (pie1 != NULL)
        {
        if (pie2 != NULL)
            {
            if (fCompareNames)
                {
                for (i = 0; !iCompare; i++)
                    {
                    b1 = pie1->abSymbol [i];
                    b2 = pie2->abSymbol [i];

                    if (fIgnoreCase)
                        {
                        b1 = LCase [b1];
                        b2 = LCase [b2];
                        }
                    iCompare = (b1 < b2 ? -1 : (b1 > b2 ? 1 : 0));
                    if ((!b1) || (!b2)) break;
                    }
                }
            else
                {
                iCompare = ((DWORD_PTR) pie1->pAddress <
                            (DWORD_PTR) pie2->pAddress
                            ? -1
                            : ((DWORD_PTR) pie1->pAddress >
                               (DWORD_PTR) pie2->pAddress
                               ? 1
                               : 0));
                }
            if (!iCompare)
                {
                iCompare = (pie1->dConvention <
                            pie2->dConvention
                            ? -1
                            : (pie1->dConvention >
                               pie2->dConvention
                               ? 1
                               : ((DWORD_PTR) pie1 <
                                  (DWORD_PTR) pie2
                                  ? -1
                                  : ((DWORD_PTR) pie1 >
                                     (DWORD_PTR) pie2
                                     ? 1
                                     : 0))));
                }
            }
        else
            {
            iCompare = 1;
            }
        }
    else
        {
        if (pie2 != NULL) iCompare = -1;
        }
    return iCompare;
    }

// -----------------------------------------------------------------

DWORD WINAPI imgSymbolSort (DWORD      dCount,
                            PIMG_INDEX pii,
                            BOOL       fSortByName,
                            BOOL       fIgnoreCase)
    {
    PIMG_ENTRY pie1, pie2;
    DWORD      dDelta, dTrans, i;
    DWORD      n = 0;

    if (pii != NULL)
        {
        if ((dDelta = dCount) > 1)
            {
            dTrans = 1;

            while ((dDelta > 1) || dTrans)
                {
                dTrans  = 0;
                dDelta -= (dDelta > 3 ? dDelta >> 2
                                      : (dDelta > 1 ? 1 : 0));

                for (i = 0; i < dCount - dDelta; i++)
                    {
                    pie1 = pii->apEntries [i       ];
                    pie2 = pii->apEntries [i+dDelta];

                    if (imgSymbolCompare (pie1, pie2,
                                          fSortByName,
                                          fIgnoreCase)
                        > 0)
                        {
                        pii->apEntries [i       ] = pie2;
                        pii->apEntries [i+dDelta] = pie1;

                        dTrans++;
                        }
                    }
                n += dTrans;
                }
            }
        }
    return n;
    }

// =================================================================
// SYMBOL TABLE MANAGEMENT
// =================================================================

PIMG_TABLE WINAPI imgTableLoadA (PBYTE pbPath,
                                 PVOID pBase)
    {
    BYTE        abPath [MAX_PATH];
    DWORD       dCount;
    PIMG_INFO   pii;
    PIMG_PUBSYM pip;
    PIMG_TABLE  pit = NULL;

    if (imgPathDbgA (pbPath, abPath, MAX_PATH) &&
        ((pii = imgInfoLoadA (abPath, pBase)) != NULL))
        {
        if ((pip = imgInfoSymbols (pii, &dCount, NULL, NULL))
            != NULL)
            {
            pit = imgSymbolTable (dCount, pip, pii);
            imgMemoryDestroy (pip);
            }
        imgMemoryDestroy (pii);
        }
    return pit;
    }

// -----------------------------------------------------------------

PIMG_TABLE WINAPI imgTableLoadW (PWORD pwPath,
                                 PVOID pBase)
    {
    WORD        awPath [MAX_PATH];
    DWORD       dCount;
    PIMG_INFO   pii;
    PIMG_PUBSYM pip;
    PIMG_TABLE  pit = NULL;

    if (imgPathDbgW (pwPath, awPath, MAX_PATH) &&
        ((pii = imgInfoLoadW (awPath, pBase)) != NULL))
        {
        if ((pip = imgInfoSymbols (pii, &dCount, NULL, NULL))
            != NULL)
            {
            pit = imgSymbolTable (dCount, pip, pii);
            imgMemoryDestroy (pip);
            }
        imgMemoryDestroy (pii);
        }
    return pit;
    }

// -----------------------------------------------------------------

PIMG_ENTRY WINAPI imgTableLookup (PIMG_TABLE pit,
                                  PVOID      pAddress,
                                  PDWORD     pdOffset)
    {
    PPIMG_ENTRY ppie;
    DWORD       i, n;
    DWORD       dOffset = 0;
    PIMG_ENTRY  pie     = NULL;

    if ((pit != NULL) && (pAddress != NULL) && (n = pit->dSymbols))
        {
        i = (n /= 2);

        while (TRUE)
            {
            pie = NULL;

            if (i >= pit->dSymbols) break;

            ppie =  pit->piiAddress->apEntries + i;
            pie  = *(ppie++);

            if (n > 1) n /= 2;

            if ((DWORD_PTR) pAddress <
                (DWORD_PTR) pie->pAddress)
                {
                i -= n;
                }
            else
                {
                if ((i + 1 == pit->dSymbols) ||
                    ((DWORD_PTR) pAddress <
                     (DWORD_PTR) (*ppie)->pAddress))
                    {
                    if (pie->pAddress == NULL) pie = NULL;
                    break;
                    }
                i += n;
                }
            }
        if (pie != NULL)
            {
            dOffset = (DWORD_PTR) pAddress -
                      (DWORD_PTR) pie->pAddress;
            }
        }
    if (pdOffset != NULL) *pdOffset = dOffset;
    return pie;
    }

// -----------------------------------------------------------------

PIMG_ENTRY WINAPI imgTableResolve (PIMG_TABLE pit,
                                   PBYTE      pbSymbol)
    {
    DWORD       i, j, k, l, n;
    PIMG_ENTRY  pie = NULL;

    if ((pit != NULL) && (pbSymbol != NULL) && (n = pit->dSymbols))
        {
        i = (n /= 2); // current index
        j = 0;        // previous distance
        k = 1;        // loop detector

        while (TRUE)
            {
            pie = NULL;

            if ((i >= pit->dSymbols) || (!k)) break;

            pie = pit->piiName->apEntries [i];

            for (l = 0; pbSymbol [l]; l++)
                {
                if (pbSymbol [l] != pie->abSymbol [l]) break;
                }
            // OK if symbol with defined calling convention
            if ((pbSymbol [l] == pie->abSymbol [l]) &&
                (pie->dConvention != IMG_CONVENTION_UNDEFINED))
                break;

            if (n > 1) n /= 2;

            if (pbSymbol [l] < pie->abSymbol [l])
                {
                k = j - n; // if 0, the sequence is stuck in a loop
                j = 0 - n;
                }
            else
                {
                k = j + n; // if 0, the sequence is stuck in a loop
                j =     n;
                }
            i += j;
            }
        }
    return pie;
    }

// =================================================================
// MODULE MANAGEMENT
// =================================================================

PVOID WINAPI imgModuleExport (PBYTE pbModule,
                              PBYTE pbExport)
    {
    PBYTE   pbModule1;
    HMODULE hModule;
    PVOID   pExport = NULL;

    pbModule1 = (pbModule != NULL ? pbModule : "ntdll.dll");

    if ((hModule = GetModuleHandleA (pbModule1)) != NULL)
        {
        pExport = GetProcAddress (hModule, pbExport);
        }
    return pExport;
    }

// -----------------------------------------------------------------

PMODULE_LIST WINAPI imgModuleList (PDWORD pdData)
    {
    NTPROC       _NtQuerySystemInformation;
    NTSTATUS     ns;
    DWORD        dSize;
    DWORD        dData = 0;
    PMODULE_LIST pml   = NULL;

    if ((_NtQuerySystemInformation =
             imgModuleExport (NULL, "NtQuerySystemInformation"))
        != NULL)
        {
        for (dSize = PAGE_SIZE; (pml == NULL) && dSize; dSize <<= 1)
            {
            if ((pml = imgMemoryCreate (dSize)) == NULL) break;

            ns = _NtQuerySystemInformation (SystemModuleInformation,
                                            pml, dSize, &dData);
            if (ns != STATUS_SUCCESS)
                {
                pml   = imgMemoryDestroy (pml);
                dData = 0;

                if (ns != STATUS_INFO_LENGTH_MISMATCH) break;
                }
            }
        }
    if (pdData != NULL) *pdData = dData;
    return pml;
    }

// -----------------------------------------------------------------

PMODULE_LIST WINAPI imgModuleFindA (PBYTE  pbModule,
                                    PDWORD pdIndex)
    {
    PBYTE        pbModule1;
    DWORD        dName, i;
    DWORD        dIndex = -1;
    PMODULE_LIST pml    = NULL;

    pbModule1 = (pbModule != NULL ? pbModule : gabKernel);

    if ((pml = imgModuleList (NULL)) != NULL)
        {
        dName = imgPathNameA (pbModule1, NULL);

        for (i = 0; i < pml->dModules; i++)
            {
            if (!lstrcmpiA (pml->aModules [i].abPath +
                            pml->aModules [i].wNameOffset,
                            pbModule1 + dName))
                {
                dIndex = i;
                break;
                }
            }
        if (dIndex == -1) pml = imgMemoryDestroy (pml);
        }
    if (pdIndex != NULL) *pdIndex = dIndex;
    return pml;
    }

// -----------------------------------------------------------------

PMODULE_LIST WINAPI imgModuleFindW (PWORD  pwModule,
                                    PDWORD pdIndex)
    {
    PWORD        pwModule1;
    WORD         awModule [MAXIMUM_FILENAME_LENGTH];
    DWORD        dName, i, j, k;
    DWORD        dIndex = -1;
    PMODULE_LIST pml    = NULL;

    pwModule1 = (pwModule != NULL ? pwModule : gawKernel);

    if ((pml = imgModuleList (NULL)) != NULL)
        {
        dName = imgPathNameW (pwModule1, NULL);

        for (i = 0; i < pml->dModules; i++)
            {
            j = 0;
            k = pml->aModules [i].wNameOffset;

            do  {
                awModule [j++] = pml->aModules [i].abPath [k++];
                }
            while (awModule [j-1]);

            if (!lstrcmpiW (awModule, pwModule1 + dName))
                {
                dIndex = i;
                break;
                }
            }
        if (dIndex == -1) pml = imgMemoryDestroy (pml);
        }
    if (pdIndex != NULL) *pdIndex = dIndex;
    return pml;
    }

// -----------------------------------------------------------------

PVOID WINAPI imgModuleBaseA (PBYTE pbModule)
    {
    PMODULE_LIST pml;
    DWORD        dIndex;
    PVOID        pBase = NULL;

    if ((pml = imgModuleFindA (pbModule, &dIndex)) != NULL)
        {
        pBase = pml->aModules [dIndex].pBase;
        imgMemoryDestroy (pml);
        }
    return pBase;
    }

// -----------------------------------------------------------------

PVOID WINAPI imgModuleBaseW (PWORD pwModule)
    {
    PMODULE_LIST pml;
    DWORD        dIndex;
    PVOID        pBase = NULL;

    if ((pml = imgModuleFindW (pwModule, &dIndex)) != NULL)
        {
        pBase = pml->aModules [dIndex].pBase;
        imgMemoryDestroy (pml);
        }
    return pBase;
    }

// =================================================================
// DLL MANAGEMENT
// =================================================================

BOOL WINAPI DllMain (HINSTANCE hInstance,
                     DWORD     dReason,
                     PVOID     pReserved)
    {
    BOOL fOk = TRUE;

    if (dReason == DLL_PROCESS_ATTACH)
        {
        ghInstance = hInstance;
        }
    return fOk;
    }

// =================================================================
// END OF PROGRAM
// =================================================================
