Some notes about this:
- The code is old and shitty; I'm not really looking for feedback. Just sharing it.
- The generation has been tested for d3d8.h, d3d9.h and dinput.h
- Not all generations are 100% perfect.
Basically the biggest faults in the headers are when the functions do not contain arguments (such as much of the DirectInput header). The parser will attempt to automatically assign generic argument names for these occurrences.
defines.h
- /**
- * dxgen - (c) 2011-2013 atom0s [atom0s@live.com]
- *
- * Slim wrapper generator for Direct3D9. Parses d3d9.h for
- * interfaces and generates wrappers for each interface
- * found.
- *
- */
- #ifndef __DEFINES_H_INCLUDED__
- #define __DEFINES_H_INCLUDED__
- #if defined (_MSC_VER) && (_MSC_VER >= 1020)
- #pragma once
- #endif
- #include <Windows.h>
- #include <fstream>
- #include <iostream>
- #include <list>
- #include <map>
- #include <regex>
- #include <sstream>
- #include <string>
- /**
- *
- * Regular expressions used to locate information.
- *
- */
- const std::wregex g_vRegexInterface(L"^DECLARE_INTERFACE_\\(([a-zA-Z0-9]+), IUnknown\\)$");
- const std::wregex g_vRegexFunctions(L"^[\\s]+?STDMETHOD\\(([a-zA-Z0-9]+)\\)\\((.*)\\) PURE;$|^[\\s]+?STDMETHOD_\\(([a-zA-Z0-9]+)[,\\s]+?([a-zA-Z0-9]+)\\)\\((.*)\\) PURE;$");
- /**
- *
- * Regular expression iterator ends.
- *
- */
- const std::wsregex_iterator g_vRegexIteratorEnd;
- const std::wsregex_token_iterator g_vRegexTokenIteratorEnd;
- /**
- *
- * Function entry structure.
- *
- */
- typedef struct _FUNCTION_ENTRY {
- std::wstring Parent;
- std::wstring RawFunction;
- std::wstring Return;
- std::wstring Function;
- std::wstring RawArguments;
- std::wstring FixedArguments;
- } functionentry_t;
- /**
- *
- * Base interface header template.
- *
- */
- const wchar_t* g_vHeaderTemplate[] =
- {
- L"",
- L"/**",
- L" * new{INTERFACE}.h - {INTERFACE} Wrapper Header",
- L" *",
- L" * This file was generated using d3dxgen!atom0s.cpp",
- L" * (c) 2011-2013 atom0s [atom0s@live.com]",
- L" */",
- L"",
- L"#pragma once",
- L"",
- L"#ifndef __{INTERFACEUPPER}_H_INCLUDED__",
- L"#define __{INTERFACEUPPER}_H_INCLUDED__",
- L"",
- L"#include <Windows.h>",
- L"#include <d3d9.h>",
- L"",
- L"interface new{INTERFACE} : public {INTERFACE}",
- L"{",
- L"public:",
- L"{CLASS_DATA}",
- L"",
- L"public:",
- L" new{INTERFACE}( {INTERFACE}** ppOrigInterface );",
- L" virtual ~new{INTERFACE}( void );",
- L"",
- L"private:",
- L" {INTERFACE}* m_vOrigInterface;",
- L"};",
- L"",
- L"#endif // __{INTERFACEUPPER}_H_INCLUDED__"
- };
- /**
- *
- * Base interface source template.
- *
- */
- const wchar_t* g_vSourceTemplate[] =
- {
- L"",
- L"/**",
- L" * new{INTERFACE}.cpp - {INTERFACE} Wrapper Source File",
- L" *",
- L" * This file was generated using d3dxgen!atom0s.cpp",
- L" * (c) 2011-2013 atom0s [atom0s@live.com]",
- L" */",
- L"",
- L"#include \"new{INTERFACE}.h\"",
- L"",
- L"new{INTERFACE}::new{INTERFACE}( {INTERFACE}** ppOrigInterface )",
- L"{",
- L" this->m_vOrigInterface = *ppOrigInterface;",
- L"}",
- L"new{INTERFACE}::~new{INTERFACE}( void )",
- L"{",
- L"}",
- L""
- };
- /**
- *
- * Function definition template (header file).
- *
- */
- const std::wstring g_vFunctionTemplate = L"virtual __declspec( nothrow ) {RETURN} __stdcall {FUNCTION}({ARGUMENTS});";
- /**
- *
- * Function definition templates (source file).
- *
- */
- const std::wstring g_vSouceFunctionTemplate = L"{RETURN} new{INTERFACE}::{FUNCTION}( {ARGUMENTS} )";
- const std::wstring g_vReturnTemplateVoid = L"m_vOrigInterface->{FUNCTION}( {ARGUMENTS_CALL} );";
- const std::wstring g_vReturnTemplate = L"return " + g_vReturnTemplateVoid;
- /**
- * Wide String Replace
- *
- * Used for easily modifing template strings with tokens.
- */
- static inline DWORD WStrRep(std::wstring& wstrInput, const std::wstring& wstrWhat, const std::wstring& wstrWith)
- {
- size_t nPosition = wstrInput.find(wstrWhat, 0);
- int nMatches = 0;
- while (nPosition != std::wstring::npos)
- {
- wstrInput.replace(nPosition, wstrWhat.size(), wstrWith);
- nPosition = wstrInput.find(wstrWhat, nPosition);
- nMatches++;
- }
- return nMatches;
- }
- /**
- * Converts the input string to lower-case.
- */
- static inline std::wstring& WStrLower(std::wstring& wstrInput)
- {
- std::transform(wstrInput.begin(), wstrInput.end(), wstrInput.begin(), ::tolower);
- return wstrInput;
- }
- /**
- * Converts the input string to upper-case.
- */
- static inline std::wstring& WStrUpper(std::wstring& wstrInput)
- {
- std::transform(wstrInput.begin(), wstrInput.end(), wstrInput.begin(), ::toupper);
- return wstrInput;
- }
- /**
- * Trim
- *
- * Removes whitespace from the strings beginning/end.
- */
- static inline std::wstring& trim(std::wstring& input)
- {
- input.erase(0, input.find_first_not_of(L' '));
- input.erase(input.find_last_not_of(L' ') + 1);
- return input;
- }
- /**
- * RemoveSpecialChars
- *
- * Removes special characters from the input string.
- */
- static inline std::wstring& RemoveSpecialChars(std::wstring& input)
- {
- std::wstring wstrNewString;
- static const wchar_t wszInvalidChars[] = { L'*', L'&' };
- for (unsigned int x = 0; x < input.size(); x++)
- {
- if (input.at(x) != wszInvalidChars[0] &&
- input.at(x) != wszInvalidChars[1])
- wstrNewString += input.at(x);
- }
- input = wstrNewString;
- return input;
- }
- /**
- * BuildFunctionCall
- *
- * Builds a function based on the input information given.
- */
- static inline std::wstring BuildFunctionCall(functionentry_t& f)
- {
- //
- // Invalid Argument Variables
- //
- static const std::wstring wstrInvalidArgument = L"INVALID_ARG";
- int nInvalidCount = 0;
- //
- // Parse for function arguments..
- //
- std::list< std::wstring > listArguments;
- std::wstring::size_type start = 0;
- std::wstring::size_type end = f.RawArguments.find(L",");
- while (end != std::wstring::npos)
- {
- listArguments.push_back(trim(f.RawArguments.substr(start, end - start)));
- start = end + 1;
- end = f.RawArguments.find(L",", start);
- }
- listArguments.push_back(trim(f.RawArguments.substr(start)));
- //
- // Parse for argument variables...
- //
- std::list< std::wstring > listFuncArgs;
- for (std::list< std::wstring >::iterator iter = listArguments.begin(), iterend = listArguments.end(); iter != iterend; ++iter)
- {
- // Cleanup argument whitespace..
- const std::wstring wstrRawArgument = *iter;
- std::wstring wstrArgument = trim(std::wstring(*iter));
- // Determine space count..
- std::wstring::size_type numSpaces = std::count_if(wstrArgument.begin(), wstrArgument.end(),
- [](const wchar_t wch) { return (wch == L' '); }
- );
- // Determine how many keywords we have (ex. const, class, struct)
- std::wstring::size_type numKeywords = 0;
- numKeywords += (WStrLower(wstrArgument).find(L"class ") == -1) ? 0 : 1;
- numKeywords += (WStrLower(wstrArgument).find(L"const ") == -1) ? 0 : 1;
- numKeywords += (WStrLower(wstrArgument).find(L"struct ") == -1) ? 0 : 1;
- // Are we a normal argument with no keywords?
- if (numSpaces == 1 && numKeywords == 0)
- {
- std::wstring wstrArg = wstrRawArgument.substr(wstrRawArgument.find_last_of(L" ") + 1);
- listFuncArgs.push_back(RemoveSpecialChars(wstrArg));
- }
- // Are we an argument with keywords?
- else if (numSpaces >= 2 && numKeywords > 0)
- {
- std::wstring wstrArg = wstrRawArgument.substr(wstrRawArgument.find_last_of(L" ") + 1);
- listFuncArgs.push_back(RemoveSpecialChars(wstrArg));
- }
- // Is there a space between an astrisk?
- else if (numSpaces == 2 && numKeywords == 0)
- {
- std::wstring wstrArg = wstrRawArgument.substr(wstrRawArgument.find_last_of(L" ") + 1);
- listFuncArgs.push_back(RemoveSpecialChars(wstrArg));
- }
- else if ((numSpaces == 1 || numSpaces == 2) && numKeywords > 0)
- {
- ++nInvalidCount;
- // Create a temp argument for this invalid arg.
- std::wstringstream wstrStreamFuncArg(wstrInvalidArgument, std::ios_base::in | std::ios_base::out | std::ios_base::ate);
- wstrStreamFuncArg << (nInvalidCount - 1);
- listFuncArgs.push_back(wstrStreamFuncArg.str());
- // Fix the original functions argument list..
- std::wstringstream wstrStreamArg(wstrRawArgument, std::ios_base::in | std::ios_base::out | std::ios_base::ate);
- wstrStreamArg << L" " << wstrInvalidArgument << (nInvalidCount - 1);
- *iter = wstrStreamArg.str();
- }
- // Are we just the word void?
- else if (numSpaces == 0 && numKeywords == 0 && wstrArgument.length() == 4 && wstrArgument == L"void")
- {
- // Don't push anything or we will create invalid calls..
- }
- // Are we just a single word..
- else if (numSpaces == 0 && numKeywords == 0 && wstrArgument.length() > 0)
- {
- ++nInvalidCount;
- // Create a temp argument for this invalid arg.
- std::wstringstream wstrStreamFuncArg(wstrInvalidArgument, std::ios_base::in | std::ios_base::out | std::ios_base::ate);
- wstrStreamFuncArg << (nInvalidCount - 1);
- listFuncArgs.push_back(wstrStreamFuncArg.str());
- // Fix the original functions argument list..
- std::wstringstream wstrStreamArg(wstrRawArgument, std::ios_base::in | std::ios_base::out | std::ios_base::ate);
- wstrStreamArg << L" " << wstrInvalidArgument << (nInvalidCount - 1);
- *iter = wstrStreamArg.str();
- }
- // Completely invalid argument not recognized yet..
- else
- {
- std::wcout << L"=================================================" << std::endl;
- std::wcout << L"Could not find a valid argument while parsing: " << f.Function << L", debug info:" << std::endl;
- std::wcout << L"=================================================" << std::endl;
- std::wcout << f.RawFunction << std::endl;
- std::wcout << L" Argument: " << wstrRawArgument << std::endl;
- std::wcout << L" Space count: " << numSpaces << std::endl << L" Keyword count: " << numKeywords << std::endl;
- std::wcout << L" Arguments: " << f.RawArguments << std::endl;
- }
- }
- //
- // Build the full function with parsed data..
- //
- std::wstringstream wstrFullFunction;
- wstrFullFunction << f.Return << L" __stdcall new{INTERFACE}::" << f.Function << L"( ";
- int nCommaCount = listArguments.size() - 1;
- std::for_each(listArguments.begin(), listArguments.end(),
- [&](const std::wstring& wstr)
- {
- wstrFullFunction << wstr;
- f.FixedArguments += wstr;
- if (nCommaCount)
- {
- wstrFullFunction << L", ";
- f.FixedArguments += L", ";
- }
- --nCommaCount;
- });
- wstrFullFunction << L" )" << std::endl << L"{" << std::endl;
- if (f.Return == L"void")
- wstrFullFunction << L" m_vOrigInterface->" << f.Function << L"(";
- else
- wstrFullFunction << L" return m_vOrigInterface->" << f.Function << L"( ";
- nCommaCount = listFuncArgs.size() - 1;
- std::for_each(listFuncArgs.begin(), listFuncArgs.end(),
- [&](const std::wstring& wstr)
- {
- wstrFullFunction << wstr;
- if (nCommaCount)
- wstrFullFunction << L", ";
- --nCommaCount;
- });
- wstrFullFunction << L" );" << std::endl << L"}" << std::endl;
- return wstrFullFunction.str();
- }
- #endif // __DEFINES_H_INCLUDED__
- /**
- * dxgen - (c) 2011-2013 atom0s [atom0s@live.com]
- *
- * Slim wrapper generator for Direct3D9. Parses d3d9.h for
- * interfaces and generates wrappers for each interface
- * found.
- *
- */
- #include <Windows.h>
- #include "defines.h"
- #include <cmath>
- #include <functional>
- #include <list>
- #include <map>
- int __cdecl main(int argc, wchar_t* argv[])
- {
- // Ensure a target header was given..
- if (argc != 2 || strlen((char*)argv[1]) == 0)
- {
- std::wcout << L"ERROR: No input file was given!" << std::endl;
- std::wcout << L"Usage: dxgen.exe [input_file]" << std::endl;
- return 0;
- }
- // Attempt to load target header file..
- std::wifstream wifs((char*)argv[1]);
- if (!wifs.is_open())
- {
- std::wcout << L"ERROR: Failed to open target file, " << (char*)argv[1] << std::endl;
- return 0;
- }
- // Read and close file..
- std::wstring wstrFileData((std::istreambuf_iterator< wchar_t >(wifs)), std::istreambuf_iterator< wchar_t >());
- wifs.close();
- // Scan and dump all interfaces..
- std::wcout << std::endl;
- std::wcout << L"=====================================================" << std::endl;
- std::wcout << L"Parsing header file for interfaces..." << std::endl;
- std::wcout << L"=====================================================" << std::endl;
- std::map< std::wstring, std::wstring > mapInterfaces;
- for (std::wsregex_iterator iter_interfaces(wstrFileData.begin(), wstrFileData.end(), g_vRegexInterface); iter_interfaces != g_vRegexIteratorEnd; ++iter_interfaces)
- {
- // Copy full interface from file contents..
- int nStartPos = iter_interfaces->position();
- int nBracePos = (wstrFileData.find(L"}", nStartPos)) + 2;
- std::wstring wstrInterface(wstrFileData.substr(nStartPos, (nBracePos - nStartPos)));
- // Store this interface..
- mapInterfaces[(*iter_interfaces)[1]] = wstrInterface;
- std::wcout << L"Found interface: " << (*iter_interfaces)[1] << std::endl;
- }
- // Assure we found some interfaces..
- if (mapInterfaces.size() == 0)
- {
- std::wcout << L"ERROR: Failed to parse for any interfaces." << std::endl;
- return 0;
- }
- // Parse each interface for functions..
- std::wcout << std::endl;
- std::wcout << L"=====================================================" << std::endl;
- std::wcout << L"Parsing interfaces for functions..." << std::endl;
- std::wcout << L"=====================================================" << std::endl;
- std::map< std::pair< std::wstring, std::wstring >, std::list< functionentry_t > > mapFunctions;
- std::for_each(mapInterfaces.begin(), mapInterfaces.end(),
- [&](const std::pair< std::wstring, std::wstring >& p)
- {
- std::wcout << L"Parsing interface: " << p.first << std::endl;
- std::list< functionentry_t > listFunctions;
- for (std::wsregex_iterator iter_functions(p.second.begin(), p.second.end(), g_vRegexFunctions); iter_functions != g_vRegexIteratorEnd; ++iter_functions)
- {
- int nGroups = std::count_if(iter_functions->begin(), iter_functions->end(), [](const std::wssub_match& smatch) { return (smatch.matched == true); });
- // Create function entry..
- functionentry_t functionEntry;
- functionEntry.RawFunction = (*iter_functions)[0].str();
- functionEntry.Return = (nGroups == 3) ? L"HRESULT" : (*iter_functions)[3].str();
- functionEntry.Function = (nGroups == 3) ? (*iter_functions)[1].str() : (*iter_functions)[4].str();
- functionEntry.RawArguments = (nGroups == 3) ? (*iter_functions)[2].str() : (*iter_functions)[5].str();
- // Cleanup unneeded macros..
- WStrRep(functionEntry.RawArguments, L"THIS_", L"");
- WStrRep(functionEntry.RawArguments, L"THIS", L"void");
- // Cleanup double-spaces..
- WStrRep(functionEntry.RawArguments, L" ", L" ");
- // Store this function entry..
- listFunctions.push_back(functionEntry);
- std::wcout << L" Found function: " << functionEntry.Function << std::endl;
- }
- // Store functions.
- mapFunctions[p] = listFunctions;
- });
- // Ensure all maps have functions..
- std::wcout << std::endl;
- std::wcout << L"=====================================================" << std::endl;
- std::wcout << L"Validating interface function lists..." << std::endl;
- std::wcout << L"=====================================================" << std::endl;
- std::map< std::pair< std::wstring, std::wstring >, std::list< functionentry_t > >::iterator iter_func = mapFunctions.begin();
- while (iter_func != mapFunctions.end())
- {
- std::wcout << L"Validating interface: " << (*iter_func).first.first << " ... ";
- if ((*iter_func).second.size() == 0)
- {
- std::wcout << L"Invalid! Removing.." << std::endl;
- mapFunctions.erase(iter_func++);
- }
- else
- {
- std::wcout << L"Ok!" << std::endl;
- ++iter_func;
- }
- }
- // Prepare path information..
- wchar_t wszCurrentDirectory[MAX_PATH] = { 0 };
- GetCurrentDirectory(MAX_PATH, wszCurrentDirectory);
- std::wstring wstrOutputPath = std::wstring(wszCurrentDirectory) + L"\\includes\\";
- if (GetFileAttributes(wstrOutputPath.c_str()) == 0xFFFFFFFF)
- CreateDirectory(wstrOutputPath.c_str(), NULL);
- // Create source files for each found interface..
- std::wcout << std::endl;
- std::wcout << L"=====================================================" << std::endl;
- std::wcout << L"Creating source files for found interfaces..." << std::endl;
- std::wcout << L"=====================================================" << std::endl;
- for (auto iter = mapFunctions.begin(), iterend = mapFunctions.end(); iter != iterend; ++iter)
- {
- std::wcout << L"Creating source file: " << (*iter).first.first << L".cpp" << std::endl;
- // Iterate and create each function body..
- std::list< std::wstring > listFuncBodies;
- for (auto fiter = (*iter).second.begin(), fiterend = (*iter).second.end(); fiter != fiterend; ++fiter)
- {
- std::wcout << L" Building function: " << (*fiter).Function << std::endl;
- std::wstring wstrFunctionBody = BuildFunctionCall(*fiter);
- WStrRep(wstrFunctionBody, L"{INTERFACE}", (*iter).first.first);
- listFuncBodies.push_back(wstrFunctionBody);
- }
- // Create our output file..
- std::wofstream wofs(std::wstring(wstrOutputPath + L"new" + (*iter).first.first + L".cpp"), std::ios_base::binary);
- if (!wofs.is_open())
- {
- std::wcout << L"Failed to create file: " << (*iter).first.first << L".cpp" << std::endl;
- }
- else
- {
- std::wstring wstrSourceFile;
- std::for_each(g_vSourceTemplate, g_vSourceTemplate + (sizeof(g_vSourceTemplate) / sizeof(g_vSourceTemplate[0])),
- [&](const std::wstring& wstr)
- {
- std::wstring wstrLine = wstr;
- std::wstring wstrLower = (*iter).first.first;
- std::wstring wstrUpper = (*iter).first.first;
- std::transform(wstrLower.begin(), wstrLower.end(), wstrLower.begin(), ::tolower);
- std::transform(wstrUpper.begin(), wstrUpper.end(), wstrUpper.begin(), ::toupper);
- WStrRep(wstrLine, L"{INTERFACE}", (*iter).first.first);
- WStrRep(wstrLine, L"{INTERFACELOWER}", wstrLower);
- WStrRep(wstrLine, L"{INTERFACEUPPER}", wstrUpper);
- wstrSourceFile += wstrLine + L"\r\n";
- });
- wofs << wstrSourceFile;
- std::ostream_iterator< std::wstring, wchar_t > ositer(wofs, L"\r\n");
- std::copy(listFuncBodies.begin(), listFuncBodies.end(),
- std::ostream_iterator< std::wstring, wchar_t >(wofs, L"\r\n")
- );
- wofs.close();
- }
- }
- // Create header files for each found interface..
- std::wcout << std::endl;
- std::wcout << L"=====================================================" << std::endl;
- std::wcout << L"Creating header files for found interfaces..." << std::endl;
- std::wcout << L"=====================================================" << std::endl;
- std::for_each(mapFunctions.begin(), mapFunctions.end(),
- [&](const std::pair< std::pair< std::wstring, std::wstring >, std::list< functionentry_t > >& p)
- {
- std::wcout << L"Creating header file: " << p.first.first << L".h ... ";
- std::wofstream wofs(std::wstring(wstrOutputPath + L"new" + p.first.first + L".h"), std::ios_base::binary);
- if (!wofs.is_open())
- {
- std::wcout << L"Failed!" << std::endl;
- }
- else
- {
- // Generate header file..
- std::wstring wstrHeader;
- std::for_each(g_vHeaderTemplate, g_vHeaderTemplate + (sizeof(g_vHeaderTemplate) / sizeof(g_vHeaderTemplate[0])),
- [&](const std::wstring& wstr)
- {
- std::wstring wstrLine = wstr;
- std::wstring wstrLower = p.first.first;
- std::wstring wstrUpper = p.first.first;
- std::transform(wstrLower.begin(), wstrLower.end(), wstrLower.begin(), ::tolower);
- std::transform(wstrUpper.begin(), wstrUpper.end(), wstrUpper.begin(), ::toupper);
- WStrRep(wstrLine, L"{INTERFACE}", p.first.first);
- WStrRep(wstrLine, L"{INTERFACELOWER}", wstrLower);
- WStrRep(wstrLine, L"{INTERFACEUPPER}", wstrUpper);
- wstrHeader += wstrLine + L"\r\n";
- });
- // Generate class data..
- std::wstring wstrClassData;
- std::for_each(p.second.begin(), p.second.end(),
- [&](const functionentry_t& f)
- {
- std::wstring wstrReturn = f.Return;
- std::wstring wstrFunction = f.Function;
- std::wstring wstrArguments = f.FixedArguments;
- WStrRep(wstrArguments, L"THIS_", L"");
- WStrRep(wstrArguments, L"THIS", L"");
- trim(wstrArguments);
- if (wstrArguments.size() == 0)
- wstrArguments = L"void";
- wstrArguments.insert(wstrArguments.cbegin(), L' ');
- wstrArguments.insert(wstrArguments.cend(), L' ');
- std::wstring wstrFullFunction = g_vFunctionTemplate;
- WStrRep(wstrFullFunction, L"{RETURN}", wstrReturn);
- WStrRep(wstrFullFunction, L"{FUNCTION}", wstrFunction);
- WStrRep(wstrFullFunction, L"{ARGUMENTS}", wstrArguments);
- wstrClassData += L" " + wstrFullFunction + L"\r\n";
- });
- WStrRep(wstrHeader, L"{CLASS_DATA}", wstrClassData);
- wofs << wstrHeader;
- wofs.close();
- std::wcout << L"Ok!" << std::endl;
- }
- });
- std::cin.sync();
- std::cin.ignore();
- return 0;
- }
http://pastebin.com/jMKaQ7FK
http://pastebin.com/BxgnveUB