Debug a bad DLL calling convention - vba

How do I debug a bad DLL calling convention error in MSAccess VBA code?
I made some changes to a function in a module and then got the error. How do a debug it to find the cause?
The error occurs on the Exit function statement of the function.

I fixed this problem by making a change in one of my class modules, executing a compilation from the Debug menu, and then undoing the change.
Background: In my case I've seen this in Excel without any external references. It happened, as with your problem, on an Exit Function call. Excel doesn't seem to have a /decompile option. I suspect that one of my class modules had mis-compiled for some reason, and Excel won't re-compile unless it thinks something has changed.

Have you checked your references and decompiled?
"C:\Program Files\Microsoft Office\Office\MSACCESS.EXE"
"d:\My Documents\access\mayapp.mdb" /decompile
See also: http://www.granite.ab.ca/access/decompile.htm
VBScript Decompile
Check references in code
Dim ref As Reference
Dim sMsg As String
''Available since 2010
If BrokenReference Then
For Each ref In References
''Available since at least 2000
If ref.IsBroken Then
sMsg = sMsg & "Ref Name: " & ref.Name
'Also, if required
'sMsg = sMsg & vbCrLf & "Built In: " & ref.BuiltIn
'sMsg = sMsg & vbCrLf & "Full Path: " & ref.FullPath
'sMsg = sMsg & vbCrLf & "GUID: " & ref.Guid
'sMsg = sMsg & vbCrLf & "Kind: " & ref.Kind
'sMsg = sMsg & vbCrLf & "Major (version number): " & ref.Major
'sMsg = sMsg & vbCrLf & "Minor (version number): " & ref.Minor
sMsg = sMsg & vbCrLf & "=================================" & vbCrLf
End If
Next
MsgBox sMsg
End If

I experienced and worked around this error using the .NET library for WinSCP from MS Access VBA.
What happened was:
A function UploadSomething for connecting to an SFTP server and uploading a file worked fine.
Within the function UploadSomething changed the "resume support" option with this code: myTransferOptions.ResumeSupport.State = TransferResumeSupportState.TransferResumeSupportState_Off
After the change, the code worked as desired. However in the code that called UploadSomething, Error 49 was thrown after the function had finished.
The error happened both when stepping through the code using the debugger and when executing at once outside of the debugger. Recompiling the project didn't work for me.
What did work was this:
Remove the reference to the COM component
Add the reference to the COM component
Recompile

In Excel VBA, this can be caused by any of several problems:
A parameter or return-value type mismatch.
An object method (such as AutoFit) applied to an erroneous object
variation for which that method isn’t available.
A call to an external library function.
Broken library references
For resolutions to these causes, see my post at: Runtime Error 49, Bad DLL calling convention

I've just got this in Excel and wondered if anyone else have gotten it previously. My solution was to move around the references to my own DLL and click 'Compile <Project>'.

We've run into some problems with VBA when trying to call a DLL compiled in Intel Fortran. It turns out that you need to align the calling conventions back to a "C" context with the compiler flag calling convention: cfv
More info here on the Intel website
Another useful thread on the same problem: Intel Fortran DLL <-> C

Related

Compile a visual studio solution programmatically

