none
Issue with Parameter of type short in P/Invoke with .NET Framework 4.5 RRS feed

  • Question

  • On a machine with just .NET Framework 4.0, I have an 64-bit C# Assembly compiled with mscs-10.0 that has following P/Invoke

    [DllImport(VisaDriverFileName64, EntryPoint = "viSetAttribute", CallingConvention = CallingConvention.StdCall)|DllImport(VisaDriverFileName64, EntryPoint = "viSetAttribute", CallingConvention = CallingConvention.StdCall)]
    private static extern ViStatus _SetAttributeInt16_64(ViObject vi, ViAttr attrName, short attrState); 

    This P/Invoke calls into the following C++ entrypoint

    ViStatus _VI_FUNC  viSetAttribute  (ViObject vi, ViAttr attrName, unsigned __int64 attrState);

    Ideally the DllImport Signature should have ulong instead of short. But this work perfectly on system with only .NET Framework 4.0, if correct value (1 or 4) is passed for the parameter attrState, for any other values underlying C++ entrypoint throws exception saying not supported value.

    Now after installing .NET Framework 4.5 on the same system, above C++ entrypoints throws exception saying not supported value for parameter attrState, even if we pass the correct values (1 or 4) from .NET Layer. We know the fix for this, however what I would like to know is why is it failing only after installing .NET Framework 4.5, and what got changed in .NET Framework 4.5 due to which this call fails?

    I have a little clue on what is happening, but what I dont is why is this happening.

    For attrState = 1

    • With just .NET Framework 4.0, C++ entrypoint reads the parameter attrState as 0x0000000000000001
    • With .NET Framework 4.0 and if we install .NET Framework 4.5, C++ entrypoint reads the parameter attrState as 0x00002de11a3f0001. I am getting different garbage value for highlighted middle bytes everytime.

    I want to know, why is this happening only when I have .NET Framework 4.5 installed on top of .NET Framework 4.0. 

    Thanks,
    Shura


    shura



    • Edited by Bhavesh Shura Thursday, December 13, 2012 3:46 PM minor typo correction
    Thursday, December 13, 2012 3:42 PM

All replies

  • One clue that might help you is that when you install 4.5, you get every hotfix, support patch, etc. for 4.0. 4.5 does an in-place upgrade of your 4.0 dlls, so it really can change a fair amount of things. I got bitten by some of the "fixes" in the 4.5 drop in our 4.0 app that I had to write workarounds for. Albeit, I was calling internal functions with reflection, so the fact that they changed their internal method signatures wasn't their fault.

    Anyway, instead of short, try System.Int64

    Since you are using a 64 bit value.

    Thursday, December 13, 2012 4:50 PM
  • As I said earliar, I want to know following:

    1. Why is this happening only when I have .NET Framework 4.5 installed on top of .NET Framework 4.0?
    2. What got changed in .NET Framework 4.5 due to which existing application in .NET 4.0 starts failing?
    3. Is that change documented anywhere?

    Hope there are answers to this questions

    Thanks,


    Shura

    Friday, December 14, 2012 1:41 PM
  • Hey Brian,

    Above code sample (C++ as well as C#) that I included is own by us. Also I already has a fix for this applied and mentioned in my post - to use ulong instead of short in DllImport. But that does not mean that we got the answers my questions. As per MSDN .NET Framework 4.5 is backward compatible Anyways looking for reason of this failure.

    Thanks,


    Shura

    Friday, December 14, 2012 4:15 PM
    1. Because your code is wrong.
    2. Probably something in the way the JIT compiler generates code. Or in the PInvoke marshaler.
    3. No. And it's quite possible that this is the consequence of an unrelated change.

    "But that does not mean that we got the answers my questions."

    Your questions don't make much sense to begin with, your code is wrong.

    "As per MSDN .NET Framework 4.5 is backward compatible"

    With code that is reasonable correct.

    Sunday, December 16, 2012 12:47 PM
    Moderator
  • Hi Shura,

    I got it, I am trying to involve some other one into this case.

    Wait it patiently, please.

    Thank you.

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Monday, December 17, 2012 5:49 AM
    Moderator
  • I can only assume it was a bug even letting you call the API with a short.

    Basically, the DLL call was going with a couple of bytes instead of the 8 bytes. Why the old 4.0 worked and 4.5 framework didn't? Good question. You can always look at the IL from the .NET stack and see what the difference is. Personally, I would find it a waste of time though.
    The code was incorrect before, so I would chalk it up to "lucky" it worked before.

    Monday, December 17, 2012 4:12 PM
  • The original code triggers a stack unbalence exception if run under debug mode.

    I can't find any specific bugs which address p/invoke + __int64 + short so I can't really say what the change was if any. It could be as simple as you get random memory that was typically 0 in 4.0 but is not 0 in 4.5.

    The bottom line here is that your signature is incorrect. Expecting incorrect code to run identically across a runtime upgrade is unreasonable, we certainly don't write test cases to ensure known bugs run the same across upgrades.

    If you're terribly curious, you might try using the IL Stub Diagnostic tool to see if the IL Stub code has changed (though it doesn't look like that tool has been updated in a while - http://blogs.msdn.com/b/dotnet/archive/2009/08/26/il-stub-diagnostic-tool.aspx)

    However, it's not a supportability issue because we can't guarantee incorrect code is going to behave incorrectly in the same manner across runtimes. That would mean we can't fix bugs.

    Tuesday, December 18, 2012 12:49 AM
  • Hey Steve,

    When I posted this question I already figured it out that there is an incorrect code and I also had a fix for incorrect code, however as it was working without any issue with just .NET Framework 4.0, I was curious to know what is different in .NET 4.5 that made existing application to break i.e. wanted to know if it is true that something got changed in .NET Framework 4.5 that opened the bug in our code.

    I totally agree that the code that we had in our library had some issue in it, and and if that incorrect code was working then that means that there was a bug somewhere in .NET Framework 4.0 or CLR or JIT Compiler, or anywhere else, that was allowing incorrect code in our library to work. So I am looking for confirmation on the fix/change being applied underneath from Microsoft.

    Lets see if anyone has something to say about this corrected behavior in .NET Framework 4.5 or can point me to some document from Microsoft.


    Shura

    Tuesday, December 18, 2012 1:16 AM
  • I disagree that it's a CLR bug. The JITter generates the code you tell it to -- it doesn't check the native signature to verify you got the p/invoke signature right. I wrote a test dll and was getting MDA unbalanced stack errors in debug mode where we do turn on code to do things like check that stacks are balanced before and after p/invoke calls.

    That you get different behaviour in different builds isn't too surprising with this type of bug -- a using uninitialized memory bug because you told the runtime to allocate and initialize 16 bits and then had your callee use 64. As someone noted up-thread, you just got lucky that the uninitialized (or initialized by something else) bits were zero before.

    Tuesday, December 18, 2012 3:57 AM
  • "The original code triggers a stack unbalence exception if run under debug mode"

    On x64? Impossible, that MDA is only for x86.

    Anyway, on x64 the native stack locations are 64 bit, it doesn't matter if a parameter is short or int or long, the size on the stack is the same. Besides, the function only has 3 parameters, this means that they'll all be passed in registers. It's possible that on .NET 4 the r8 register happens to contain 0 before being loaded with the attrState value.

    • Proposed as answer by Alex Skalozub Wednesday, December 19, 2012 3:55 AM
    Tuesday, December 18, 2012 8:41 AM
    Moderator