Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions src/fsharp/TypeChecker.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -9174,15 +9176,15 @@ 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
| None -> error(Error(FSComp.SR.fscSystemRuntimeInteropServicesIsRequired(), mMethExpr))
| 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
Expand Down
9 changes: 6 additions & 3 deletions src/fsharp/infos.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
3 changes: 3 additions & 0 deletions tests/RunTests.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -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<SWbemObject>
|> Seq.map (fun o -> o.GetObjectText_(0))
|> Seq.iter (printfn "%s")

doStuff()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why a function? Ti can ve replaced with the function body

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #907 (comment) - extra problems occur when you put the code in a function. Wanted to make sure that was covered.

Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down