From 865f1acac49aa6648651de91c1b27396f8679ef1 Mon Sep 17 00:00:00 2001
From: notaz <notasas@gmail.com>
Date: Mon, 6 Apr 2015 02:55:58 +0300
Subject: [PATCH] translate: initial struct parsing for member calls

---
 tools/protoparse.h | 154 +++++++++++++++++++++++++++++++++++++++++--
 tools/translate.c  | 158 ++++++++++++++++++++++++++++++++-------------
 win32.hlist        | 143 ++++++++++++++++++++++++++++++++++------
 3 files changed, 382 insertions(+), 73 deletions(-)

diff --git a/tools/protoparse.h b/tools/protoparse.h
index 2647bba..511e337 100644
--- a/tools/protoparse.h
+++ b/tools/protoparse.h
@@ -50,6 +50,15 @@ struct parsed_proto {
 	unsigned int has_retreg:1;
 };
 
+struct parsed_struct {
+	char name[256];
+	struct {
+		int offset;
+		struct parsed_proto pp;
+	} members[64];
+	int member_count;
+};
+
 static const char *hdrfn;
 static int hdrfline = 0;
 
@@ -58,6 +67,7 @@ static void pp_copy_arg(struct parsed_proto_arg *d,
 
 static int b_pp_c_handler(char *proto, const char *fname,
 	int is_include, int is_osinc, int is_cinc);
+static int struct_handler(FILE *fhdr, char *proto, int *line);
 
 static int do_protostrs(FILE *fhdr, const char *fname, int is_include)
 {
@@ -120,8 +130,12 @@ static int do_protostrs(FILE *fhdr, const char *fname, int is_include)
 
 		hdrfline = line;
 
-		ret = b_pp_c_handler(protostr, hdrfn, is_include,
-			is_osinc, is_cinc);
+		if (!strncmp(protostr, "struct", 6)
+		    && strchr(protostr, '{') != NULL)
+			ret = struct_handler(fhdr, protostr, &line);
+		else
+			ret = b_pp_c_handler(protostr, hdrfn,
+				is_include, is_osinc, is_cinc);
 		if (ret < 0)
 			break;
 	}
@@ -165,7 +179,6 @@ static const char *known_type_mod[] = {
 	"const",
 	"signed",
 	"unsigned",
-	"struct",
 	"enum",
 	"CONST",
 	"volatile",
@@ -225,7 +238,6 @@ static const char *ignored_keywords[] = {
 	"WINADVAPI",
 };
 
-// returns ptr to char after type ends
 static int typecmp(const char *n, const char *t)
 {
 	for (; *t != 0; n++, t++) {
@@ -269,6 +281,14 @@ static int check_type(const char *name, struct parsed_type *type)
 
 	n = skip_type_mod(name);
 
+	if (!strncmp(n, "struct", 6) && my_isblank(n[6])) {
+		type->is_struct = 1;
+
+		n += 6;
+		while (my_isblank(*n))
+			n++;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(known_ptr_types); i++) {
 		if (typecmp(n, known_ptr_types[i]))
 			continue;
@@ -351,7 +371,18 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp)
 		p = sskip(p + 2);
 	}
 
-	// strip unneeded stuff
+	// allow start of line comment
+	if (p[0] == '/' && p[1] == '*') {
+		p = strstr(p + 2, "*/");
+		if (p == NULL) {
+			printf("%s:%d: multiline comments unsupported\n",
+				hdrfn, hdrfline);
+			return -1;
+		}
+		p = sskip(p + 2);
+	}
+
+	// we need remaining hints in comments, so strip / *
 	for (p1 = p; p1[0] != 0 && p1[1] != 0; p1++) {
 		if ((p1[0] == '/' && p1[1] == '*')
 		 || (p1[0] == '*' && p1[1] == '/'))
@@ -662,6 +693,77 @@ static int pp_name_cmp(const void *p1, const void *p2)
 	return strcmp(pp1->name, pp2->name);
 }
 
+static int ps_name_cmp(const void *p1, const void *p2)
+{
+	const struct parsed_struct *ps1 = p1, *ps2 = p2;
+	return strcmp(ps1->name, ps2->name);
+}
+
+// parsed struct cache
+static struct parsed_struct *ps_cache;
+static int ps_cache_size;
+static int ps_cache_alloc;
+
+static int struct_handler(FILE *fhdr, char *proto, int *line)
+{
+	struct parsed_struct *ps;
+	char lstr[256], *p;
+	int offset = 0;
+	int m = 0;
+	int ret;
+
+	if (ps_cache_size >= ps_cache_alloc) {
+		ps_cache_alloc = ps_cache_alloc * 2 + 64;
+		ps_cache = realloc(ps_cache, ps_cache_alloc
+				* sizeof(ps_cache[0]));
+		my_assert_not(ps_cache, NULL);
+		memset(ps_cache + ps_cache_size, 0,
+			(ps_cache_alloc - ps_cache_size)
+			 * sizeof(ps_cache[0]));
+	}
+
+	ps = &ps_cache[ps_cache_size++];
+	ret = sscanf(proto, "struct %255s {", ps->name);
+	if (ret != 1) {
+		printf("%s:%d: struct parse failed\n", hdrfn, *line);
+		return -1;
+	}
+
+	while (fgets(lstr, sizeof(lstr), fhdr))
+	{
+		(*line)++;
+
+		p = sskip(lstr);
+		if (p[0] == '/' && p[1] == '/')
+			continue;
+		if (p[0] == '}')
+			break;
+
+		if (m >= ARRAY_SIZE(ps->members)) {
+			printf("%s:%d: too many struct members\n",
+				hdrfn, *line);
+			return -1;
+		}
+
+		hdrfline = *line;
+		ret = parse_protostr(p, &ps->members[m].pp);
+		if (ret < 0) {
+			printf("%s:%d: struct member #%d/%02x "
+				"doesn't parse\n", hdrfn, *line,
+				m, offset);
+			return -1;
+		}
+		ps->members[m].offset = offset;
+		offset += 4;
+		m++;
+	}
+
+	ps->member_count = m;
+
+	return 0;
+}
+
+// parsed proto cache
 static struct parsed_proto *pp_cache;
 static int pp_cache_size;
 static int pp_cache_alloc;
@@ -692,7 +794,7 @@ static int b_pp_c_handler(char *proto, const char *fname,
 	return 0;
 }
 
-static void build_pp_cache(FILE *fhdr)
+static void build_caches(FILE *fhdr)
 {
 	long pos;
 	int ret;
@@ -705,6 +807,7 @@ static void build_pp_cache(FILE *fhdr)
 		exit(1);
 
 	qsort(pp_cache, pp_cache_size, sizeof(pp_cache[0]), pp_name_cmp);
+	qsort(ps_cache, ps_cache_size, sizeof(ps_cache[0]), ps_name_cmp);
 	fseek(fhdr, pos, SEEK_SET);
 }
 
@@ -716,7 +819,7 @@ static const struct parsed_proto *proto_parse(FILE *fhdr, const char *sym,
 	char *p;
 
 	if (pp_cache == NULL)
-		build_pp_cache(fhdr);
+		build_caches(fhdr);
 
 	if (sym[0] == '_') // && strncmp(fname, "stdc", 4) == 0)
 		sym++;
@@ -734,6 +837,41 @@ static const struct parsed_proto *proto_parse(FILE *fhdr, const char *sym,
 	return pp_ret;
 }
 
+static const struct parsed_proto *proto_lookup_struct(FILE *fhdr,
+	const char *type, int offset)
+{
+	struct parsed_struct ps_search, *ps;
+	int m;
+
+	if (pp_cache == NULL)
+		build_caches(fhdr);
+	if (ps_cache_size == 0)
+		return NULL;
+
+	while (my_isblank(*type))
+		type++;
+	if (!strncmp(type, "struct", 6) && my_isblank(type[6]))
+		type += 7;
+
+	if (sscanf(type, "%255s", ps_search.name) != 1)
+		return NULL;
+
+	ps = bsearch(&ps_search, ps_cache, ps_cache_size,
+			sizeof(ps_cache[0]), ps_name_cmp);
+	if (ps == NULL) {
+		printf("%s: struct '%s' is missing\n",
+			hdrfn, ps_search.name);
+		return NULL;
+	}
+
+	for (m = 0; m < ps->member_count; m++) {
+		if (ps->members[m].offset == offset)
+			return &ps->members[m].pp;
+	}
+
+	return NULL;
+}
+
 static void pp_copy_arg(struct parsed_proto_arg *d,
 	const struct parsed_proto_arg *s)
 {
@@ -833,4 +971,6 @@ static inline void proto_release(struct parsed_proto *pp)
 	if (pp->ret_type.name != NULL)
 		free(pp->ret_type.name);
 	free(pp);
+
+	(void)proto_lookup_struct;
 }
diff --git a/tools/translate.c b/tools/translate.c
index dadf7a9..bec6d07 100644
--- a/tools/translate.c
+++ b/tools/translate.c
@@ -208,7 +208,8 @@ struct parsed_op {
 };
 
 // datap:
-// OP_CALL  - parser proto hint (str)
+// on start:  function/data type hint (sctproto)
+// after analysis:
 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
 // OP_PUSH  - points to OP_POP in complex push/pop graph
 // OP_POP   - points to OP_PUSH in simple push/pop pair
@@ -641,7 +642,7 @@ static char *default_cast_to(char *buf, size_t buf_size,
 {
   buf[0] = 0;
 
-  if (!opr->is_ptr)
+  if (!opr->is_ptr || strchr(opr->name, '['))
     return buf;
   if (opr->pp == NULL || opr->pp->type.name == NULL
     || opr->pp->is_fptr)
@@ -3488,10 +3489,25 @@ static void resolve_branches_parse_calls(int opcnt)
     po->bt_i = -1;
     po->btj = NULL;
 
+    if (po->datap != NULL) {
+      pp = calloc(1, sizeof(*pp));
+      my_assert_not(pp, NULL);
+
+      ret = parse_protostr(po->datap, pp);
+      if (ret < 0)
+        ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
+      free(po->datap);
+      po->datap = NULL;
+      po->pp = pp;
+    }
+
     if (po->op == OP_CALL) {
       pp = NULL;
 
-      if (po->operand[0].type == OPT_LABEL) {
+      if (po->pp != NULL)
+        pp = po->pp;
+      else if (po->operand[0].type == OPT_LABEL)
+      {
         tmpname = opr_name(po, 0);
         if (IS_START(tmpname, "loc_"))
           ferr(po, "call to loc_*\n");
@@ -3521,16 +3537,6 @@ static void resolve_branches_parse_calls(int opcnt)
           my_assert_not(pp, NULL);
         }
       }
-      else if (po->datap != NULL) {
-        pp = calloc(1, sizeof(*pp));
-        my_assert_not(pp, NULL);
-
-        ret = parse_protostr(po->datap, pp);
-        if (ret < 0)
-          ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
-        free(po->datap);
-        po->datap = NULL;
-      }
 
       if (pp != NULL) {
         if (pp->is_fptr)
@@ -3807,36 +3813,11 @@ static void scan_prologue_epilogue(int opcnt)
   }
 }
 
-static const struct parsed_proto *resolve_icall(int i, int opcnt,
-  int *pp_i, int *multi_src)
-{
-  const struct parsed_proto *pp = NULL;
-  int search_advice = 0;
-
-  *multi_src = 0;
-  *pp_i = -1;
-
-  switch (ops[i].operand[0].type) {
-  case OPT_REGMEM:
-  case OPT_LABEL:
-  case OPT_OFFSET:
-    pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice);
-    if (!search_advice)
-      break;
-    // fallthrough
-  default:
-    scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
-      pp_i, multi_src);
-    break;
-  }
-
-  return pp;
-}
-
 // find an instruction that changed opr before i op
 // *op_i must be set to -1 by the caller
-// *entry is set to 1 if one source is determined to be the caller
+// *is_caller is set to 1 if one source is determined to be g_func arg
 // returns 1 if found, *op_i is then set to origin
+// returns -1 if multiple origins are found
 static int resolve_origin(int i, const struct parsed_opr *opr,
   int magic, int *op_i, int *is_caller)
 {
@@ -4015,6 +3996,96 @@ static int try_resolve_const(int i, const struct parsed_opr *opr,
   return -1;
 }
 
+static const struct parsed_proto *resolve_icall(int i, int opcnt,
+  int *pp_i, int *multi_src)
+{
+  const struct parsed_proto *pp = NULL;
+  int search_advice = 0;
+  int offset = -1;
+  char name[256];
+  char s_reg[4];
+  int reg, len;
+  int ret;
+
+  *multi_src = 0;
+  *pp_i = -1;
+
+  switch (ops[i].operand[0].type) {
+  case OPT_REGMEM:
+    // try to resolve struct member calls
+    ret = sscanf(ops[i].operand[0].name, "%3s+%x%n",
+            s_reg, &offset, &len);
+    if (ret == 2 && len == strlen(ops[i].operand[0].name))
+    {
+      reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
+      if (reg >= 0) {
+        struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
+        int j = -1;
+        ret = resolve_origin(i, &opr, i + opcnt * 19, &j, NULL);
+        if (ret != 1)
+          break;
+        if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
+          && ops[j].operand[0].lmod == OPLM_DWORD
+          && ops[j].pp == NULL) // no hint
+        {
+          // allow one simple dereference (directx)
+          reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
+                  ops[j].operand[1].name);
+          if (reg < 0)
+            break;
+          struct parsed_opr opr2 = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
+          int k = -1;
+          ret = resolve_origin(j, &opr2, j + opcnt * 19, &k, NULL);
+          if (ret != 1)
+            break;
+          j = k;
+        }
+        if (ops[j].op != OP_MOV)
+          break;
+        if (ops[j].operand[0].lmod != OPLM_DWORD)
+          break;
+        if (ops[j].pp != NULL) {
+          // type hint in asm
+          pp = ops[j].pp;
+        }
+        else if (ops[j].operand[1].type == OPT_REGMEM) {
+          // allow 'hello[ecx]' - assume array of same type items
+          ret = sscanf(ops[j].operand[1].name, "%[^[][e%2s]",
+                  name, s_reg);
+          if (ret != 2)
+            break;
+          pp = proto_parse(g_fhdr, name, g_quiet_pp);
+        }
+        else if (ops[j].operand[1].type == OPT_LABEL)
+          pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
+        else
+          break;
+        if (pp == NULL)
+          break;
+        if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
+          pp = NULL;
+          break;
+        }
+        pp = proto_lookup_struct(g_fhdr, pp->type.name, offset);
+      }
+      break;
+    }
+    // fallthrough
+  case OPT_LABEL:
+  case OPT_OFFSET:
+    pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice);
+    if (!search_advice)
+      break;
+    // fallthrough
+  default:
+    scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
+      pp_i, multi_src);
+    break;
+  }
+
+  return pp;
+}
+
 static struct parsed_proto *process_call_early(int i, int opcnt,
   int *adj_i)
 {
@@ -8065,11 +8136,8 @@ do_pending_endp:
 
     parse_op(&ops[pi], words, wordc);
 
-    if (sctproto != NULL) {
-      if (ops[pi].op == OP_CALL || ops[pi].op == OP_JMP)
-        ops[pi].datap = sctproto;
-      sctproto = NULL;
-    }
+    ops[pi].datap = sctproto;
+    sctproto = NULL;
     pi++;
   }
 
