Example #1
0
        /// <summary>
        /// Converts function parameters to C# and appends to sb like "(...);\r\n".
        /// _i must be at '('. Finally will be after ')'.
        /// </summary>
        void _ConvertParameters(StringBuilder sb, string parentName, _TypeContext context)
        {
            if (!_TokIsChar(_i, '('))
            {
                _Err(_i, "unexpected");
            }
            _i++;
            sb.Append('(');

            if (!_TokIsChar(_i, ')'))
            {
                for (int iParam = 0; ; iParam++, _i++)
                {
                    //ignore ...
                    if (_TokIsChar(_i, '.') && _TokIsChar(_i + 1, '.') && _TokIsChar(_i + 2, '.') && _TokIsChar(_i + 3, ')'))
                    {
                        _i += 3;
                        sb.Remove(sb.Length - 2, 2);                         //", "
                        break;
                    }

                    _PARAMDATA t;
                    _ParseParamOrMember(context, out t, parentName, iParam + 1);

                    //skip default value of optional parameter
                    if (_TokIsChar(_i, '='))
                    {
                        while (!_TokIsChar(++_i, ',', ')'))
                        {
                        }
                    }

                    //is ',' or ')'?
                    bool isLast = _TokIsChar(_i, ')');
                    if (!isLast && !_TokIsChar(_i, ','))
                    {
                        _Err(_i, "unexpected");
                    }

                    if (t.attributes != null)
                    {
                        sb.Append(t.attributes); sb.Append(' ');
                    }
                    sb.Append(t.typeName); sb.Append(' '); sb.Append(t.name);
                    if (!isLast)
                    {
                        sb.Append(", ");
                    }

                    if (isLast)
                    {
                        break;
                    }
                }
            }
            _i++;             //skip ')'
            sb.Append(");\r\n");
        }
