1

I would like to retrieve a list of all the structs in a header file, e.g. a selection of structs in CommCtrl.h:

LVCOLUMNW,LVITEMW,REBARINFO,TVITEMW

This is related to the wider goal of starting with a list of structs, and retrieving their sizeof values:

[STRUCT=sizeof64:sizeof32]
LVCOLUMNW=56:44
LVITEMW=88:60
REBARINFO=16:12
TVITEMW=56:40

Currently I compile cpp files as x64/x32 exes to determine whether a header file contains a struct (blanks are returned on failure), and to determine a struct's sizeof value:

#define UNICODE 1
#include <iostream>
#include <Windows.h>

int main()
{
    std::cout << sizeof(BITMAPINFOHEADER) << std::endl;
    return 0;
}

If I could refer to struct names dynamically, or ignore invalid struct names, then I could do this far more efficiently.

Ultimately I would like to apply the code above to this list of 19486 'Win words': http://katahiromz.web.fc2.com/win32/winwords.txt

Another idea would be to retrieve a list of all of the currently defined struct names in a Visual Studio project, if this is possible.

vafylec
  • 965
  • 1
  • 6
  • 23
  • The problem is that if any struct name applied to sizeof is invalid or undefined, the exe will not compile. Therefore to do sizeof for multiple structs in one exe, all the structs must be defined. [Response to a deleted comment.] – vafylec Aug 16 '17 at 21:24
  • 1
    Doesn't it also depend on the packing and how you declare the structs? If a struct is a double, bool, double, bool, it will return a different size from a double, double, bool, bool depending on the packing. – cup Aug 16 '17 at 21:52
  • AFAIK x64 and x32, in Windows, have the same packing rules, the difference is that a Ptr/UPtr will be size 8 in x64 and size 4 in x32. So structs lacking a Ptr/UPtr should be the same in x64/x32, other structs will have different offsets/padding/sizes in x64/x32. -- Another complicating factor for structs that I've just thought of is if conditions based on the Windows version number. – vafylec Aug 16 '17 at 22:05
  • Maybe (big maybe) the following will help to find out which structures are defined: https://stackoverflow.com/questions/10711952/how-to-detect-existence-of-a-class-using-sfinae then you can create a program to check sizes only for defined structs. – grek40 Aug 17 '17 at 14:52
  • I tried the script, I could get it to work with some entities, but I couldn't get it to work with structs, although I don't have that much C++ experience. Much appreciated. – vafylec Aug 23 '17 at 04:17

1 Answers1

0

Here is some provisional code to list the structs in a header file (.h file) via AHK, and to then retrieve their sizes via C++. The list generated is not guaranteed to be 100% complete, but the script has proven quite effective at retrieving struct names. Tested on CommCtrl.h and WinUser.h.

;AHK v2 script

#Warn
ListLines("Off")

;q:: ;list structs in a header file (.h file) (provisional script)
vPath := "C:\Program Files (x86)\Windows Kits\8.1\Include\um\CommCtrl.h"
;vPath := "C:\Program Files (x86)\Windows Kits\8.1\Include\um\WinUser.h"
if !FileExist(vPath)
{
    MsgBox("error: file not found:`r`n" vPath)
    return
}
vText := FileRead(vPath)
vDoGetNext := 0
vTemp2 := ""
vIndent := ""
VarSetCapacity(vOutput, 1000000*2)
VarSetCapacity(vListDefine, 1000000*2)
oDict := ComObjCreate("Scripting.Dictionary")

;get struct names from 'typedef struct' definitions
;and store potential struct names from '#define' directives
Loop Parse vText, "`n", "`r"
{
    vTemp := LTrim(A_LoopField) ;remove leading spaces/tabs
    vTemp := RegExReplace(vTemp, "[ `t]+", " ")
    vTemp := RegExReplace(vTemp, " //.*")
    if (SubStr(vTemp, 1, 7) = "#define")
    {
        ;ignore numeric definitions etc
        if !RegExMatch(vTemp, "[(\\\-:" Chr(34) "]| \d")
            vListDefine .= vTemp "`r`n"
        continue
    }

    vTemp := A_LoopField
    ;if (vPos := RegExMatch(vTemp, "typedef"))
    if (vPos := RegExMatch(vTemp, "typedef struct"))
    {
        vTemp2 := vTemp
        vIndent := SubStr(vTemp, 1, vPos-1)
        vDoGetNext := 1
    }
    else if vDoGetNext
    && (SubStr(vTemp, 1, StrLen(vIndent)+1) = vIndent "}")
    {
        vTemp := RegExReplace(vTemp, "^[} ]+|[,;].*")
        if !(vTemp = "")
        && !oDict.Exists("" vTemp)
        && !(vTemp = "DUMMYUNIONNAME")
        {
            oDict.Item["" vTemp] := 1
            vOutput .= vTemp "`r`n"
            ;vOutput .= vTemp2 "`t" vTemp "`r`n"
        }
        vDoGetNext := 0
    }
}

;get struct names from stored '#define' directives
;lines of the form '#define newname oldname'
vOutput .= "`r`n"
Loop Parse vListDefine, "`n", "`r"
{
    oTemp := StrSplit(A_LoopField, " ")
    if (oTemp.Length() = 3)
    && !oDict.Exists("" oTemp.2) ;new name not seen before
    && oDict.Exists("" oTemp.3) ;old name seen before
    {
        oDict.Item["" oTemp.2] := 1
        vOutput .= oTemp.2 "`r`n"
    }
}

;get raw list of structs:
;Clipboard := RTrim(vOutput, "`r`n") "`r`n"
;MsgBox(vOutput)

vList := vOutput
VarSetCapacity(vOutput, StrLen(vList)*10*2)
Loop Parse vList, "`n", "`r"
{
    vTemp := A_LoopField
    if (vTemp = "")
    {
        vOutput .= "`r`n"
        continue
    }
    vOutput .= "std::cout << " Chr(34) vTemp "=" Chr(34) " << sizeof(" vTemp ") << std::endl;`r`n"
}

Clipboard := RTrim(vOutput, "`r`n") "`r`n"
oDict := ""
MsgBox("done")
return

Example C++ code using code generated by the AHK script.

//structs get sizes

#include "stdafx.h"
#include <iostream>
#include "Windows.h"
#include "CommCtrl.h"

int _tmain(int argc, _TCHAR* argv[])
{
    std::cout << "TVITEMA=" << sizeof(TVITEMA) << std::endl;
    std::cout << "TVITEMW=" << sizeof(TVITEMW) << std::endl;
    std::cout << "TVITEM=" << sizeof(TVITEM) << std::endl;
    std::getchar();
    return 0;
}

Note: another approach would be to retrieve unique strings from the header file, paste them into Visual Studio, wait for Visual Studio to colour the appropriate words, copy the list to WordPad, save as an rtf file, and parse the raw rtf for coloured words.

Posted here also:
C++: list structs in a header file - AutoHotkey Community

vafylec
  • 965
  • 1
  • 6
  • 23