-4

A call to PInvoke function 'ReleaseCapture' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

The function has been defined this way and has been working for over 6 years just fine. We didn't get word of this error until a user reported it. It happens when a user starts to drag a user control on the screen, if it's not dragged it is fine.

  <DllImport("user32")> _
  Public Shared Function ReleaseCapture(ByVal hwnd As IntPtr) As Integer
  End Function

This function is called on the user control MouseDown event. For example:

  Private Sub uxCalcTitleBar_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles uxCalcTitleBar.MouseDown, lblCalcTitle.MouseDown
    If e.Button = Windows.Forms.MouseButtons.Left And e.Clicks = 1 Then
        If Not Me._CalcIsMoving And Not Me._CalcIsPackedForMove Then
            Me.Calc_PackForMove()
        End If
        ReleaseCapture(Me.uxCalculator.Handle) **ERROR HERE**
        SendMessage(Me.uxCalculator.Handle, WM_SYSCOMMAND, MOUSE_MOVE, 0)
        Me._CalcNewLocation = Me.uxCalculator.Location

        Me.uxCalcTitleBar_MouseUp(sender, e)
    End If
End Sub

One thing we noticed, this started happening after moving to the 4.5 framework from 2.0. Do not know if this makes a difference, but I think it should not. After some research I found that the resolution should be reviewing the managed platform invoke signature and calling convention to confirm it matches the signature and calling convention of the native target.

What I have Tried

I examined the signature and it seem's to be just fine, nothing I can actually see. I also specified the convention as such to clear the stack it doesn't help...

  <DllImport("user32", CallingConvention:=CallingConvention.Cdecl)> _
  Public Shared Function ReleaseCapture(ByVal hwnd As IntPtr) As Integer
  End Function
Trevor
  • 7,777
  • 6
  • 31
  • 50
  • From [MSDN](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646261(v=vs.85).aspx): `BOOL WINAPI ReleaseCapture(void);` it doesnt take a param. – Ňɏssa Pøngjǣrdenlarp Jan 28 '16 at 20:40
  • Yes you can as you can use it for drag functionality. You can on the mousedown event and then send a message, it delegates events... http://www.pinvoke.net/default.aspx/user32.releasecapture – Trevor Jan 28 '16 at 20:48
  • Can someone explain the downvote? So I can edit my question... – Trevor Jan 28 '16 at 22:17
  • Not my DV....but since I got pinged: The error message says to `check calling convention and parameters`. The official source for the function says pass no params. Passing one where one is not expected is the definition of a stack imbalance. The snippet you used is some undocumented "feature" from some guy on the internet from 10 years ago. Such things have a way of eventually not working as the OS and other things change. Such things happen. – Ňɏssa Pøngjǣrdenlarp Jan 28 '16 at 22:28
  • I agree, but why does it work in other classes and not this one. Also the class it works in is another project under the solution. So trying to find differences... – Trevor Jan 28 '16 at 22:36
  • 1
    http://stackoverflow.com/questions/3506796/pinvokestackimbalance-how-can-i-fix-this-or-turn-it-off – David Heffernan Jan 28 '16 at 22:38
  • 1
    If you browse some of the entries under **Related** you'll see that they all have the same source problem: whacky params (well, the 3 I looked at anyway) – Ňɏssa Pøngjǣrdenlarp Jan 28 '16 at 22:39
  • @DavidHeffernan please see my comment's on your answer... thanks! – Trevor Jan 29 '16 at 00:11

1 Answers1

3

The correct signature is this:

<DllImport("user32.dll")> _
Public Shared Function ReleaseCapture() As Boolean
End Function

The function does not take any parameters as can be seen from the documentation: https://msdn.microsoft.com/en-us/library/windows/desktop/ms646261.aspx

Regarding your use of CallingConvention.Cdecl, that is a mistake. The calling convention is CallingConvention.StdCall, which is the default and so can be omitted. You don't get to decide what the calling convention is any more than you get to decide what the parameters are. You cannot decide to impose CallingConvention.Cdecl as a means to "clear the stack". That is just meaningless. The implementer of the function decides its calling convention, parameters and so on. Your job is to meet the interface contract specified by the implementer of the function.


One thing we noticed, this started happening after moving to the 4.5 framework from 2.0.

Indeed. Version 2.0 of .net did not contain the pInvokeStackImbalance MDA that is producing this message. Your program has been wrong for all that time and you've just been lucky. Now that you are using better tooling, that tooling has been able to inform you of your error.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • I've already seen these, this isnt the problem. I said it's been working for 6 years... – Trevor Jan 28 '16 at 22:16
  • No, this is the problem. Your code has been wrong for 6 years. Can you read the documentation I linked to. Or do you think that you know better than MSDN? – David Heffernan Jan 28 '16 at 22:18
  • 1
    Open your eyes please. Please read the documentation I linked to. A stack imbalance like this where you pass an extra parameter does not necessarily lead to an error because the p/invoke mechanism happens to paper over your mistake. But your code was wrong, the code in my answer is correct. I cannot imagine why you would vote down the answer given the facts that can so plainly be seen in the MSDN docs. – David Heffernan Jan 28 '16 at 22:21
  • I know what the signature is. That's the first thing I done. Using Ants Profiler I am seeing some memory issues with not using my controls handle to release the delegated events. – Trevor Jan 28 '16 at 22:26
  • Someone has changed something and not quite sure exactly.... Still digging into it. – Trevor Jan 28 '16 at 22:27
  • Also if I don't pass in the handle the control doesn't drag across. When we do it's fine. Something changed and finding the issue has been a task. – Trevor Jan 28 '16 at 22:28
  • And yes you are right about the signature, but that's not the reason I am afraid I don't believe. We have other classes that use this and we can't replicate the issue where we are using this same call. – Trevor Jan 28 '16 at 22:30
  • This question, in one form or another, has been asked here so many times. Older .net versions did not have this MDA. Newer ones do. You might have disabled the MDA in some of your projects. The code was always wrong. You'll eventually see that I am right. – David Heffernan Jan 28 '16 at 22:31
  • Wow, finally got it. It seems that the SystemInterop namespace had something to do with it. I am not sure exactly how, but when I went back to 2.0 framework it works just fine. I asked another engineer here (he's been here longer) and told me that was the only way at the time to move a user control (well provide drag functionality). Thank goodness in release mode it doesn't throw the error, the control just doesn't drag... And I stand corrected, it was code and after putting in `CallingConvention:=CallingConvention.Cdecl` , clean the solution and rebuild it was fine, the error went away. – Trevor Jan 29 '16 at 00:08
  • This points out a bigger issue now, it was failing gracefully in production but it's an issue we need to get fixed. Again, thank you for your time and solution. It seems we will need to be putting in a ticket for a re-write on this functionality :) – Trevor Jan 29 '16 at 00:10
  • Version 2.0 does not have the MDA. That's why you don't see the message there. Cdecl is wrong. It is StdCall. – David Heffernan Jan 29 '16 at 07:08