Working with structures - the pure .net way

This forum is meant for questions and discussions about the X# language and tools
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am
Location: Germany

Working with structures - the pure .net way

Post by Karl-Heinz »

Guys,

1.While playing with structures i´ve noticed that the compiler throws an misleading error when you pass
a different structure than the callee expects: "error XS1620: Argument 1 must be passed with the 'ref' keyword"
Such an misleading XS1620 error happens when you do something like this:

IF GetVersionEx ( struInfoExW ) // wrong structure - OSVERSIONINFOEXW

instead of:

IF GetVersionEx ( struInfoEx ) // correct structure - OSVERSIONINFOEX


2. I´m able to compile a "_DLL" import not only as "ANSI" or "UNICODE", but with "AUTO" too, though "AUTO" seems to have no effect at runtime. For what is "AUTO" good for in this context ?

There are some more notes in the attached app, so i thing it should be easy to follow what i´m doing and how i´m using the import possibilities

"_DLL" / "[DllImport" and the charsets Ansi,UniCode and Auto.


BTW I. the StructureTest.viaef has no references to any Vulcan dll or X# dll. Also, the warning 0170 is disabeld via "/nowarn:170" . The structure member "szCSDVersion" is only filled when you´re running Win7 SP1 or Vista SPx. Win 8.1 and Win 10 have no servicepacks.

BTW II. very nice to be able to do something like this now:

? "OutPut: " + lStart + " " + dwStart

// Of course, lStart is a LOGIC and dwStart a DWORD


Any comments/corrections are welcome.


regards
Karl-Heinz
Attachments
StructureTest.zip
(2.46 KiB) Downloaded 59 times
User avatar
Chris
Posts: 4906
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

Working with structures - the pure .net way

Post by Chris »

Hi Karl-Heinz,

1. About the misleading error, the problem is that the function requires a param by REF:

_DLL FUNCTION GetVersionEx ( struOS REF OSVERSIONINFOEX ) AS LOGIC

But the code calls it (as in VO), without indicating that the param is actually passed by reference:

GetVersionEx ( struInfoEx )

In Roslyn/c# this would throw a compiler error, but it is allowed in X# for compatibility with VO/Vulcan, although the "more correct" or advised syntax to use would be to explicitly specify that you pass the param by reference:

GetVersionEx ( REF struInfoEx )

Now if you had used the wrong structure (struInfoExW) in your case, you would get a proper error message:

error XS1503: Argument 1: cannot convert from 'ref OSVERSIONINFOEXW' to 'ref OSVERSIONINFOEX'

The reason why you do not get a better error message in the original sample, is due to the X# compiler trickery that takes place and tries to decide if you actually intended to pass a param by reference but did not explicitly mentioned that in the code, in which case the compiler silently and adds the "REF" itself. Apparently something goes wrong in that routine in this particular case and confuses the compiler, making it report an error about not using REF yourself, while actually the real problem is that you used the wrong structure. Not sure how easy it will be to fix this, but I will enter it a a bug report.


2. For things like that, it is extremely helpful to check the generated code/function declarations with ILSpy, to see what the compiler did differently in each case. If you do that, you will see that when using ANSI, the compiler generates this attribute for the function/method:

[DllImport("User32", CharSet := CharSet.Ansi, ExactSpelling =: true, SetLastError := true)]

When you use UNICODE, he only difference is the CharSet part which becomes CharSet.Unicode and for AUTO it becomes CharSet.Auto. Having a look at the documentation for CharSet:

https://docs.microsoft.com/en-us/dotnet ... es.CharSet

it explains what Auto stands for in different OSes.

If you want to have full control over things, it's maybe a good idea to not rely on _DLL declarations, but instead always apply the DllImport attribute yourself to class methods, so you always know what gets emitted.


3. Actually I do not like this and would had liked to be disallowed in X# :). It is supported by c#/Roslyn so also supported by X# which uses Roslyn as its backend, but in my opinion it is error prone, as it could hide coding errors where the user typed the wrong variable. In my opinion, it would be better to use this also easy syntax instead:

? "OutPut: " + lStart:ToString() + " " + dwStart:ToString()

which I think is more straightforward about what's happening. But of course it's normal that we can have different opinions! :)

Chris
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am
Location: Germany

Working with structures - the pure .net way

Post by Karl-Heinz »

