From 1881a37bd574435fd97329a193925a6cad3c0801 Mon Sep 17 00:00:00 2001 From: Lincoln Atkinson Date: Fri, 29 Jan 2016 10:55:39 -0800 Subject: [PATCH 1/3] Use correct flags to create ctor calls for DispatchWrapper and UnknownWrapper fixes https://github.com/Microsoft/visualfsharp/issues/907 --- src/fsharp/TypeChecker.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index 526f5a0ea06..d6019227ae0 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -9174,7 +9174,7 @@ and TcMethodApplication | Some assemblyRef -> let tref = mkILNonGenericBoxedTy(mkILTyRef(assemblyRef, "System.Runtime.InteropServices.DispatchWrapper")) let mref = mkILCtorMethSpecForTy(tref,[cenv.g.ilg.typ_Object]).MethodRef - let expr = Expr.Op(TOp.ILCall(false,false,false,false,CtorValUsedAsSuperInit,false,false,mref,[],[],[cenv.g.obj_ty]),[],[mkDefault(mMethExpr,currCalledArgTy)],mMethExpr) + let expr = Expr.Op(TOp.ILCall(false,false,false,true,NormalValUse,false,false,mref,[],[],[cenv.g.obj_ty]),[],[mkDefault(mMethExpr,currCalledArgTy)],mMethExpr) emptyPreBinder,expr | WrapperForIUnknown -> match cenv.g.ilg.traits.SystemRuntimeInteropServicesScopeRef.Value with @@ -9182,7 +9182,7 @@ and TcMethodApplication | Some assemblyRef -> let tref = mkILNonGenericBoxedTy(mkILTyRef(assemblyRef, "System.Runtime.InteropServices.UnknownWrapper")) let mref = mkILCtorMethSpecForTy(tref,[cenv.g.ilg.typ_Object]).MethodRef - let expr = Expr.Op(TOp.ILCall(false,false,false,false,CtorValUsedAsSuperInit,false,false,mref,[],[],[cenv.g.obj_ty]),[],[mkDefault(mMethExpr,currCalledArgTy)],mMethExpr) + let expr = Expr.Op(TOp.ILCall(false,false,false,true,NormalValUse,false,false,mref,[],[],[cenv.g.obj_ty]),[],[mkDefault(mMethExpr,currCalledArgTy)],mMethExpr) emptyPreBinder,expr | PassByRef (ty, dfltVal2) -> let v,_ = mkCompGenLocal mMethExpr "defaultByrefArg" ty From 6e5fc1459dd2af51506bffac7377483b4805a3d7 Mon Sep 17 00:00:00 2001 From: Lincoln Atkinson Date: Fri, 29 Jan 2016 13:31:46 -0800 Subject: [PATCH 2/3] Update COM optional arg handling to match C# and VB --- src/fsharp/TypeChecker.fs | 10 ++++++---- src/fsharp/infos.fs | 9 ++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index d6019227ae0..96022bb7da0 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -9128,11 +9128,13 @@ and TcMethodApplication // Handle CallerSide optional arguments. // // CallerSide optional arguments are largely for COM interop, e.g. to PIA assemblies for Word etc. - // As a result we follow the VB spec here. To quote from an email exchange between the C# and VB teams. + // As a result we follow the VB and C# behavior here. // - // "1. If the parameter is statically typed as System.Object and does not have a value, then there are two cases: - // a. The parameter may have the IDispatchConstantAttribute or IUnknownConstantAttribute attribute. If this is the case, the VB compiler then create an instance of the System.Runtime.InteropServices.DispatchWrapper /System.Runtime.InteropServices.UnknownWrapper type at the call site to wrap the value Nothing/null. - // b. If the parameter does not have those two attributes, we will emit Missing.Value. + // "1. If the parameter is statically typed as System.Object and does not have a value, then there are four cases: + // a. The parameter is marked with MarshalAs(IUnknown), MarshalAs(Interface), or MarshalAs(IDispatch). In this case we pass null. + // b. Else if the parameter is marked with IUnknownConstantAttribute. In this case we pass new System.Runtime.InteropServices.UnknownWrapper(null) + // c. Else if the parameter is marked with IDispatchConstantAttribute. In this case we pass new System.Runtime.InteropServices.DispatchWrapper(null) + // d. Else, we will pass Missing.Value. // 2. Otherwise, if there is a value attribute, then emit the default value. // 3. Otherwise, we emit default(T). // 4. Finally, we apply conversions from the value to the parameter type. This is where the nullable conversions take place for VB. diff --git a/src/fsharp/infos.fs b/src/fsharp/infos.fs index 58baa613bd8..3d685ecab50 100755 --- a/src/fsharp/infos.fs +++ b/src/fsharp/infos.fs @@ -499,9 +499,12 @@ type OptionalArgInfo = let ty = destByrefTy g ty PassByRef (ty, analyze ty) elif isObjTy g ty then - if TryFindILAttributeOpt g.attrib_IDispatchConstantAttribute ilParam.CustomAttrs then WrapperForIDispatch - elif TryFindILAttributeOpt g.attrib_IUnknownConstantAttribute ilParam.CustomAttrs then WrapperForIUnknown - else MissingValue + match ilParam.Marshal with + | Some(ILNativeType.IUnknown | ILNativeType.IDispatch | ILNativeType.Interface) -> Constant(ILFieldInit.Null) + | _ -> + if TryFindILAttributeOpt g.attrib_IUnknownConstantAttribute ilParam.CustomAttrs then WrapperForIUnknown + elif TryFindILAttributeOpt g.attrib_IDispatchConstantAttribute ilParam.CustomAttrs then WrapperForIDispatch + else MissingValue else DefaultValue CallerSide (analyze (ImportTypeFromMetadata amap m ilScope ilTypeInst [] ilParam.Type)) From 769b0cf04302190ffe978cc79433e7f16a227548 Mon Sep 17 00:00:00 2001 From: Lincoln Atkinson Date: Fri, 29 Jan 2016 16:11:21 -0800 Subject: [PATCH 3/3] Add test for optional COM arguments --- tests/RunTests.cmd | 3 ++ .../OptionalArguments/OptArgsFromCOM.fs | 34 +++++++++++++++++++ .../OptionalArguments/env.lst | 1 + 3 files changed, 38 insertions(+) create mode 100644 tests/fsharpqa/Source/Conformance/DeclarationElements/MemberDefinitions/OptionalArguments/OptArgsFromCOM.fs diff --git a/tests/RunTests.cmd b/tests/RunTests.cmd index a7ebbea2eeb..649a394af65 100644 --- a/tests/RunTests.cmd +++ b/tests/RunTests.cmd @@ -170,6 +170,9 @@ set OSARCH=%PROCESSOR_ARCHITECTURE% set X86_PROGRAMFILES=%ProgramFiles% if "%OSARCH%"=="AMD64" set X86_PROGRAMFILES=%ProgramFiles(x86)% +set SYSWOW64=. +if "%OSARCH%"=="AMD64" set SYSWOW64=SysWoW64 + set REGEXE32BIT=reg.exe if not "%OSARCH%"=="x86" set REGEXE32BIT=%WINDIR%\syswow64\reg.exe diff --git a/tests/fsharpqa/Source/Conformance/DeclarationElements/MemberDefinitions/OptionalArguments/OptArgsFromCOM.fs b/tests/fsharpqa/Source/Conformance/DeclarationElements/MemberDefinitions/OptionalArguments/OptArgsFromCOM.fs new file mode 100644 index 00000000000..f5fa9ccb481 --- /dev/null +++ b/tests/fsharpqa/Source/Conformance/DeclarationElements/MemberDefinitions/OptionalArguments/OptArgsFromCOM.fs @@ -0,0 +1,34 @@ +open System +open WbemScripting + +let doStuff() = + let locator = + let comTy = Type.GetTypeFromProgID("WbemScripting.SWbemLocator") + Activator.CreateInstance(comTy) :?> SWbemLocator + + // SWBemLocator.ConnectServer https://msdn.microsoft.com/en-us/library/windows/desktop/aa393720(v=vs.85).aspx + // SWbemServices ConnectServer( + // [MarshalAs(UnmanagedType.BStr)] [In] string strServer = ".", + // [MarshalAs(UnmanagedType.BStr)] [In] string strNamespace = "", + // [MarshalAs(UnmanagedType.BStr)] [In] string strUser = "", + // [MarshalAs(UnmanagedType.BStr)] [In] string strPassword = "", + // [MarshalAs(UnmanagedType.BStr)] [In] string strLocale = "", + // [MarshalAs(UnmanagedType.BStr)] [In] string strAuthority = "", + // [In] int iSecurityFlags = 0, + // [IDispatchConstant] [MarshalAs(UnmanagedType.IDispatch)] [In] object objWbemNamedValueSet = null); + let services = locator.ConnectServer() + + // SWbemServices.ExecQuery https://msdn.microsoft.com/en-us/library/windows/desktop/aa393866(v=vs.85).aspx + // SWbemObjectSet ExecQuery( + // [MarshalAs(UnmanagedType.BStr)] [In] string strQuery, + // [MarshalAs(UnmanagedType.BStr)] [In] string strQueryLanguage = "WQL", + // [In] int iFlags = 16, + // [IDispatchConstant] [MarshalAs(UnmanagedType.IDispatch)] [In] object objWbemNamedValueSet = null); + let resultSet = services.ExecQuery("select * from Win32_Processor") + + resultSet + |> Seq.cast + |> Seq.map (fun o -> o.GetObjectText_(0)) + |> Seq.iter (printfn "%s") + +doStuff() diff --git a/tests/fsharpqa/Source/Conformance/DeclarationElements/MemberDefinitions/OptionalArguments/env.lst b/tests/fsharpqa/Source/Conformance/DeclarationElements/MemberDefinitions/OptionalArguments/env.lst index 549e383433c..d9dc3e051ae 100644 --- a/tests/fsharpqa/Source/Conformance/DeclarationElements/MemberDefinitions/OptionalArguments/env.lst +++ b/tests/fsharpqa/Source/Conformance/DeclarationElements/MemberDefinitions/OptionalArguments/env.lst @@ -5,6 +5,7 @@ SOURCE=E_SanityCheck02.fs SOURCE=SanityCheck03.fs + SOURCE=OptArgsFromCOM.fs SCFLAGS="-r:WbemScripting.dll" PRECMD="tlbimp %SystemRoot%\\%SYSWOW64%\\wbem\\wbemdisp.tlb" # OptArgsFromCOM.fs SOURCE=NullOptArgsFromVB.fs SCFLAGS="-r:TestLibVB.dll" PRECMD="\$VBC_PIPE /t:library TestLibVB.vb" # NullOptArgsFromVB.fs SOURCE=NullOptArgsFromCS.fs SCFLAGS="-r:TestLib.dll" PRECMD="\$CSC_PIPE /t:library TestLib.cs" # NullOptArgsFromCS.fs SOURCE=SanityOptArgsFromCS.fs SCFLAGS="-r:TestLib.dll" PRECMD="\$CSC_PIPE /t:library TestLib.cs" # SanityOptArgsFromCS.fs