I have a requirement of programmatically compiling a solution. I cannot directly give the path of MSBuild because it differs between 2013 and earlier versions.
I am sharing my code below -
Using exeprocess As New System.Diagnostics.Process
exeprocess.StartInfo.FileName = "cmd"
exeprocess.StartInfo.CreateNoWindow = True
exeprocess.StartInfo.UseShellExecute = False
exeprocess.StartInfo.RedirectStandardInput = True
exeprocess.StartInfo.RedirectStandardOutput = True
exeprocess.Start()
Dim sw As StreamWriter = exeprocess.StandardInput
Dim sr As StreamReader = exeprocess.StandardOutput
sw.WriteLine("PUSHD C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\")
sw.WriteLine("call vcvarsall.bat")
sw.WriteLine("#MSBuild /t:Rebuild" & " /flp1:logfile=" & """" & logFilePath & """;errorsonly" & " " & """" & solutionPath & """")
sr.ReadLine()
While Not sr.EndOfStream()
sr.ReadLine()
End While
End Using
My requirement is to wait until the compilation is over.
The issue is that it hangs at the line "While Not sr.EndOfStream()".
I am unable to understand the reason for the issue. Not sure if this is the right way of ensuring that the compilation is over.
Any help is highly appreciated.
I can't tell what your specific problem is, but a few recommendations:
Don't bother writing to input stream, just generate a simple .bat text file and launch it.
You can use Microsoft.Build.Utilities.ToolLocationHelper to get any of the paths.
You can use Microsoft.Build.Execution.BuildManager to build programmatically.

Out of Memory Error VB6 when try to add an existing Class module

I'm working on a project in VB6. I have to add a download functionality. It contains 1 form, 1 class module and 1 module (bas) files. When I add the existing module to my project, it is successful But when I try to add the class module or the frm file to the project, it says OUT OF MEMORY. I have been banging my head against this issue for quite some time now but couldn't find any solution.
I cannot post any code because it's a company project. All I can tell is that its a huge project with thousands of lines of code. The module I'm trying to add is used to download a file over HTTP, and it accesses the methods in Wininet.dll.
I don't know if the project has reached it maximum limit of lines of code, or whether it's an issue of variables.
I have heard that making a DLL can solve this issue, but we don't need that. Can anyone help?
I think I've faced something similar in the past, and after some digging and trying different things it turned out to be the number of variables / forms / controls that we had in the project. There is a limit to the number of unique variable, constant, and control names you can have in the project.
The way we proved it was to add the module that didn't quite break it, then add an empty module. In the empty module start adding variables until it breaks, it shouldn't take to long.
We cured it by going through the code and changing names of labels on forms to be control arrays, using constants for strings, and removing any code that was old an no longer required. Try to remove unused variables as well.
If it makes life easier you could try moving some of the code out to dll's.
Hope this helps.
Cast your eye over this, the sub sections might help:
VB6 Project Limitations
You know there are high level objects available that do in two or three lines what requires many in Wininet.
Try this way using xmlhttp. Edit the url's etc. If it seems to work comment out the if / end if to dump info even if seeming to work. It's vbscript but vbscript works in vb6.
On Error Resume Next
Set File = WScript.CreateObject("Microsoft.XMLHTTP")
File.Open "GET", "http://www.microsoft.com/en-au/default.aspx", False
'This is IE 8 headers
File.setRequestHeader "User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 1.1.4322; .NET CLR 3.5.30729; .NET CLR 3.0.30618; .NET4.0C; .NET4.0E; BCD2000; BCD2000)"
File.Send
If err.number <> 0 then
line =""
Line = Line & vbcrlf & ""
Line = Line & vbcrlf & "Error getting file"
Line = Line & vbcrlf & "=================="
Line = Line & vbcrlf & ""
Line = Line & vbcrlf & "Error " & err.number & "(0x" & hex(err.number) & ") " & err.description
Line = Line & vbcrlf & "Source " & err.source
Line = Line & vbcrlf & ""
Line = Line & vbcrlf & "HTTP Error " & File.Status & " " & File.StatusText
Line = Line & vbcrlf & File.getAllResponseHeaders
wscript.echo Line
Err.clear
wscript.quit
End If
On Error Goto 0
Set BS = CreateObject("ADODB.Stream")
BS.type = 1
BS.open
BS.Write File.ResponseBody
BS.SaveToFile "c:\users\test.txt", 2

Excel VBA error using WScript.Shell.Run

After recently upgrading from Excel 2010 to Excel 2013, I moved a custom add-in (.xlam) to the new Application.LibraryPath directory (C:\Program Files\Microsoft Office 15\root\office15\Library\BTRTools). There is a bit of code that launches an executable (exe) file (located in sub directory of the add-in). However, since the upgrade/move, I am not getting an error:
PrettyPrintXml.exe - Application Error
The application was unable to start correctly (0xc000007b). Click OK to close the application.
I'm obviously pretty convinced it is file permissions. I have explicitly added myself permissions with full rights to the \Library folder (and all subs). Note that I think I had to do this even with Excel 2010 (folder at C:\Program Files (x86)\Microsoft Office\Office14\Library) to make things work.
However, after all this, I'm still stuck and can not launch the exe file. Any ideas/suggestions on how to make this work?
Code is pretty standard:
Public Sub RunShellExecute(sFile As String, Optional params As String = "", Optional wait As Boolean = False)
Dim wsh As Object: Set wsh = VBA.CreateObject("WScript.Shell")
Dim waitOnReturn As Boolean: waitOnReturn = wait
Dim windowStyle As Integer: windowStyle = 1
Dim exe As String: exe = IIf(Left(sFile, 1) <> """", """" & sFile & """", sFile)
Dim exeParams As String: exeParams = IIf(params <> "", " " & params, "")
Dim errorCode As Integer: errorCode = wsh.Run(exe & exeParams, windowStyle, waitOnReturn)
If errorCode = 0 Then
'// MsgBox "Done! No error to report."
Else
MsgBox "Program exited with error code " & errorCode & "."
End If
End Sub
I know your question is "Why doesn't this work", but I thought you might be interested in an alternate solution: There is a native VBA PrettyPrintXML. You need to add a reference to the MSXML library in your VBA project by clicking "Tools" ---> "References..." and then check the box next to Microsoft XML, v6.0 (or whatever version is included with your version of Office/Windows).
Please change the title of your question, because Excel VBA is able to use WScript.Shell.Run, otherwise you wouldn't be getting your error.
As for the actual issue, this looks like a 32-bit / 64-bit problem. Investigate whether the program you're calling is appropriate for your system and whether it tries to load the right DLLs.
The problem is not file permissions, then you would get a different status code.
You should use a path without spaces in it, something simple like 'C:\BTRTools'. Then it should work.

Issue with an LPR Command in VB

I am creating a VB app which will "move" xls reports from a directory to a ReportSafe app. I am also working in an existing VB app which does just that, so I am using it for reference.
It isn't as simple as moving files from one directory to another, because ReportSafe requires an lpr command to tell it (ReportSafe) which file to pick up.
Here is what I have so far:
Imports System.IO
Module Module1
Sub Main()
''Declarations
Dim Files As ArrayList = New ArrayList()
Dim FileName As String
''Write All Files in *directory* to ReportSafe
Files.Clear()
Files.AddRange(Directory.GetFiles(*directory*))
For Each FileName In Files
Dim RPname As String
Dim RealName As String
RPname = FileName.ToString
RealName = "/"
RealName = RealName & RPname.Remove(0, 34)
Dim a As New Process
a.StartInfo.FileName = "C:\Windows\system32\lpr.exe"
a.StartInfo.Arguments = "-S*ServerName* -Plp -J" & Chr(34) & RealName & Chr(34) & " " & Chr(34) & RPname & Chr(34)
a.StartInfo.UseShellExecute = False
Next
End Sub
End Module
The whole lpr command/arguments are throwing me for a loop. I'm not sure if my question is specific to ReportSafe, and if that's the case, I may be out of luck here. I have pulled this code from the already existing app which moves reports to ReportSafe, and adjusted for my own use, but no luck so far.
FYI, I had to turn on LPR Monitor services to obtain to the lpr.exe
Questions:
What are the proper arguments to pass through to this lpr command?
Is there a problem with the logic that is causing the issue?
I continued to tinker and look at my reference code and discovered some flaws in logic:
For one, the report name I was passing did not include the complete file path.
Another thing is that I never started the process with a.Start(). Rookie mistakes for sure... haha

Open Word Document From Dynamic Directory VB.Net

I have a program for which I have developed a user guide. I have placed this user guide within the project directory. I created a MenuStrip Item by which to open the user guide in Word on the user's machine. I was successfully able to do this with the following code:
Try
userGuide = MSWord.Documents.Open("C:Users\administrator\Documents\VisualStudio2010\Project3\UserGuide.doc")
MSWord.WindowState = Word.WdWindowState.wdWindowStateNormal
MSWord.Visible = True
Catch ex As Exception
MsgBox("An error has prevented the document from opening. The document may not be available." & vbCrLf & vbCrLf & _
"Please try one of the following options:" & vbCrLf & _
"- Check to see if the document is already open" & vbCrLf & _
"- Restart the program")
End Try
The problem is, the path used to open the file will not exist on the users machine. This is a standalone system, so no file share can be created in which to place the document, therefore no common path can be coded.
Is there a way to code dynamic paths? Perhaps something like:
userGuide = MSWord.Documents.Open("%windir%\UserGuide.doc")
Thanks!
if the document will be stored relative to the install path of the application executable, then start with the path of the exe:
Dim path As String
path = System.IO.Path.GetDirectoryName( _
System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase)
Dim docPath as String;
docPath = Path.Combine(path,"UserGuide.doc");