Q. Excel keeps throwing the following error, whenever my addin is loaded (Runtime Error 49, Bad DLL calling convention)
The dialog starts to pop up everytime with no indication of where the error is, despite having absolutely no external DLL references.
OR
Q. Excel crashes every time I save a particular line of code.
How can this be fixed?
This error is probably occurring because of a compiler-bug.
The easiest solution to this, would be to make a small code-change and recompile.
What I usually do is,
1 -> Add a Private Enum type to the top of any module in the addin
Private Enum Something
member = 1
End Enum
2 -> Compile the addin
3 -> Restart excel
4 -> Remove the code change made. It is no longer necessary.
Even though this error refers to an external (DLL) function call, it
can be triggered by a parameter or return-value type mismatch for a
VBA-defined function or subroutine. Furthermore, when it is
triggered by these causes, the debugger sometimes displays the error
point to be a different function call, often higher in the
call-stack, including calls that have been working and stable until
the problem-situation was created. Often, the problem is triggered
by a miss-match between a fixed-type parameter-argument or return value and a
Variant or vice versa.
Example: A Variant-valued function returns a
Long value at run time that is assigned to an Integer variable.
Resolution:
Carefully check all parameter-argument and return
value types and assignment statements, especially for routines that
you have been recently working on. If any are Variant-valued functions, explicitly type-cast to the correct type for the
assignment.
If the above situation is unavoidable due to using the Application.Run method to call a routine in a different workbook (for which you have no control over the parameter definitions), as a result of the Application.Run method passing all arguments ByVal, then, if the containing routine is a Sub, try converting it to a Function with no specified return type. This seems to force a clean-up of the stack and suppresses the error condition being thrown at a higher level in the call-stack.
An object method (such as AutoFit) applied to an erroneous object variation for which that method isn’t available (such as AutoFit
being applied to a range that is neither an entire row or entire
column range). Similarly to the above scenario, the error may be
thrown at the return point of the routine in which the problem
statement exists, not at the statement itself.
Resolution: Start with fixing the
syntax problem. Unfortunately fixes that should work sometimes
continue to throw the error until the VBE editor is reset. I
haven’t deduced the minimal set of steps that resolve that issue but
something like this often works:
Explicit recompile the project.
Save the file and close it.
Re-open the file and re-run the code.
If a call to an external library function is identified as the culprit, refer to Microsoft’s documentation on the error:
Bad DLL calling convention
*Arguments passed to a dynamic-link library (DLL) must exactly match
those expected by the routine. Calling conventions deal with number,
type, and order of arguments. Your program may be calling a routine
in a DLL that is being passed the wrong type or number of arguments.
To correct this error make sure all argument types agree with those
specified in the declaration of the routine that you are calling.
Make sure you are passing the same number of arguments indicated in
the declaration of the routine that you are calling.
If the DLL routine expects arguments by value, make sure ByVal is
specified for those arguments in the declaration for the routine.
Return argument:
One thing that can be easily overlooked when
talking about procedure arguments is the return argument. Make sure
its of the correct type, or that its not missing. Excel/VBA users
are used to the fact that if you leave out a return type for a
function, the system implicitly sets the return type to Variant, and
it works with any returned data. Not so with externally declared
functions!! The return type has to be declared in the DECLARE
statement.*
Broken library references: check whether the library references for your module code are valid. In the VBA IDE, select
Tools=>References to see the list of referenced libraries and make
sure none of the checked items are marked "Missing". If so, fix
those.
Or, the best option ever:
- Rewrite the name of the routine.
- Then recompile !
You're good to go now!
For info, I also experienced "Runtime Error 49, Bad DLL calling convention" in Excel VBA code that had been running fine.
The error was pointing to an internal function call and the fix for me was to change an argument from ByVal to ByRef. There existed a call to another function where that value was already passed ByRef, so this may have been a factor.
Another way instead of "change/add something and recompile" would be to /decompile your project.
Esp. in large access/excel projects that can get ride of a lot of problems.
Just to add another possible cause, I was using the Application.OnTime method to call a public sub with a parameter. The parameter is meant to be a long (the current row), but I'm guessing it's actually passed as a string value.
Here is an example of the OnTime call:
Application.OnTime Now + TimeValue("00:00:01"), "'UpdateEditedPref " & curRow & "'"
I tried performing an arbitrary update to the code and recompiling, but this didn't fix the issue. What fixed it was changing the parameter type from long to string in the called sub:
Public Sub UpdateEditedPref(ByVal inRowStr As String)
Then you just need to convert the string to a value within the sub. Thankfully, no more error.
Update: Passing a parameter using Application.OnTime seems to have caused another error, "Cannot run the macro". I was getting this error when the worksheet was locked. I'm still using Application.OnTime, but instead of passing a parameter, I'm saving the value in a global variable and using that value in the called sub. This now appears to be working correctly.
The OnTime call now looks like this:
' Set global variable
gCurRow = curRow
Application.OnTime Now + TimeValue("00:00:01"), "UpdateEditedPref"
I had a similar issue, on my development PC it was working just fine. Funny thing was I had two separate calls to the same routine, one worked and the other didn't. On a production PC, kept getting the error. Tried renaming the routine, changing the parameters, parameter types to no avail.
What worked for me was to move the failing calling routine into the same module as the called subroutine.
The routine that was working previously was already in the same module.
In my case this was "caused" by an excessive use of the continue character _ in a single if conditional
I had already recompiled, checked all return codes, moved modules around ,restarted excel , restarted my computer, copied the code to a brand new Excel spread-sheet, I read this article and the bit about return codes made me think about how many returns can be in an if statement
I had this
If CompressIntoOneLineON(rg1, rgstart, rgend) or _
CompressIntoOneLineOS(rg1, rgstart, rgend) or _
CompressIntoOneLineOGN(rg1, rgstart, rgend) or _
CompressIntoOneLineOGS(rg1, rgstart, rgend) or _
CompressIntoOneLineGO(rg1, rgstart, rgend) Then
<code>
End If
I was getting the error when the subroutine containing this code exited
So I changed to this
matched = True
If CompressIntoOneLineON(rg1, rgstart, rgend) Then
ElseIf CompressIntoOneLineOS(rg1, rgstart, rgend) Then
ElseIf CompressIntoOneLineOGN(rg1, rgstart, rgend) Then
ElseIf CompressIntoOneLineOGS(rg1, rgstart, rgend) Then
ElseIf CompressIntoOneLineGO(rg1, rgstart, rgend) Then
Else
matched = False
End If
if matched then
<code>
and the error went away
My experiments have shown:
The error: 'Runtime Error 49, Bad DLL calling convention' disappeared when I replaced the declarations:
Dim coll as new Collection
on
Dim coll as Collection
Set coll = New Collection
The object must explicitly become Nothing on failure of creation (if it does not itself) so that its existence can be traced.
Thanks, RubberDuck VBA
Related
I just created this tiny Office script:
async function main(context: Excel.RequestContext) {
context.workbook.names.getItem("Newname").delete;
}
The range name 'Newname' exists in the current workbook, the code runs without error but the name is not deleted. Why? I would expect to receive a runtime error if I'm not allowed to delete range names.
I think it missed the bracket:
context.workbook.names.getItem("Newname").delete();
I just tried by this gist, you could have a try. https://gist.github.com/lumine2008/f55a6265a93b421112de210b22e9a48a
delete is a method. In JavaScript, a method requires opening and closing parentheses, even if there are no parameters to be passed:
context.workbook.names.getItem("Newname").delete();
My tests confirm this. Also, the code should include await.context.sync();
It's important to realize that JavaScript supports assigning a method to a variable (object), similar to assigning a function to an Excel Name, by leaving off the parentheses. This object can then be used at some point to execute the method. This is why no errors are thrown when the parentheses are omitted.
Example:
const deleteNewName = context.workbook.names.getItem("Newname").delete;
deleteNewName();
(Thanks to Lumpenstein for this information about JS kindly provided in a comment.)
I've looked on some similar question of "Object required on calling sub", but None of them seems to help with my problem. I want to call a sub(for example, in sheet2) from a sub in sheet1 like
Private Sub Worksheet_Activate()
ThisWorkbook.ActiveSheet.Cells.Clear
Call sheet2.generate <== where the error comes from
End Sub
where generate is the sub name on sheet2 which don't require any parameter
but it tells me that Object required and sendback an error.
I've tried:
without using call
sheet2.generate
without sheet name
generate
call generate
and adding a useless parameter for calling( also added to generate sub)
call sheet2.generate(1)
but it's not working too, so i detele that parameter as it have no use in the code.
there is no problem on generate sub(which i test for many time)
still, all of the above do not work for me, can someone provide a vaild way to solve this?
I've found that the problem is not at calling function,but instead, stuffs INSIDE function have problem, and debug arrow goes function and says "error 1004", after fixing some variable problem of the function, the problem no longer shows.
BRUH
New to VBA but years of experience with assembler, C and C#. I have created a Private Sub called CPScenarioData(wsname as String, rownum As Integer). When I call the procedure using the statement:
CPScenarioData(wsname, l)
I get an error 'Compile error: Expected =', however when I preceded the statement with Call no error occurs, why is this. I have other Private subs that I call without using Call that work fine. I am sure there is a simple answer or mistake I have made and will feel very sheepish when I see the answer but that's life. I am using Excel 2013 VBA. Thank you for your help.
It's a quirk (feature according to taste) of VB. To call a sub, you don't include brackets. So simply type:
CPScenarioData wsname, 1
Normally brackets are used to denote a Function, which returns a value. In VB you must provide a variable to receive the returned value. (Hence the compile error for missing =; it is expecting a = CPScenario(wsname, 1)).
Adding the word Call enables you to keep the brackets for Subs (equivalent of c# void).
For VBA functions and most programming in general i understand general program execution to occur something like this...
Inside a sub procedure if you call a function (it should return a value), in this case it would return a value to variable num.
To expand this means that execution reaches the line where I call the function, and should then skip down to where the function is written, and go through executing each line inside that function.
This is how it has worked for me previously when I use the F8 key to highlight and follow the code execution line by line.
The problem
The problem is when execution reaches the line inside the sub procedure where the function is called the function is just skipped over and execution doesn't go inside the function and run each line inside it.
(and I should say when this happened I had 95% of a working program, and i've tried re-writing the function, calling other functions).
But whenever a function is called execution of the code doesn't go into the function itself it just skips over it, and the variable that holds the result of the function therefore is left empty.
I've tried creating breakpoints at the beginning of the function and when the function is called in the sub procedure however this hasn't worked.
At the very least execution should get to the definition of the function (Function FirstRow() etc) and throw and error but it's not doing that.
Sub Main
Dim num as double
Dim sheet_name as string
num = FirstRow(sheet_name)
End Sub
Function FirstRow(sheet as string) as double
select case sheet '<<----- execution never gets inside the function
case "sheet"
FirstRow = 8
case "sheet2"
FirstRow = 12
end select
End Function
Put a value in sheet_name and try again.
What caused some functions to stop working (and execution of code to not reach the function definition or move inside it) was unloading the form.
All the functions and sub procedures were defined in a module which is part of the form.
Therefore you can only access this module by clicking on the controls on the form.
This meant that I only had one folder FORMS - which had one form inside it, and didn't have a Modules Folder which would normally appear in the VBA Project section.
Therefore I can either:
1) wait until all the data processing has been done before unloading the form right at the last minute
or
2) move the functions to a new module (External to the Form in the MODULES folder) so when the fuctions and sub procedures are called they don't rely on the form being open.
I have a VBA function that worked fine, until I tried to pass an extra variable to it. Now the code won't run, and I get an error stating Expected:=, I've tried renaming the function, but no help.
Was - Function GetData(site_add)
Changed to Function GetData(site_add, temporary) and failed - despite changing the call to the function accordingly...!?!
Is it possible that the compiler is glitching and I should focus on that? I have other functions in the code that use 5 call 5 variables and don't even call/use them all...!? Help...
By adding the second parameter, you are effectively telling the compiler that every call to this method now requires two parameters instead of one. So you have to find everywhere you call the GetData() function and make sure it now passes two parameters instead of one, even if the second parameter is Nothing. Now, if you want it to default to nothing so you don't need to pass it you can rewrite it as
GetData(site_add, Optional temporary)
*my vb is rusty, so take my example with a grain of salt please.