Hi Chris,

i see the point. Adding "REF" shows the real problem. In a forum sample that uses ref vars i saw that there
the "REF" Keyword is not used, so i did it the same way - without thinking about why ;-). Wouldn´t it be better - and more readable - that the compiler would force us to insert "REF" instead of adding it silently to the IL Code if it´s missing. ?

The code below runs, but if you don´t know the callee signature a quick look at the caller only suggests that in the first case only the first param is a ref var, and in the second case only the second param.

Foo ( REF dw1 , dw2 )

Foo ( dw1 , REF dw2 )


FUNCTION Foo( dwOne REF DWORD , dwTwo REF DWORD ) AS LOGIC
...

>
> ? "OutPut: " + lStart + " " + dwStart
>

I discovered it by accident, and i´ll use this "feature" only where i quickly need an output without to worry about the Datatypes.


regards
Karl-Heinz
User avatar
wriedmann
Posts: 3755
Joined: Mon Nov 02, 2015 5:07 pm
Location: Italy

Working with structures - the pure .net way

Post by wriedmann »

Hi Karl-Heinz,
Wouldn´t it be better - and more readable - that the compiler would force us to insert "REF" instead of adding it silently to the IL Code if it´s missing. ?
Maybe because of compatibility to VO and Vulcan? I suspect there is much code dealing with structures in the GUI classes...

Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am
Location: Germany

Working with structures - the pure .net way

Post by Karl-Heinz »

Hi Wolfgang,

>
> Maybe because of compatibility to VO and Vulcan?
>

that doesn´t satisfy me ;-)

At least in the described context, the compiler knows exactly if "REF" needs to be added or not.

regards
Karl-Heinz
User avatar
wriedmann
Posts: 3755
Joined: Mon Nov 02, 2015 5:07 pm
Location: Italy

Working with structures - the pure .net way

Post by wriedmann »

Hi Karl-Heinz,

AFAIK there is a lot of VO code around that needs to be ported, and I think the development team will make the migration work as easy as possible.

Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
User avatar
Chris
Posts: 4906
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

Working with structures - the pure .net way

Post by Chris »

Hi guys,

Yes, this is also a preference of mine, I was actually strongly suggesting it in the vulcan years, too, because using REF explicitly makes the code a lot more readable/understandable of what it's doing.

Possibly we will make that code requiring REF in X# at some point, but as Wolfgang said we need to support also the "old" way, because there's so much existing code without it, so the new behavior must be optional. Maybe with a /strict compiler option or something like that.

Chris
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
MathiasHakansson
Posts: 50
Joined: Fri Feb 16, 2018 7:52 am

Working with structures - the pure .net way

Post by MathiasHakansson »

Hi,

why does the code have to be compatible? Coulden't this change be handled by the transporter?

/Mathias
User avatar
Chris
Posts: 4906
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

Working with structures - the pure .net way

Post by Chris »

Hi Mathias,

That could be a possibility, but it is not easy. First of all, it would have to be an optional feature, because some people do not like this change :), also we try to keep the changes to as few as possible, because some people need to share code between VO/X# while porting step by step to X#.

The big issue is that in order to implement that, the XPorter needs to become much smarter, it needs to analyze LOCALs and params, to find their types, then lookup the method signatures of that type and figure out if each param should be passed by REF or not. It's doable, but needs a lot of work, so I am afraid this one of those "nice to have" things which have to wait for after we're finished with more pressuring things like the runtime.

Chris
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am
Location: Germany

Working with structures - the pure .net way

Post by Karl-Heinz »

Hi Chris,

ok, i´ll keep my legs still and wait ;-)

But i have another thing:

it´s not a showstopper, but i´m able to write "code" like below. Only when i add to such a textline a space char followed by some more text an "XS9002: Parser: unexpected input" error is thrown. It seems, that this only happens if a dialect other than <core> is selected. Only <core> throws immediately an error.

-----------

CLASS Foo1

classghgghg
forhjhjh
jkjkj
interfacehjhh


END CLASS


INTERFACE iFoo

ISfghfg
hjkhkh
jkjk

END INTERFACE

------------

BTW. Is it possible to add the *.viaef extension to the list of allowed upload files ?

regards
Karl-Heinz
Attachments
Foo.zip
(1.03 KiB) Downloaded 69 times
Post Reply