diff --git a/win32.hlist b/win32.hlist
index 993b322..1f90f6e 100644
--- a/win32.hlist
+++ b/win32.hlist
@@ -1865,30 +1865,131 @@ DWORD WINAPI lineTranslateDialogA(HLINEAPP,DWORD,DWORD,HWND,LPCSTR);
 DWORD WINAPI lineUnhold(HCALL);
 DWORD WINAPI lineUnparkA(HLINE,DWORD,LPHCALL,LPCSTR);
 
+struct IDirectDraw {
+          // IUnknown methods
+/*00*/    HRESULT (WINAPI *QueryInterface)(void *this, REFIID riid, void** ppvObject);
+/*04*/    ULONG (WINAPI *AddRef)(void *this);
+/*08*/    ULONG (WINAPI *Release)(void *this);
+          // IDirectDraw methods
+/*0c*/    int (WINAPI *Compact)(void *this);
+/*10*/    int (WINAPI *CreateClipper)(void *this, DWORD dwFlags, LPDIRECTDRAWCLIPPER *lplpDDClipper, IUnknown *pUnkOuter);
+/*14*/    int (WINAPI *CreatePalette)(void *this, DWORD dwFlags, LPPALETTEENTRY lpColorTable, LPDIRECTDRAWPALETTE *lplpDDPalette, IUnknown *pUnkOuter); // 14
+/*18*/    int (WINAPI *CreateSurface)(void *this, LPDDSURFACEDESC lpDDSurfaceDesc, LPDIRECTDRAWSURFACE *lplpDDSurface, IUnknown *pUnkOuter);
+/*1c*/    int (WINAPI *DuplicateSurface)(void *this, LPDIRECTDRAWSURFACE lpDDSurface, LPDIRECTDRAWSURFACE *lplpDupDDSurface);
+/*20*/    int (WINAPI *EnumDisplayModes)(void *this, DWORD dwFlags, LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext, LPDDENUMMODESCALLBACK lpEnumModesCallback);
+/*24*/    int (WINAPI *EnumSurfaces)(void *this, DWORD dwFlags, LPDDSURFACEDESC lpDDSD, LPVOID lpContext, LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback);
+/*28*/    int (WINAPI *FlipToGDISurface)(void *this);
+/*2c*/    int (WINAPI *GetCaps)(void *this, LPDDCAPS lpDDDriverCaps, LPDDCAPS lpDDHELCaps);
+/*30*/    int (WINAPI *GetDisplayMode)(void *this, LPDDSURFACEDESC lpDDSurfaceDesc);
+/*34*/    int (WINAPI *GetFourCCCodes)(void *this, LPDWORD lpNumCodes, LPDWORD lpCodes);
+/*38*/    int (WINAPI *GetGDISurface)(void *this, LPDIRECTDRAWSURFACE *lplpGDIDDSurface);
+/*3c*/    int (WINAPI *GetMonitorFrequency)(void *this, LPDWORD lpdwFrequency);
+/*40*/    int (WINAPI *GetScanLine)(void *this, LPDWORD lpdwScanLine);
+/*44*/    int (WINAPI *GetVerticalBlankStatus)(void *this, BOOL *lpbIsInVB);
+/*48*/    int (WINAPI *Initialize)(void *this, GUID *lpGUID);
+/*4c*/    int (WINAPI *RestoreDisplayMode)(void *this);
+/*50*/    int (WINAPI *SetCooperativeLevel)(void *this, HWND hWnd, DWORD dwFlags);
+/*54*/    int (WINAPI *SetDisplayMode)(void *this, DWORD dwWidth, DWORD dwHeight, DWORD dwBPP);
+/*58*/    int (WINAPI *WaitForVerticalBlank)(void *this, DWORD dwFlags, HANDLE hEvent);
+};
+
+struct IDirectDrawPalette {
+          // IUnknown methods
+/*00*/    HRESULT (WINAPI *QueryInterface)(void *this, REFIID riid, void** ppvObject);
+/*04*/    ULONG (WINAPI *AddRef)(void *this);
+/*08*/    ULONG (WINAPI *Release)(void *this);
+          // IDirectDrawPalette methods
+/*0c*/    int (WINAPI *GetCaps)(void *this, LPDWORD lpdwCaps);
+/*10*/    int (WINAPI *GetEntries)(void *this, DWORD dwFlags, DWORD dwBase, DWORD dwNumEntries, LPPALETTEENTRY lpEntries);
+/*14*/    int (WINAPI *Initialize)(void *this, LPDIRECTDRAW lpDD, DWORD dwFlags, LPPALETTEENTRY lpDDColorTable);
+/*18*/    int (WINAPI *SetEntries)(void *this, DWORD dwFlags, DWORD dwStartingEntry, DWORD dwCount, LPPALETTEENTRY lpEntries);
+};
+
+struct IDirectDrawSurface {
+          // IUnknown methods
+/*00*/    HRESULT (WINAPI *QueryInterface)(void *this, REFIID riid, void** ppvObject);
+/*04*/    ULONG (WINAPI *AddRef)(void *this);
+/*08*/    ULONG (WINAPI *Release)(void *this);
+          // IDirectDrawSurface methods
+/*0c*/    int (WINAPI *AddAttachedSurface)(void *this, LPDIRECTDRAWSURFACE lpDDSAttachedSurface);
+/*10*/    int (WINAPI *AddOverlayDirtyRect)(void *this, LPRECT lpRect);
+/*14*/    int (WINAPI *Blt)(void *this, LPRECT lpDestRect, LPDIRECTDRAWSURFACE lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwFlags, LPDDBLTFX lpDDBltFx);
+/*18*/    int (WINAPI *BltBatch)(void *this, LPDDBLTBATCH lpDDBltBatch, DWORD dwCount, DWORD dwFlags);
+/*1c*/    int (WINAPI *BltFast)(void *this, DWORD dwX, DWORD dwY, LPDIRECTDRAWSURFACE lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans);
+/*20*/    int (WINAPI *DeleteAttachedSurface)(void *this, DWORD dwFlags, LPDIRECTDRAWSURFACE lpDDSAttachedSurface);
+/*24*/    int (WINAPI *EnumAttachedSurfaces)(void *this, LPVOID lpContext, LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback);
+/*28*/    int (WINAPI *EnumOverlayZOrders)(void *this, DWORD dwFlags, LPVOID lpContext, LPDDENUMSURFACESCALLBACK lpfnCallback);
+/*2c*/    int (WINAPI *Flip)(void *this, LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride, DWORD dwFlags);
+/*30*/    int (WINAPI *GetAttachedSurface)(void *this, LPDDSCAPS lpDDSCaps, LPDIRECTDRAWSURFACE *lplpDDAttachedSurface);
+/*34*/    int (WINAPI *GetBltStatus)(void *this, DWORD dwFlags);
+/*38*/    int (WINAPI *GetCaps)(void *this, LPDDSCAPS lpDDSCaps);
+/*3c*/    int (WINAPI *GetClipper)(void *this, LPDIRECTDRAWCLIPPER *lplpDDClipper);
+/*40*/    int (WINAPI *GetColorKey)(void *this, DWORD dwFlags, LPDDCOLORKEY lpDDColorKey);
+/*44*/    int (WINAPI *GetDC)(void *this, HDC *lphDC);
+/*48*/    int (WINAPI *GetFlipStatus)(void *this, DWORD dwFlags);
+/*4c*/    int (WINAPI *GetOverlayPosition)(void *this, LPLONG lplX, LPLONG lplY);
+/*50*/    int (WINAPI *GetPalette)(void *this, LPDIRECTDRAWPALETTE *lplpDDPalette);
+/*54*/    int (WINAPI *GetPixelFormat)(void *this, LPDDPIXELFORMAT lpDDPixelFormat);
+/*58*/    int (WINAPI *GetSurfaceDesc)(void *this, LPDDSURFACEDESC lpDDSurfaceDesc);
+/*5c*/    int (WINAPI *Initialize)(void *this, LPDIRECTDRAW lpDD, LPDDSURFACEDESC lpDDSurfaceDesc);
+/*60*/    int (WINAPI *IsLost)(void *this);
+/*64*/    int (WINAPI *Lock)(void *this, LPRECT lpDestRect, LPDDSURFACEDESC lpDDSurfaceDesc, DWORD dwFlags, HANDLE hEvent);
+/*68*/    int (WINAPI *ReleaseDC)(void *this, HDC hDC);
+/*6c*/    int (WINAPI *Restore)(void *this);
+/*70*/    int (WINAPI *SetClipper)(void *this, LPDIRECTDRAWCLIPPER lpDDClipper);
+/*74*/    int (WINAPI *SetColorKey)(void *this, DWORD dwFlags, LPDDCOLORKEY lpDDColorKey);
+/*78*/    int (WINAPI *SetOverlayPosition)(void *this, LONG lX, LONG lY);
+/*7c*/    int (WINAPI *SetPalette)(void *this, LPDIRECTDRAWPALETTE lpDDPalette);
+/*80*/    int (WINAPI *Unlock)(void *this, LPVOID lpSurfaceData);
+/*84*/    int (WINAPI *UpdateOverlay)(void *this, LPRECT lpSrcRect, LPDIRECTDRAWSURFACE lpDDDestSurface, LPRECT lpDestRect, DWORD dwFlags, LPDDOVERLAYFX lpDDOverlayFx);
+/*88*/    int (WINAPI *UpdateOverlayDisplay)(void *this, DWORD dwFlags);
+/*8c*/    int (WINAPI *UpdateOverlayZOrder)(void *this, DWORD dwFlags, LPDIRECTDRAWSURFACE lpDDSReference);
+};
+
+struct IDirectSound {
+          // IUnknown methods
+/*00*/    HRESULT (WINAPI *QueryInterface)(void *this, REFIID riid, void** ppvObject);
+/*04*/    ULONG (WINAPI *AddRef)(void *this);
+/*08*/    ULONG (WINAPI *Release)(void *this);
+          // IDirectSound methods
+/*0c*/    int (WINAPI *CreateSoundBuffer)(void *this, LPCDSBUFFERDESC lpcDSBufferDesc, LPLPDIRECTSOUNDBUFFER lplpDirectSoundBuffer, IUnknown *pUnkOuter);
+/*10*/    int (WINAPI *GetCaps)(void *this, LPDSCAPS lpDSCaps);
+/*14*/    int (WINAPI *DuplicateSoundBuffer)(void *this, LPDIRECTSOUNDBUFFER lpDsbOriginal, LPLPDIRECTSOUNDBUFFER lplpDsbDuplicate);
+/*18*/    int (WINAPI *SetCooperativeLevel)(void *this, HWND hwnd, DWORD dwLevel);
+/*1c*/    int (WINAPI *Compact)(void *this);
+/*20*/    int (WINAPI *GetSpeakerConfig)(void *this, LPDWORD lpdwSpeakerConfig);
+/*24*/    int (WINAPI *SetSpeakerConfig)(void *this, DWORD dwSpeakerConfig);
+/*28*/    int (WINAPI *Initialize)(void *this, LPCGUID lpcGuid);
+};
+
+struct IDirectSoundBuffer {
+          // IUnknown methods
+/*00*/    HRESULT (WINAPI *QueryInterface)(void *this, REFIID riid, void** ppvObject);
+/*04*/    ULONG (WINAPI *AddRef)(void *this);
+/*08*/    ULONG (WINAPI *Release)(void *this);
+          // IDirectSoundBuffer methods
+/*0c*/    int (WINAPI *GetCaps)(void *this, LPDSBCAPS lpDSBufferCaps);
+/*10*/    int (WINAPI *GetCurrentPosition)(void *this, LPDWORD lpdwCurrentPlayCursor, LPDWORD lpdwCurrentWriteCursor);
+/*14*/    int (WINAPI *GetFormat)(void *this, LPWAVEFORMATEX lpwfxFormat, DWORD dwSizeAllocated, LPDWORD lpdwSizeWritten);
+/*18*/    int (WINAPI *GetVolume)(void *this, LPLONG lplVolume);
+/*1c*/    int (WINAPI *GetPan)(void *this, LPLONG lplpan);
+/*20*/    int (WINAPI *GetFrequency)(void *this, LPDWORD lpdwFrequency);
+/*24*/    int (WINAPI *GetStatus)(void *this, LPDWORD lpdwStatus);
+/*28*/    int (WINAPI *Initialize)(void *this, LPDIRECTSOUND lpDirectSound, LPCDSBUFFERDESC lpcDSBufferDesc);
+/*2c*/    int (WINAPI *Lock)(void *this, DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1, LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags);
+/*30*/    int (WINAPI *Play)(void *this, DWORD dwReserved1, DWORD dwReserved2, DWORD dwFlags);
+/*34*/    int (WINAPI *SetCurrentPosition)(void *this, DWORD dwNewPosition);
+/*38*/    int (WINAPI *SetFormat)(void *this, LPCWAVEFORMATEX lpcfxFormat);
+/*3c*/    int (WINAPI *SetVolume)(void *this, LONG lVolume);
+/*40*/    int (WINAPI *SetPan)(void *this, LONG lPan);
+/*44*/    int (WINAPI *SetFrequency)(void *this, DWORD dwFrequency);
+/*48*/    int (WINAPI *Stop)(void *this);
+/*4c*/    int (WINAPI *Unlock)(void *this, LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioPtr2);
+/*50*/    int (WINAPI *Restore)(void *this);
+};
 
 //    sctproto: int (__stdcall *Direct*Create)(void *, void *, void *)
 // 08 sctproto: int (WINAPI *dx_Release)(void *iface)
