void _DeclareFunction() { //now we expect one of: // function declaration, like TYPE __stdcall Func(TYPE a, TYPE b); // global variable, which can be: // previously-defined type, like TYPE var; // now-defined function type, like TYPE (*var)(TYPE a, TYPE b); var d = new _FINDTYPEDATA(); _FindTypename(false, ref d); _i++; //pointer int ptr = 0; while (_TokIsChar(_i, '*', '&')) { _i++; ptr++; } if (!_TokIsIdent(_i)) { //could be 'T (*var)(...);' //0 in SDK //_Err(_i, "unexpected"); _SkipStatement(true); return; } int iCallConv = 0; if (_TokIsIdent(_i + 1)) { iCallConv = _i++; } if (!_TokIsChar(_i + 1, '(')) { //could be 'T var;' //1 in SDK //_Err(_i, "unexpected"); _i = d.outTypenameToken; if (!_ExternConst()) { _SkipStatement(true); } return; } string name = _TokToString(_i++); //skip some if (name.IndexOf('_') > 0) { if (name.Ends("_UserSize") || name.Ends("_UserMarshal") || name.Ends("_UserUnmarshal") || name.Ends("_UserFree") || name.Ends("_UserSize64") || name.Ends("_UserMarshal64") || name.Ends("_UserUnmarshal64") || name.Ends("_UserFree64") ) { _SkipStatement(false); return; } } string callConv = iCallConv == 0 ? "Cdecl" : _ConvertCallConv(iCallConv); string returnType, returnAttr = null; bool isHRESULT = false; if (ptr == 0 && _TokIs(d.outTypenameToken, "HRESULT")) { isHRESULT = true; returnType = "int"; } else { returnType = _ConvertTypeName(d.outSym, ref ptr, d.outIsConst, d.outTypenameToken, _TypeContext.Return, out returnAttr); } string dll, nameInDll = null; if (_funcDllMap.TryGetValue(name, out dll)) { int i = dll.IndexOf('|'); if (i > 0) { nameInDll = dll.Substring(i + 1); dll = dll.Substring(0, i); //AOutput.Write(nameInDll); } else if (name.Starts("K32")) { //AOutput.Write(name); nameInDll = name; name = name.Substring(3); if (name.Ends("W")) { name = name.Remove(name.Length - 1); } else if (name.Ends("A")) { _SkipStatement(false); return; } } } else { bool skip = false; if (name.Contains("_")) { skip = true; //mostly CRT library functions, X_Proxy/X_Stub, X_UserMarshal and similar } else if (name.Starts("Dll")) { skip = true; //DllInstall, DllRegisterServer etc } else if (name.Starts("Ndr") || name.Starts("Rpc")) { skip = true; //undocumented } else { //AOutput.Write(name); skip = true; //all these in SDK others are undocumented, or documented as deprecated/removed _funcUnknownDll.Add(name); } if (skip) { _SkipStatement(); return; } dll = "?"; } var sb = _sbFuncTemp; sb.Clear(); sb.Append("\r\n[DllImport(\""); sb.Append(dll); sb.Append('\"'); if (nameInDll != null) { sb.AppendFormat(", EntryPoint=\"{0}\"", nameInDll); } if (callConv != null) { sb.AppendFormat(", CallingConvention=CallingConvention.{0}", callConv); } if (isHRESULT) { sb.Append(", PreserveSig=true"); //default, but makes clear that it returns HRESULT and easier to change to 'false' } sb.AppendLine(")]"); if (returnAttr != null) { sb.AppendLine(returnAttr); } sb.Append("internal static extern "); sb.Append(returnType); sb.Append(' '); sb.Append(name); _ConvertParameters(sb, name, _TypeContext.Parameter); string decl = sb.ToString(); _func[name] = decl; //try { _func.Add(name, decl); } //catch { //about 10 in SDK. The second declarations are identical or better (without tagSTRUCT). // AOutput.Write("----"); // AOutput.Write(name); // AOutput.Write(_func[name]); // AOutput.Write(decl); //} if (!_TokIsChar(_i, ';')) { _Err(_i, "unexpected"); } }
/// <summary> /// Converts C++ function parameter or struct member definition (type, name, const etc) to C# typename/name/etc. /// _i must be at its start. Finally it will be after the parsed part. Does not check whether it is followed by ',' etc. /// </summary> /// <param name="context">Member, Parameter or DelegateParameter.</param> /// <param name="t">Receives C# typename, name etc.</param> /// <param name="parentName">The function/struct name. Used to auto-create names for nameless parameters.</param> /// <param name="iParam">1-based index of parameter/member. Used to auto-create names for nameless parameters.</param> void _ParseParamOrMember(_TypeContext context, out _PARAMDATA t, string parentName, int iParam) { bool isMember = context == _TypeContext.Member; t = new _PARAMDATA(); int iSAL = 0; if (_TokIsChar(_i, '^') && _TokIsChar(_i + 1, '\"')) { _i++; if (!isMember) { iSAL = _i; _tok[iSAL] = new _Token(_tok[iSAL].s + 1, _tok[iSAL].len - 2); } _i++; } var d = new _FINDTYPEDATA(); _FindTypename(isMember, ref d); if (d.outIsNestedTypeDefinition) { if (_TokIsChar(_i, ';')) { t.isNestedTypeDefinitionWithoutVariables = true; t.isAnonymousTypeDefinitionWithoutVariables = d.outIsAnonymousTypeDefinition; t.typeName = d.outSym.csTypename; return; } } else { _i++; } //pointer int ptr = 0; while (_TokIsChar(_i, '*', '&')) { _i++; ptr++; } //suport inline function type definition bool isFunc = !d.outIsNestedTypeDefinition && _DetectIsFuncType(_i); if (isFunc) { var f = new _INLINEFUNCTYPEDATA(parentName, iParam); _DeclareTypedefFunc(d.outSym, ptr, d.outIsConst, d.outTypenameToken, f); t.typeName = f.typeName; t.name = f.paramName; } else { //typename, param/member name t.typeName = _ConvertTypeName(d.outSym, ref ptr, d.outIsConst, d.outTypenameToken, context, out t.attributes, iSAL); if (_TokIsIdent(_i)) { t.name = _TokToString(_i++); } else if (!isMember && _TokIsChar(_i, ",)[=")) { t.name = "param" + iParam; } else { _Err(_i, "no name"); } } if (_TokIsChar(_i, '[')) { _ConvertCArray(ref t.typeName, ref t.name, ref t.attributes, !isMember); } //escape names that are C# keywords if (_csKeywords.Contains(t.name)) { //AOutput.Write(t.name); t.name = "@" + t.name; } }
/// <summary> /// Finds typename. Gets its _Symbol etc. /// Starts searching from _i. Finally _i will be typename token index. /// Error if not found. /// Initially sets all outX=0/false/null. /// If there is 'const', sets outIsConst=true. /// If there is 'struct' etc as nested definition, converts the definition, sets outIsNestedStruct=true; then _i finally will be after }, which can be semicolon, variable name or * variable name. /// If there is 'struct' etc as forward declaration, adds forward declaration. /// </summary> void _FindTypename(bool isMember, ref _FINDTYPEDATA d) { d.outSym = null; d.outIsConst = false; d.outIsNestedTypeDefinition = false; d.outTypenameToken = 0; //process keywords until typename for (; _TokIsIdent(_i); _i++) { d.outSym = _FindSymbol(_i, true); var k = d.outSym as _Keyword; if (k == null) { d.outTypenameToken = _i; return; } switch (k.kwType) { case _KeywordT.TypeDecl: //is nested struct/enum/typedef definition? if (isMember) { bool isDef = false; if (_TokIsChar(_i, 't')) { isDef = true; } else { int j = _i + 1; if (_TokIsIdent(j)) { j++; } if (_TokIsChar(j, "{:;")) { isDef = true; } } if (isDef) { _DeclareType(ref d); d.outIsNestedTypeDefinition = true; return; } } //inline forward declaration d.outSym = _InlineForwardDeclaration(); d.outTypenameToken = _i; return; case _KeywordT.Normal: if (_TokIs(_i, "const")) { d.outIsConst = true; continue; } break; } _Err(_i, "unexpected"); } _Err(_i, "no type"); }
void _Statement() { //try { g0: _Symbol x = _FindSymbol(_i, true); var k = x as _Keyword; if (k != null) { if (k.cannotStartStatement) { _Err(_i, "unexpected"); } if (k.kwType == _KeywordT.TypeDecl) { //is forward decl like 'struct X* Func(...);'? if (!_TokIsChar(_i, 't') && _TokIsChar(_i + 2, '*', '&')) { _InlineForwardDeclaration(); goto g0; } var ftd = new _FINDTYPEDATA(); //just for ref parameter _DeclareType(ref ftd, true); } else if (k.kwType == _KeywordT.IgnoreFuncEtc) { _SkipStatement(); return; } else if (_TokIs(_i, "extern")) { if (_TokIsChar(_i + 1, '\"')) //extern "C" { _i++; if (_TokIsChar(_i + 1, '{')) { _i++; } return; } else //extern T X { if (_TokIs(++_i, "const")) { _i++; } if (!_ExternConst()) { _SkipStatement(); } } } else if (_TokIs(_i, "const")) { _i++; if (!_ExternConst(true)) { _SkipStatement(); } } else { //can be: //namespace _Err(_i, "unexpected"); //TODO } if (!_TokIsChar(_i, ';')) { _Err(_i, "unexpected"); } } else //a type { _DeclareFunction(); } //} //catch(ConverterException e) { // //AOutput.Write(e); // AWnd.FindFast(null, "QM_Editor").SendS(Api.WM_SETTEXT, 1, $"M \"api_converter_error\" A(||) {e.Message}||{_cppFile}||{e.Offset}"); // if(ADialog.Show("Error. Skip statement and continue?", e.Message, "Yes|No").ButtonName != "Yes") throw e as Exception; // _SkipStatement(); // } }