@@ -106,7 +106,8 @@ public override bool VisitArrayType(ArrayType array, TypeQualifiers quals)
106106 Helpers . InternalStruct , Context . ReturnVarName ) ;
107107 else
108108 {
109- if ( arrayType . IsPrimitiveType ( PrimitiveType . Char ) &&
109+ if ( ( arrayType . IsPrimitiveType ( PrimitiveType . Char ) ||
110+ arrayType . IsPrimitiveType ( PrimitiveType . WideChar ) ) &&
110111 Context . Context . Options . MarshalCharAsManagedChar )
111112 {
112113 supportBefore . WriteLineIndent (
@@ -130,7 +131,8 @@ public override bool VisitArrayType(ArrayType array, TypeQualifiers quals)
130131 break ;
131132 case ArrayType . ArraySize . Incomplete :
132133 // const char* and const char[] are the same so we can use a string
133- if ( array . Type . Desugar ( ) . IsPrimitiveType ( PrimitiveType . Char ) &&
134+ if ( ( array . Type . Desugar ( ) . IsPrimitiveType ( PrimitiveType . Char ) ||
135+ array . Type . Desugar ( ) . IsPrimitiveType ( PrimitiveType . WideChar ) ) &&
134136 array . QualifiedType . Qualifiers . IsConst )
135137 return VisitPointerType ( new PointerType
136138 {
@@ -155,17 +157,16 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
155157 var isRefParam = param != null && ( param . IsInOut || param . IsOut ) ;
156158
157159 var pointee = pointer . Pointee . Desugar ( ) ;
158- bool marshalPointeeAsString = CSharpTypePrinter . IsConstCharString ( pointee ) && isRefParam ;
159-
160- if ( ( CSharpTypePrinter . IsConstCharString ( pointer ) && ! MarshalsParameter ) ||
161- marshalPointeeAsString )
160+ var finalPointee = pointer . GetFinalPointee ( ) ;
161+
162+ if ( CSharpTypePrinter . IsConstCharString ( pointer ) ||
163+ ( CSharpTypePrinter . IsConstCharString ( pointee ) && isRefParam ) )
162164 {
163165 Context . Return . Write ( MarshalStringToManaged ( Context . ReturnVarName ,
164166 pointer . GetFinalPointee ( ) . Desugar ( ) as BuiltinType ) ) ;
165167 return true ;
166168 }
167169
168- var finalPointee = pointer . GetFinalPointee ( ) ;
169170 PrimitiveType primitive ;
170171 if ( finalPointee . IsPrimitiveType ( out primitive ) || finalPointee . IsEnumType ( ) )
171172 {
@@ -237,11 +238,13 @@ public override bool VisitPrimitiveType(PrimitiveType primitive, TypeQualifiers
237238 // returned structs must be blittable and char isn't
238239 if ( Context . Context . Options . MarshalCharAsManagedChar )
239240 {
240- Context . Return . Write ( "global::System.Convert.ToChar({0})" ,
241- Context . ReturnVarName ) ;
241+ Context . Return . Write ( $ "global::System.Convert.ToChar({ Context . ReturnVarName } )") ;
242242 return true ;
243243 }
244244 goto default ;
245+ case PrimitiveType . WideChar :
246+ Context . Return . Write ( $ "new CppSharp.Runtime.WideChar({ Context . ReturnVarName } )") ;
247+ return true ;
245248 case PrimitiveType . Char16 :
246249 return false ;
247250 case PrimitiveType . Bool :
@@ -271,10 +274,10 @@ public override bool VisitTypedefType(TypedefType typedef, TypeQualifiers quals)
271274 var ptrName = Generator . GeneratedIdentifier ( "ptr" ) +
272275 Context . ParameterIndex ;
273276
274- Context . Before . WriteLine ( "var {0} = {1};" , ptrName ,
275- Context . ReturnVarName ) ;
277+ Context . Before . WriteLine ( $ "var { ptrName } = { Context . ReturnVarName } ;") ;
276278
277- var res = $ "{ ptrName } == IntPtr.Zero? null : ({ typedef } )Marshal.GetDelegateForFunctionPointer({ ptrName } , typeof({ typedef } ))";
279+ var res = $@ "{ ptrName } == IntPtr.Zero? null : ({ typedef
280+ } )Marshal.GetDelegateForFunctionPointer({ ptrName } , typeof({ typedef } ))";
278281 Context . Return . Write ( res ) ;
279282 return true ;
280283 }
@@ -286,11 +289,10 @@ public override bool VisitFunctionType(FunctionType function, TypeQualifiers qua
286289 {
287290 var ptrName = Generator . GeneratedIdentifier ( "ptr" ) + Context . ParameterIndex ;
288291
289- Context . Before . WriteLine ( "var {0} = {1};" , ptrName ,
290- Context . ReturnVarName ) ;
292+ Context . Before . WriteLine ( $ "var { ptrName } = { Context . ReturnVarName } ;") ;
291293
292- Context . Return . Write ( "({1})Marshal.GetDelegateForFunctionPointer({0}, typeof({1}))" ,
293- ptrName , function . ToString ( ) ) ;
294+ Context . Return . Write ( $@ "({ function . ToString ( )
295+ } )Marshal.GetDelegateForFunctionPointer( { ptrName } , typeof( { function . ToString ( ) } ))" ) ;
294296 return true ;
295297 }
296298
@@ -316,7 +318,7 @@ public override bool VisitClassDecl(Class @class)
316318
317319 public override bool VisitEnumDecl ( Enumeration @enum )
318320 {
319- Context . Return . Write ( "{0}" , Context . ReturnVarName ) ;
321+ Context . Return . Write ( $ " { Context . ReturnVarName } " ) ;
320322 return true ;
321323 }
322324
@@ -340,8 +342,7 @@ public override bool VisitParameterDecl(Parameter parameter)
340342 if ( ! string . IsNullOrWhiteSpace ( ctx . Return ) &&
341343 ! parameter . Type . IsPrimitiveTypeConvertibleToRef ( ) )
342344 {
343- Context . Before . WriteLine ( "var _{0} = {1};" , parameter . Name ,
344- ctx . Return ) ;
345+ Context . Before . WriteLine ( $ "var _{ parameter . Name } = { ctx . Return } ;") ;
345346 }
346347
347348 Context . Return . Write ( "{0}{1}" ,
@@ -512,12 +513,16 @@ public override bool VisitArrayType(ArrayType array, TypeQualifiers quals)
512513 }
513514 else
514515 {
515- if ( arrayType . IsPrimitiveType ( PrimitiveType . Char ) &&
516+ if ( ( arrayType . IsPrimitiveType ( PrimitiveType . Char ) ||
517+ arrayType . IsPrimitiveType ( PrimitiveType . WideChar ) ) &&
516518 Context . Context . Options . MarshalCharAsManagedChar )
517519 {
518- supportBefore . WriteLineIndent (
519- "{0}[i] = global::System.Convert.ToSByte({1}[i]);" ,
520- Context . ReturnVarName , Context . ArgName ) ;
520+ if ( arrayType . IsPrimitiveType ( PrimitiveType . Char ) )
521+ supportBefore . WriteLineIndent (
522+ $ "{ Context . ReturnVarName } [i] = global::System.Convert.ToSByte({ Context . ArgName } [i]);") ;
523+ else
524+ supportBefore . WriteLineIndent (
525+ $ "{ Context . ReturnVarName } [i] = global::System.Convert.ToChar({ Context . ArgName } [i]);") ;
521526 }
522527 else
523528 {
@@ -591,6 +596,10 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
591596
592597 var param = Context . Parameter ;
593598 var isRefParam = param != null && ( param . IsInOut || param . IsOut ) ;
599+ var finalPointee = pointer . GetFinalPointee ( ) ;
600+
601+ PrimitiveType primitive ;
602+ bool finalPointeeIsPrimitiveType = finalPointee . IsPrimitiveType ( out primitive ) ;
594603
595604 if ( CSharpTypePrinter . IsConstCharString ( pointee ) && isRefParam )
596605 {
@@ -601,12 +610,12 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
601610 }
602611 else if ( param . IsInOut )
603612 {
604- Context . Return . Write ( MarshalStringToUnmanaged ( Context . Parameter . Name ) ) ;
613+ Context . Return . Write ( MarshalStringToUnmanaged ( Context . Parameter . Name , primitive ) ) ;
605614 Context . ArgumentPrefix . Write ( "&" ) ;
606615 }
607616 else
608617 {
609- Context . Return . Write ( MarshalStringToUnmanaged ( Context . Parameter . Name ) ) ;
618+ Context . Return . Write ( MarshalStringToUnmanaged ( Context . Parameter . Name , primitive ) ) ;
610619 Context . Cleanup . WriteLine ( "Marshal.FreeHGlobal({0});" , Context . ArgName ) ;
611620 }
612621 return true ;
@@ -639,9 +648,7 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
639648 }
640649
641650 var marshalAsString = CSharpTypePrinter . IsConstCharString ( pointer ) ;
642- var finalPointee = pointer . GetFinalPointee ( ) ;
643- PrimitiveType primitive ;
644- if ( finalPointee . IsPrimitiveType ( out primitive ) || finalPointee . IsEnumType ( ) ||
651+ if ( finalPointeeIsPrimitiveType || finalPointee . IsEnumType ( ) ||
645652 marshalAsString )
646653 {
647654 // From MSDN: "note that a ref or out parameter is classified as a moveable
@@ -667,13 +674,11 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
667674 {
668675 if ( ! marshalAsString &&
669676 Context . Context . Options . MarshalCharAsManagedChar &&
670- primitive == PrimitiveType . Char )
677+ ( primitive == PrimitiveType . Char || primitive == PrimitiveType . WideChar ) )
671678 Context . Return . Write ( $ "({ typePrinter . PrintNative ( pointer ) } ) ") ;
672679
673- if ( marshalAsString && ( Context . MarshalKind == MarshalKind . NativeField ||
674- Context . MarshalKind == MarshalKind . VTableReturnValue ||
675- Context . MarshalKind == MarshalKind . Variable ) )
676- Context . Return . Write ( MarshalStringToUnmanaged ( Context . Parameter . Name ) ) ;
680+ if ( marshalAsString )
681+ Context . Return . Write ( MarshalStringToUnmanaged ( Context . Parameter . Name , primitive ) ) ;
677682 else
678683 Context . Return . Write ( Context . Parameter . Name ) ;
679684 }
@@ -684,19 +689,25 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
684689 return pointer . QualifiedPointee . Visit ( this ) ;
685690 }
686691
687- private string MarshalStringToUnmanaged ( string varName )
692+ private string MarshalStringToUnmanaged ( string varName , PrimitiveType type )
688693 {
689- if ( Equals ( Context . Context . Options . Encoding , Encoding . ASCII ) )
694+ if ( type == PrimitiveType . WideChar )
690695 {
691- return string . Format ( "Marshal.StringToHGlobalAnsi({0})" , varName ) ;
696+ // Looks like Marshal.StringToHGlobalUni is already able
697+ // to handle both Unicode and MBCS charsets
698+ return $ "Marshal.StringToHGlobalUni({ varName } )";
692699 }
700+
701+ if ( Equals ( Context . Context . Options . Encoding , Encoding . ASCII ) )
702+ return $ "Marshal.StringToHGlobalAnsi({ varName } )";
703+
693704 if ( Equals ( Context . Context . Options . Encoding , Encoding . Unicode ) ||
694705 Equals ( Context . Context . Options . Encoding , Encoding . BigEndianUnicode ) )
695706 {
696- return string . Format ( "Marshal.StringToHGlobalUni({0 })" , varName ) ;
707+ return $ "Marshal.StringToHGlobalUni({ varName } )";
697708 }
698- throw new NotSupportedException ( string . Format ( "{0} is not supported yet." ,
699- Context . Context . Options . Encoding . EncodingName ) ) ;
709+ throw new NotSupportedException (
710+ $ " { Context . Context . Options . Encoding . EncodingName } is not supported yet." ) ;
700711 }
701712
702713 public override bool VisitPrimitiveType ( PrimitiveType primitive , TypeQualifiers quals )
@@ -714,6 +725,15 @@ public override bool VisitPrimitiveType(PrimitiveType primitive, TypeQualifiers
714725 return true ;
715726 }
716727 goto default ;
728+ case PrimitiveType . WideChar :
729+ // returned structs must be blittable and char isn't
730+ if ( Context . Context . Options . MarshalCharAsManagedChar )
731+ {
732+ Context . Return . Write ( "global::System.Convert.ToChar({0})" ,
733+ Context . Parameter . Name ) ;
734+ return true ;
735+ }
736+ goto default ;
717737 case PrimitiveType . Char16 :
718738 return false ;
719739 case PrimitiveType . Bool :
0 commit comments