-// IDirectDraw
-// 14 sctproto: int (WINAPI *ddraw1_CreatePalette)(void *iface, DWORD flags, PALETTEENTRY *entries, void **palette, void *)
-// 18 sctproto: int (WINAPI *ddraw1_CreateSurface)(void *iface, void *surface_desc, void **surface, void *)
-// 2C sctproto: int (WINAPI *ddraw1_GetCaps)(void *iface, void *driver_caps, void *hel_caps)
-// 38 sctproto: int (WINAPI *ddraw1_GetGDISurface)(void *iface, void **surface)
-// 44 sctproto: int (WINAPI *ddraw1_GetVerticalBlankStatus)(void *iface, BOOL *status)
-// 50 sctproto: int (WINAPI *ddraw1_SetCooperativeLevel)(void *iface, HWND window, DWORD flags)
-// 54 sctproto: int (WINAPI *ddraw1_SetDisplayMode)(void *iface, DWORD width, DWORD height, DWORD bpp)
-// 58 sctproto: int (WINAPI *ddraw1_WaitForVerticalBlank)(void *iface, DWORD flags, HANDLE event)
-// IDirectDrawPalette
-// 10 sctproto: int (WINAPI *palette_GetEntries)(void *, DWORD flags, DWORD start, DWORD count, PALETTEENTRY *entries)
-// 18 sctproto: int (WINAPI *palette_SetEntries)(void *, DWORD flags, DWORD start, DWORD count, PALETTEENTRY *entries)
-// IDirectDrawSurface
-// 14 sctproto: int (WINAPI *surface1_Blt)(void *, RECT *, void *, RECT *, DWORD, void *)
-// 30 sctproto: int (WINAPI *surface1_GetAttachedSurface)(void *, void *caps, void **attachment)
-// 38 sctproto: int (WINAPI *surface1_GetCaps)(void *iface, void *caps)
-// 54 sctproto: int (WINAPI *surface1_GetPixelFormat)(void *iface, void *fmt)
-// 64 sctproto: int (WINAPI *surface1_Lock)(void *, void *, void *, DWORD, HANDLE)
-// 6C sctproto: int (WINAPI *surface1_Restore)(void *)
-// 7C sctproto: int (WINAPI *surface1_SetPalette)(void *iface, void *palette)
-// 80 sctproto: int (WINAPI *surface1_Unlock)(void *, void *)
 // IDirectSound8
 // 0C sctproto: int (WINAPI *dsound_CreateSoundBuffer)(void *iface, void *dsbd, void **ppdsb, void *lpunk)
 // 18 sctproto: int (WINAPI *dsound_SetCooperativeLevel)(void *iface, HWND hwnd, DWORD level)
-- 
2.39.5