Example #2
0
        /// <summary>
        /// Converts type name/pointer to C# type name.
        /// The return value is type name, possibly with * or []. If parameter, also can have ref/out/in and [In]/[Out].
        /// </summary>
        /// <param name="t">The type.</param>
        /// <param name="ptr">Pointer level. The function may adjust it depending on typedef pointer level etc.</param>
        /// <param name="isConst">Is const.</param>
        /// <param name="iTokTypename">Type name token index. Can be 0 if don't need to unalias etc; then just adds pointer/ref if need.</param>
        /// <param name="context">Depending on it char* will be converted to "string" etc.</param>
        /// <param name="attributes">Receives null or MarshalAs attribute.</param>
        /// <param name="iSAL">SAL token index, or 0 if no SAL.</param>
        string _ConvertTypeName(_Symbol t, ref int ptr, bool isConst, int iTokTypename, _TypeContext context, out string attributes, int iSAL = 0)
        {
            attributes = null;
            string name, marshalAs = null;

            bool isLangType = false, isParameter = false, isCOM = false, isBlittable = false, isRawPtr = false;

            switch (context)
            {
            case _TypeContext.Parameter:
            case _TypeContext.DelegateParameter: isParameter = true; break;

            case _TypeContext.ComParameter: isParameter = true; isCOM = true; break;

            case _TypeContext.ComReturn: isCOM = true; break;
            }

            bool _In_ = false, _Out_ = false, _Inout_ = false;

            if (iSAL > 0)
            {
                //AOutput.Write(_tok[iSAL]);
                if (_TokStarts(iSAL, "_In_"))
                {
                    _In_ = true;
                }
                else if (_TokStarts(iSAL, "_Out"))
                {
                    _Out_ = true;
                }
                else if (_TokStarts(iSAL, "_Inout_"))
                {
                    _Inout_ = true;
                }
                else
                {
                    _Err(iSAL, "unknown SAL");
                }
            }

            if (iTokTypename != 0)
            {
                ptr += _Unalias(iTokTypename, ref t, ref isConst);
                name = t.csTypename;

                var c = t as _CppType;
                if (c != null)
                {
                    isLangType  = true;
                    isBlittable = true;
                    switch (name)
                    {
                    case "char":
                        isBlittable = false;
                        if (ptr == 1)                          //not 'if(ptr != 0)', because cannot be 'ref string'
                        {
                            ptr = 0;
                            bool isBSTR = _TokIs(iTokTypename, "BSTR");

                            switch (context)
                            {
                            case _TypeContext.Member:
                                if (isConst || isBSTR)
                                {
                                    name = "string";
                                    if (isBSTR)
                                    {
                                        marshalAs = "BStr";
                                    }
                                }
                                else
                                {
                                    //string dangerous, because if the callee changes member pointer, .NET tries to free the new string with CoTaskMemFree.
                                    ptr = 1;
                                    //AOutput.Write(_DebugGetLine(iTokTypename));
                                    isRawPtr = true;
                                }
                                break;

                            case _TypeContext.Return:
                            case _TypeContext.ComReturn:
                                ptr      = 1;                            //if string, .NET tries to free the return value
                                isRawPtr = true;
                                break;

                            case _TypeContext.DelegateParameter:
                                ptr      = 1;                            //because some are "LPSTR or WORD". Rarely used.
                                isRawPtr = true;
                                break;

                            case _TypeContext.Parameter:
                            case _TypeContext.ComParameter:
                                Debug.Assert(!(isConst && (_Out_ || _Inout_)));
                                if (isConst || _In_ || isBSTR)
                                {
                                    name = "string";
                                    if (isCOM)
                                    {
                                        //if(!isBSTR) AOutput.Write(_tok[iTokTypename]);
                                        if (!isBSTR)
                                        {
                                            marshalAs = "LPWStr";
                                        }
                                    }
                                    else
                                    {
                                        if (isBSTR)
                                        {
                                            marshalAs = "BStr";
                                        }
                                    }
                                }
                                else
                                {
                                    ptr      = 1;
                                    isRawPtr = true;
                                    //Could be StringBuilder, but the Au library does not use it, it is slow.
                                    //Or [Out] char[]. The Au library uses it with Util.AMemoryArray.Char_.
                                }
                                break;
                            }
                        }
                        else if (ptr > 1)
                        {
                            isRawPtr = true;
                            isConst  = false;
                        }
                        break;

                    case "int":
                        if (_TokIs(iTokTypename, "BOOL"))
                        {
                            if (ptr == 0 || (ptr == 1 && isParameter))
                            {
                                name = "bool";
                                if (isCOM)
                                {
                                    marshalAs = "Bool";
                                }
                                isBlittable = false;
                            }
                        }
                        break;

                    case "bool":
                        marshalAs   = "U1";
                        isBlittable = false;
                        break;

                    case "void":
                    case "byte":
                    case "sbyte":
                        if (ptr > 0)
                        {
                            isRawPtr = true;
                        }
                        break;

                    case "double":
                        if (_TokIs(iTokTypename, "DATE"))
                        {
                            if (ptr == 0 || (ptr == 1 && isParameter))
                            {
                                name        = "DateTime";
                                isBlittable = false;
                            }
                        }
                        break;
                    }
                    if (isRawPtr)
                    {
                        isBlittable = true;
                    }
                }
            }
            else
            {
                name = t.csTypename;
            }

            if (!isLangType)
            {
                var ts = t as _Struct;
                if (ts != null)
                {
                    if (ts.isInterface)
                    {
                        //OutList(ptr, ts.csTypename);
                        if (ptr == 0)
                        {
                            _Err(iTokTypename, "unexpected");
                        }
                        ptr--;
                        switch (name)
                        {
                        case "IUnknown":
                            marshalAs = name;
                            name      = "Object";
                            break;
                            //case "IDispatch": //not sure should this be used, because we don't convert SDK interfaces to C# IDispatch interfaces
                            //	marshalAs = name;
                            //	name = "Object";
                            //	break;
                        }
                    }
                    else if (!ts.isClass)
                    {
                        switch (name)
                        {
                        case "AWnd":
                        case "LPARAM": isBlittable = true; break;

                        case "GUID": name = "Guid"; break;

                        case "DECIMAL": name = "decimal"; break;

                        case "VARIANT":
                            if (context == _TypeContext.ComParameter)
                            {
                                name = "object";
                            }
                            break;

                        //case "SAFEARRAY": //in SDK used only with SafeArrayX functions, with several other not-important functions and as [PROP]VARIANT members
                        //AOutput.Write(ptr);
                        //break;
                        case "ITEMIDLIST":
                            if (ptr > 0)
                            {
                                ptr--; name = "IntPtr"; isBlittable = true;
                            }
                            //else _Err(iTokTypename, "example"); //0 in SDK
                            break;

                        case "POINTL": name = "POINT"; break;

                        case "RECTL": name = "RECT"; break;
                        }
                    }
                }
                else if (t is _Enum)
                {
                    isBlittable = true;
                }
            }

            if (ptr > 0)
            {
                __ctn.Clear();
                bool isArray = false;
                if (!isRawPtr && isParameter)
                {
                    string sal = null;
                    if (iSAL > 0)
                    {
                        sal = _TokToString(iSAL);
                    }

                    if (iSAL > 0 && ptr == 1)                      //if ptr>1, can be TYPE[]* or TYPE*[]
                    {
                        if (_In_ && (sal.Contains("_reads_") || sal.Contains("count")))
                        {
                            //OutList(_tok[iTokTypename], name, _DebugGetLine(iTokTypename));
                            isArray = true;
                            __ctn.Append("[In] ");
                        }
                        if (_Inout_ && (sal.Contains("_updates_") || sal.Contains("count")))
                        {
                            //OutList(_tok[iTokTypename], name, _DebugGetLine(iTokTypename));
                            isArray = true;
                            __ctn.Append("[In,Out] ");
                        }
                        if (_Out_ && (sal.Contains("_writes_") || sal.Contains("count")))
                        {
                            //OutList(_tok[iTokTypename], name, _DebugGetLine(iTokTypename));
                            isArray = true;
                            __ctn.Append("[Out] ");
                        }
                    }

                    if (_Inout_)
                    {
                        isConst = false;
                    }

                    if (isArray)
                    {
                        ptr--;
                    }
                    else
                    {
                        ptr--;

                        if (_Out_)
                        {
                            __ctn.Append("out ");
                        }
                        else if (_In_ || isConst)
                        {
                            if (isBlittable)
                            {
                                if (isConst && ptr == 0 && name != "IntPtr")
                                {
                                    //OutList(_tok[iTokTypename], name, _DebugGetLine(iTokTypename));
                                    isArray = true;                                     //usually array, because there is no sense for eg 'const int* param', unless it is a 64-bit value (SDK usually then uses LARGE_INTEGER etc, not __int64). Those with just _In_ usually are not arrays, because for arrays are used _In_reads_ etc.
                                }
                                else
                                {
                                    __ctn.Append("in ");
                                    //OutList(_tok[iTokTypename], name, _DebugGetLine(iTokTypename));
                                }
                            }
                            else
                            {
                                if (isConst)
                                {
                                    __ctn.Append("in ");                                     //prevents copying non-blittable types back to the caller when don't need
                                }
                                else
                                {
                                    //OutList(_tok[iTokTypename], name, _DebugGetLine(iTokTypename));
                                    //__ctn.Append("in "); //no, because there are many errors in SDK where inout parameters have _In_
                                    __ctn.Append("ref ");
                                }
                            }
                        }
                        else
                        {
                            __ctn.Append("ref ");
                        }
                    }

                    if (isArray)
                    {
                        bool useMarshalAsSubtype = false;
                        if (isCOM)
                        {
                            //by default marshals as SAFEARRAY
                            if (marshalAs == null)
                            {
                                marshalAs = "LPArray";
                            }
                            else
                            {
                                useMarshalAsSubtype = true;
                            }
                        }
                        else if (context == _TypeContext.DelegateParameter)
                        {
                            isArray = false;
                            ptr++;
                            __ctn.Clear();
                            //maybe can be array, not tested. Never mind, in SDK only 4 rarely used.
                            //OutList(_tok[iTokTypename], name, _DebugGetLine(iTokTypename));
                        }
                        else if (marshalAs != null)
                        {
                            useMarshalAsSubtype = true;
                        }

                        if (useMarshalAsSubtype)
                        {
                            marshalAs = "LPArray, ArraySubType = UnmanagedType." + marshalAs;
                        }
                    }
                }                 //if(isParameter)

                __ctn.Append(name);
                if (ptr > 0)
                {
                    __ctn.Append('*', ptr);
                }
                if (isArray)
                {
                    __ctn.Append("[]");
                }

                name = __ctn.ToString();
            }

            if (marshalAs != null)
            {
                __ctn.Clear();
                string ret = null; if (context == _TypeContext.Return || context == _TypeContext.ComReturn)
                {
                    ret = "return: ";
                }
                attributes = $"[{ret}MarshalAs(UnmanagedType.{marshalAs})]";
            }
            return(name);
        }
Example #3
0
        /// <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;
            }
        }