I've an issue regarding p/invoke from managed to unmanaged code. See my original post at the MSDN forum (as brief summary is seen later in this post). Before I go on, I just want to explain a couple of things: I have a wrapper assembly in net 3.5 that does the actual interop to the unmanaged code. Then I have my console "host app" which uses the wrapper assembly.
The solution I came up (I refer to my MSDN post) works when the host app is using .net 4, but it doesn't work when changing the host app to use .net 3.5. When changing, I get a AccessViolationException.
host app: 4.0, wrapper assembly: 3.5
-> works
host app: 3.5, wrapper assembly: 3.5 -> throws
AccessViolationException
Do anyone have a clue to why I get an AccessViolationException? Most importantly, how do I get it working with .net 3.5?
Brief summary on the MSDN post I refered to. I have this messy p/Invoke I need to solve. The C declaration looks like this:
long TBAPI TbeAndring (short,
short,
PTB_PU,
PTB_ANDRING_INFO,
PTB_PARAMS,
PTB_PREMIE_NIVA_INFO,
PTB_PREMIE,
PTB_FORMAN_INFO,
PTB_FORMAN,
PTB_FUNK,
PTB_PARAMS,
PTB_PREMIE_NIVA_INFO,
PTB_PREMIE,
PTB_FORMAN_INFO,
PTB_FORMAN,
PTB_FUNK);
Where PTB means that each argument is a struct pointer to an array of arbitrary length. The structs mostly contains strings, doubles, char and short. Anyway, I ended up with this DllImport statement:
<DllImport(NativeLibraryName, CallingConvention:=CallingConvention.StdCall, CharSet:=CharSet.Ansi, SetLastError:=True)>
Public Shared Function TbeAndring(ByVal sAntMoment As Short, _
ByVal sAntPU As Short, _
<[In]()> ByVal atbpu As PTB_PU(), _
<[In]()> ByVal atbandringinfo() As PTB_ANDRING_INFO, _
<[In]()> ByVal atbparamsEfter() As PTB_PARAMS, _
<[In]()> ByVal aNivaInfoEfter() As PTB_PREMIE_NIVA_INFO, _
<[In](), Out()> ByVal atbpremieEfter() As PTB_PREMIE, _
<[In]()> ByVal atbFormanInfoEfter() As PTB_FORMAN_INFO, _
<[In](), Out()> ByVal atbFormanEfter() As PTB_FORMAN, _
<[In](), Out()> ByVal atbfunkEfter() As PTB_FUNK, _
<[In]()> ByVal atbparamsFore() As PTB_PARAMS, _
<[In]()> ByVal aNivaInfoFore() As PTB_PREMIE_NIVA_INFO, _
<[In](), Out()> ByVal atbpremieFore() As PTB_PREMIE, _
<[In]()> ByVal atbFormanInfoFore() As PTB_FORMAN_INFO, _
<[In](), Out()> ByVal atbFormanFore() As PTB_FORMAN, _
<[In](), Out()> ByVal atbfunkFore() As PTB_FUNK) As Int32
End Function
As you see some of the arguments are changed by the unmanaged code as well.
I don't know if it's the only reason for AccessViolationException, but I've seen that exception come from unmanaged code that was running with a corrupt C runtime library heap. In particular, some memory which was meant to contain a valid pointer came to contain garbage: when dereferenced, it pointed to nonexistant memory.
If you have an issue like this, then the change in .NET version may simply have moved the problem around, such that the problem has been seen under .NET 3.5 but has not yet been seen under .NET 4.0.
I recommend running the code under the debugger, and including Native code debugging. You may find the original exception.
Related
This question already has answers here:
PInvokeStackImbalance exception when using IntPtr in .NET 4? (Works in .NET 3.5)
(3 answers)
Closed 4 years ago.
I have a problem with my code, which it can be run on vb6 but somehow it crashed on vb.net
Public Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As String, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long
And here is how i call that function:
Dim lRetval As Long
'Get Host IP Address in host.ini
sHostIP = Space(128)
lRetval = GetPrivateProfileString("HOSTPATH", "HOSTIP", "", sHostIP, Len(sHostIP), "Host.ini")
The error says:
Managed Debugging Assistant 'PInvokeStackImbalance' : 'A call to PInvoke function 'BDS ByPass!CreateBulkCIF.GlobalClass::GetPrivateProfileString' 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.'
Please help... I cant find any something useful anywhere.
The most common cause of this issue is using a function signature that was intended for VB6 rather than VB.NET. If you have a parameter or return of type Long then that is almost certainly the case. Windows API functions and other unmanaged APIs generally work with 32-bit integers. In VB6, the Long type was 32-bit and the Integer type was 16-bit. In VB.NET, the Long type is 64-bit and the Integer type is 32-bit. You should almost always be using Integer rather than Long in VB.NET.
Pinvoke.net shows the signature for that function as the following:
<DllImport("kernel32.dll", SetLastError:=True)>
Private Shared Function GetPrivateProfileString(ByVal lpAppName As String,
ByVal lpKeyName As String,
ByVal lpDefault As String,
ByVal lpReturnedString As StringBuilder,
ByVal nSize As Integer,
ByVal lpFileName As String) As Integer
End Function
You should use that site as your first choice for VB.NET API signatures.
I've purchased a license of BoxedAPP and when I wrote for help to the support mail I got any answer.
I've downloaded the SDK examples but all the important examples are in C# (and even if I use a translator I can't understand it), and the vb.net examples are for store files not executing they.
My question is simple, How I can use BoxedAPP to store a file in memory (Virtualize a file) and then execute it from memory?
For example I want to virtualize a Video file named "test.avi" as "my.resources.test" and then execute it with "process.start", this is what I've tryed to virtualize my recurse but don't run:
BoxedAppSDK.NativeMethods.BoxedAppSDK_CreateVirtualFile(My.Resources.test, _
BoxedAppSDK.NativeMethods.EFileAccess.GenericAll, _
BoxedAppSDK.NativeMethods.EFileShare.None, IntPtr.Zero, _
BoxedAppSDK.NativeMethods.ECreationDisposition.New, _
BoxedAppSDK.NativeMethods.EFileAttributes.Normal, _
IntPtr.Zero)
The first argument should be a string, check the function declaration:
<DllImport("bxsdk32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Public Shared Function BoxedAppSDK_CreateVirtualFile( _
ByVal lpFileName As String, _
ByVal dwDesiredAccess As EFileAccess, _
ByVal dwShareMode As EFileShare, _
ByVal lpSecurityAttributes As IntPtr, _
ByVal dwCreationDisposition As ECreationDisposition, _
ByVal dwFlagsAndAttributes As EFileAttributes, _
ByVal hTemplateFile As IntPtr) As IntPtr
End Function
Also what does BoxedAppSDK_CreateVirtualFile return?
How can I extract items from other application's gridview? The class name of the control is TStringGrid.
I can get the handle of the TStringGrid window with FindWindowEx using these declarations:
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function FindWindow( _
ByVal lpClassName As String, _
ByVal lpWindowName As String) As IntPtr
End Function
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function FindWindowEx(ByVal parentHandle As IntPtr, _
ByVal childAfter As IntPtr, _
ByVal lclassName As String, _
ByVal windowTitle As String) As IntPtr
End Function
code:
Dim TheMainForm As Integer = FindWindow("form", "fname")
Dim GV As Integer = FindWindowEx(TheMainForm, 0, "TStringGrid", "")
How can I extract the items from GV (TStringGrid handle)?
(I have to finish this project by tomorrow.)
A Delphi string grid is not a windows control. It's a custom Delphi control. As such it doesn't respond to windows messages asking for its content. Without the source of the app you would need to reverse engineer the app to work out where the content is stored.
Realistically the most effective way to do this will be to inject a thread into the target application. That thread can then do the work of reading the information and can then use some IPC to get the data back to your VB process.
In order to do this you will, ideally, need:
Knowledge of the exact version of Delphi used to build the app.
A deep understanding of the Delphi compiler and RTL.
The Delphi VCL source code for TStringGrid.
I've no idea how you'll be able to synchronize your reading thread with the Delphi app.
Anyway, whilst what you ask for is, in theory possible, in reality it is completely impractical. The sensible solution is to ask the authors of the Delphi program to provide an automation interface.
I am migrating project from .net 3.5 to .net 4.0 and faced the following issue.
There are 2 DllImport statements:
<DllImport("hid64.dll")> _
Public Sub GenerateHardwareID( _
<MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> ByVal Buffer As Byte(), _
ByVal BufferLength As Int32)
End Sub
<DllImport("hid64.dll")> _
Public Function BufferToString( _
<MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> ByVal Buffer As Byte(), _
ByVal BufferLength As Int32) As <MarshalAs(UnmanagedType.LPWStr)> String
End Function
For the .NET 3.5 both functions work well. But for the .NET 4.0 the call of the BufferToString function breaks execution of the programm without raising any exception.
I played around with CallingConvention, CharSet and so on fields of the DllImport attribute:
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.dllimportattribute.aspx
without success.
This variant:
<DllImport("hid64.dll", CharSet:=CharSet.Auto, PreserveSig:=False, SetLastError:=True)> _
Public Function BufferToString( _
<MarshalAs(UnmanagedType.LPArray)> ByVal Buffer As Byte(), _
ByVal BufferLength As Int32) As <MarshalAs(UnmanagedType.LPWStr)> String
End Function
does not break execution of the programm but the function returns 'Nothing'.
Here's what I believe to be the most likely explanation.
The BufferToString function has a return value that is a string. The p/invoke marshaller has to marshal that from native to managed. It does that by assuming that the native code returns a null-terminated character pointer that was allocated by the COM allocator. When it has finished transferring the content to a .net string it calls CoTaskMemFree on the pointer. If that memory was not allocated by the COM allocator then you may see failures at this point.
To get around the problem you have a few options. You could change the p/invoke for BufferToString to return IntPtr. Copy the contents to a .net string with Marshal.PtrToStringUni. This then leaves you with the responsibility of disposing of the unmanaged memory. Presumably the unmanaged library offers you a mechanism to do that.
If you wrote the unmanaged library then you can use an alternative solution. Leave the p/invoke exactly as it currently is but change the unmanaged library to allocate the return value using CoTaskMemAlloc. That then will match with the p/invoke marshaller's assumptions.
I am updating our "Printer Monitoring" application. Previously this application runs successfully on Windows 2000 server. Now we shifted to Windows 7 server. On windows 7 our "Print monitor" application crashes. When I debug it, I found that our SetJob function throws the following exception:
The parameter is incorrect.
Does anyone know anything about this?
Function call:
SetJob(
mhPrinter,
midJob,
0,
IntPtr.Zero,
PrintJobControlCommands.JOB_CONTROL_PAUSE) 'Here exception is thrown
Spooler API which we use :
<DllImport("winspool.drv", EntryPoint:="SetJob", _
SetLastError:=True, CharSet:=CharSet.Ansi, _
ExactSpelling:=False, _
CallingConvention:=CallingConvention.StdCall)> _
Public Function SetJob _
(<InAttribute()> ByVal hPrinter As IntPtr, _
<InAttribute()> ByVal dwJobId As Int32, _
<InAttribute()> ByVal Level As Int32, _
<InAttribute()> ByVal lpJob As IntPtr, _
<InAttribute(), MarshalAs(UnmanagedType.U4)> ByVal dwCommand As PrintJobControlCommands _
) As Boolean
Please have a loop here, how the function has to be build and how the parsmeters are called:
http://www.pinvoke.net/default.aspx/winspool.setjob
It is a bit different then you implemented it. Hope it will help.