Pelles C forum

C language => User contributions => Topic started by: Rainbow Sally on January 29, 2005, 07:10:17 pm

Title: GetDbgType -- pseudo-oop demos theory, tradeoffs, tricks
Post by: Rainbow Sally on January 29, 2005, 07:10:17 pm
GetDbgType info

This is a pseudo class demo, another taste of OOP while I
get the next generation of OOPz ready.


Creates a single object named gdt through which all public
functions and variables can be accessed.  No inheritance,
no "make", no "create" and no "new", but this shows the basic
idea of simple OOP in C.

Here are the tradeoffs compared to a message passing OOP
system such as the one used in the Win32 API.

Code: [Select]

this                            that

calls through func ptrs         "interprets" messages

all calls equally fast          msgs after first few are slow
                                even if threaded.

can be superclassed             can only be superclassed if
                                the interpreter itself is
                                a function pointer variable

no global inits/checks          can do inits and checks for
                                all methods before case-switches
harder to write                 easier to write

better type checking            worse

any return type is ok           return types must be cast or
                                have variable's addr on stack

Let us begin...

Code: [Select]

// GetDbgType.h

#include <windows.h>
#include <stdio.h>


// Functions

gdt.InitOnce()          fully automatic, usually never called
gdt.CountTypes()        counts the number of debug type dirs
gdt.HasType(TypeId)     returns t/f; TypeId should be
gdt.FindType(TypeId)    returns index # 1-based; see note above

// Variables

    int nDirs;      same as CountTypes, but must be initialized!
    misc stuff...


typedef struct _gdt_t
    // public initialized
    int is_inited;
    int(*CountTypes)(void);     // not a msg, no case switch
    int(*HasType)(int arg);     // not a msg, no case switch
    int(*GetTypeId)(int arg);   // not a msg, no case switch
    int (*FindType)(int arg);   // not a msg, no case switch

    // public/protected uninitialized variables
    int nDirs;
    int sizeDirs; // 28 bytes per dir
    PIMAGE_DOS_HEADER pehdr;    // 'MZ'...
    PIMAGE_NT_HEADERS pnhdr;    // 'PE'...
    PIMAGE_DATA_DIRECTORY pde;  // list in lo mem
    PIMAGE_DEBUG_DIRECTORY pdd;     // addr in .data
    PIMAGE_DEBUG_DIRECTORY pddEnd;  // total size in .data

// the public interface

extern gdt_t gdt;           // "create" one that we can find

// GetDbgType.c
// hidden nutz and boltz

static void GDT_Noop(void)  // func to turn InitOnce() off
    __asm ret

static void GDT_InitOnce(void)
    if(gdt.is_inited != (int)&gdt.is_inited)
        gdt.InitOnce = (void*)GDT_Noop; // faster bypass
        gdt.pehdr = (PIMAGE_DOS_HEADER)GetModuleHandle(NULL);
        gdt.pnhdr = (PIMAGE_NT_HEADERS)((PBYTE)gdt.pehdr + gdt.pehdr->e_lfanew);
        gdt.pde = &gdt.pnhdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
        if (gdt.pde->Size != 0)
            gdt.pdd = (PIMAGE_DEBUG_DIRECTORY)((PBYTE)gdt.pehdr + gdt.pde->VirtualAddress);
            gdt.pddEnd = (PIMAGE_DEBUG_DIRECTORY)((PBYTE)gdt.pdd + gdt.pde->Size);
            gdt.sizeDirs = ((PCHAR)gdt.pddEnd-(PCHAR)gdt.pdd);
        gdt.is_inited = (int)&gdt.is_inited; // a 'self' pointer

static int GDT_CountTypes(void)
    if (gdt.pde->Size == 0) return 0;
    return gdt.nDirs;

static int GDT_FindType(int arg)
    if (gdt.pde->Size == 0) return 0;

    int cvfound = 0;
    for (int i=0; i<gdt.nDirs; i++)
        if (gdt.GetTypeId(i) == arg)
            cvfound=i+1; // index is 1-based
    return cvfound;

static int GDT_HasType(int arg)
    return GDT_FindType(arg)? 1: 0; // only returns t/f

static int GDT_GetTypeId(int arg)
    if (gdt.pde->Size == 0) return 0;
    if (arg >= gdt.nDirs) return 0;
    return gdt.pdd[arg].Type;

// compile-time initialization for single obj of class

gdt_t gdt=
    0,                  // inited -- will equal &gdt later
    GDT_InitOnce,       // function list
    GDT_CountTypes,     // must match order
    GDT_HasType,        // declared in typedef
    GDT_GetTypeId,      // ...

// main.c
// tester..
#include <stdlib.h> // malloc
int WinPrintf(char* fmt, ...)
    int rcode;      char* tmp=malloc(4096);
    va_list args;   va_start(args, fmt);
    vsprintf(tmp, fmt, args);   va_end(args);
    rcode = MessageBox(NULL, tmp, "WinPrintf -- Message", MB_OK);
    free (tmp);     return rcode;

int main(void)
    int nTypes;
    WinPrintf("There are %d types of debug info in the file.\n", nTypes);
    // search for codeview
        WinPrintf("The file does have CodeView debug info "
        "in directory #%d\n", gdt.FindType(IMAGE_DEBUG_TYPE_CODEVIEW));
        WinPrintf("No CodeView info..\n");
    return 0;