Type Mismatch in VB6 on call to method in .NET DLL - vb6

I have a .NET DLL that serves as a wrapper to a 3rd party application. The DLL is registered for COM-Interop as follows:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe /tlb /codebase "C:\Dev\1) Source\TAC10_CAD\Lib\PowerPhoneInterface\PowerPhoneInterface.dll"
There are multiple methods in the DLL that are called from VB6. All work perfectly except one. The .NET function prototype for that method is as follows:
int SetAniAli([Optional] string incidentType);
In VB6, I invoke the problematic method as follows:
If GetSettingBitValue("G_POWERPHONE_ENABLE") Then
If CheckPowerPhoneConnection() Then
frmParent_Dispatch.PowerPhoneInterface.SetCallerInformation person,
phone, Callback, Address.FullText
frmParent_Dispatch.PowerPhoneInterface.SetAniAli
rc = frmParent_Dispatch.PowerPhoneInterface.SetAniAli
If rc = 10 Then
PowerPhoneCallInit = True
Else
Call modCAD.SetWarning("Attempt to set ANIALI information failed.")
End If
End If
End If
PowerPhoneInterface is the object reference to my DLL. The first method call (SetCallerInformation) works great. In addition, there are two other DLL calls invoked from the function CheckPowerPhoneConnection that also work great. However, SetAniAli gives a "type mismatch" error every time. I have rc defined as a Long in VB6, but also tried Variant. No success with either.
I have googled until I get blurred vision and cannot seem to find what is wrong with the call.
Any suggestions would be greatly appreciated.

I'm not sure if this is the reason or not, but I modified the SetAniAli method to make the incidentType parameter required vs optional and the problem is no more. If someone definitively knows that VB6 has a problem with optional parameters or if they require special handling on the VB6 side, please post a comment so that others can benefit.

Related

SetProcessDpiAwareness error code

I'm adding a call to the SetProcessDpiAwareness windows function as the first thing in my Delphi XE7 application (after dynamically loading the shcore DLL). I know it is preferable to use a manifest to set the DPIAware value and I've got that working separately and will use it eventually. However during development I want to use a command line parameter to set DPIAwareness value, otherwise I have to rebuild the app to change this status.
The problem is that SetProcessDpiAwareness returns the error code $800700A0.
That is not documented in the function description, what does the code mean?
Ah I've found it, thanks to the answer to look at the parameter, I had declared the function type wrong, I had:
TSetDPIFunc = function (const PROCESS_DPI_AWARENESS) : HRESULT; stdcall;
but PROCESS_DPI_AWARENESS was not defined as an enum.
Changed to the following and it now works fine:
TSetDPIFunc = function (const x: Integer) : HRESULT; stdcall;
0x8007XXXX is a Win32 error code encapsulated in a COM HRESULT using HRESULT_FROM_WIN32(). WIN32_FROM_HRESULT(0x800700A0) gives 0xA0, i.e. error code 160, which is ERROR_BAD_ARGUMENTS ("One or more of the input parameters are not correct").
It makes no sense for me though that you get this error, since this function doesn't even take any arguments!
So the only thing I can think of would be that it has something to with the issue described here, assuming you changed the DPI settings yourself for testing and it failed then:
So it seems that in order for SetProcessDPIAware (and the related approaches: SetProcessDpiAwareness() and manifest with true) to work correctly, one has to log out and login again after changing the DPI setting and before running the program.
By the way, in case this is helpful: For testing manifests without totally rebuilding, you could use mt.exe to attach a manifest to your application from the command line.

Runtime error 429 When trying to create ActiveX component

Runtime Error 429 -ActiveX Component Can't Create Object
This error comes up when my program executes the following lines.
Private WithEvents CommClient As XXcommClient
Private Sub Class_Initialize()
'Initializes the CommClient object.
Set CommClient = CreateObject("COMMLIBXLibCtl.XXcommClient") 'errors here
what is missing? >_<
i've already added XXCommLibX.dll as a reference in this project (and it contains the class definitions (i think that's what they're called) for XXcommClient and XXcommServer)
i'm running this on win8.1. i've already changed the access permissions and stuff in mmc comexp.msc /32 for "XXCom.XxInfo" (which contains the above code). the settings btw are none, everyone can edit, and interactive user.
can someone please point me to the right direction? i've been going in circles for the past few days huhuhuhuhu
#Bob77 had it right.
It was actually a) i did not have the dll registered properly.
XXCommLibX.dll was actually dependent on three other .dlls and two .exes. This detail was actually mentioned in the manual. It's embarrassing, really.
After properly registering the dll, i went back to using this line:
Set CommClient = new XXcommClient
... and it worked. >.<

Microsoft AJAX: Unable to get property 'x' of undefined or null reference

How do I troubleshoot the following error being thrown by a Microsoft AJAX JavaScript framework method? It is an automatically generated line of JavaScript from a custom User Control in a Web Forms App (Sitefinity 5 CMS)
Error Message:
Unable to get property 'FancyBlockDesigner' of undefined or null reference
Here is the JavaScript that is throwing the error:
Sys.Application.add_init(function() {
$create(SitefinityWebApp.Esd.TheLab.SampleHtmlEditor.FancyBlockDesigner, null, null, {"Editor":"propertyEditor_ctl00_ctl00_ctl00_ctl00_ctl00_Editor","propertyEditor":"propertyEditor"}, $get("propertyEditor_ctl00_ctl00_ctl00"));
});
Rather than discuss the ascx and cs files that try to abstract this detail away from me, I want to know what this error means. If I understand the detail, the abstraction might make more sense.
"$create" function in ASP.NET Ajax creates an instance of JavaScript class. Microsoft had their own opinion on how to make JavaScript object orientated and as time had shown, their approach wasn't exactly perfect.
Anyhow, to try to explain what is happening, let me give a bit of an overview oh how it works. We start by a server side control which implements IScriptControl interface which mandates two members: GetScriptDescriptors and GetScriptReferences. The second one is pretty straightforward - it lets you register references to all JavaScript files that you control will require. The GetScriptDescriptors, on the other hand, let's you define all the instances of JavaScript classes you want to use as well as it lets you set their properties - initialize them, if you will.
What the autogenerated JavaScript code you've pasted says is basically that you have defined in GetScriptDescriptors that you will need an instance of type "SitefinityWebApp.Esd.TheLab.SampleHtmlEditor.FancyBlockDesigner" where you want Editor property to be initialized. This code will go and look for a JavaScript constructor that looks like this:
function SitefinityWebApp.Esd.TheLab.SampleHtmlEditor.FancyBlockDesigner(element) {
}
that most probably also has a prototype defined, something like:
SitefinityWebApp.Esd.TheLab.SampleHtmlEditor.FancyBlockDesigner.prototype = {
}
Now, since the error you have posted states: "Unable to get property 'FancyBlockDesigner' of undefined or null reference", most probably one of the following is the problem:
You have not included the JavaScript file which contains the class (constructor + prototype) that I've talked about above
You have forgot to add the "FancyBlockDesigner" to the constructor (it seems that you do have other object, perhaps through MS Ajax namespaces - "SitefinityWebApp.Esd.TheLab"
You have not registerd the "SampleHtmlEditor" namespace. Make sure at the top of your JS file you have this: Type.registerNamespace("SitefinityWebApp.Esd.TheLab.SampleHtmlEditor");
So, short story long, the function with name "SitefinityWebApp.Esd.TheLab.SampleHtmlEditor.FancyBlockDesigner" cannot be found.
Hope this helps,
Ivan

Language Service: ParseReason.Check never called after migrating to VS2010

I just migrated my language service from VS2008 to VS2010. Everything works fine except for one important thing: I no longer get LanguageService.ParseSource invoked for ParseReason.Check. It do get a single invoke after opening a file. But after editing code, it no longer gets invoked.
Any ideas what could be causing that?
I also migrated a language service from 2008 to 2010. Can you check if you've fallowed all of these steps?
http://msdn.microsoft.com/en-us/library/dd885475.aspx
I didn't have to do anything else, which I verified by diffing the important files in our depot before and after the change.
I don't know if you ever figured your question out, but have you tried making sure that your Source class' LastParseTime is set to 0 when creating it? I seem to recall some issues with Check not happening unless you manually set LastParseTime to 0 when creating your Source object.
Protip: If you use .NET Reflector, you can disassemble all of the base classes for the LanguageService framework and get a pretty good understanding of how it all works under the hood. The classes you'd be interested in live in Microsoft.VisualStudio.Package.LanguageService.10.0.dll, which should be installed in the GAC. I've found this to be unimaginably helpful when trying to figure out why things weren't working in my own Language Service, and being able to step through the source code in the debugger mitigates almost all the pain of working with these frameworks!
When your Source object is initialized, it starts off with a LastParseTime of Int32.MaxValue. The code that causes fires off a ParseRequest with ParseReason.Check checks the LastParseTime value to see if the time since the last change to the text is less than the time it takes to run a parse (or the CodeSenseDelay setting, whichever is greater).
The code that handles the response from ParseSource is supposed to set the LastParseTime, but as far as I can tell, it only does that if the ParseReason is Check.
You can get around this issue by setting Source.LastParseTime = 0 when you initialize your Source. This has the side-effect of setting CompletedFirstParse to true, even if the first parse hasn't finished yet.
Another way to fix this issue is to override Source.OnIdle to fire off the first call to BeginParse() This is the way I would recommend.
public override void OnIdle(bool periodic)
{
// Once first "Check" parse completes, revert to base implementation
if (this.CompletedFirstParse)
{
base.OnIdle(periodic);
}
// Same as base implementation, except we don't check lastParseTime
else if (!periodic || this.LanguageService == null || this.LanguageService.LastActiveTextView == null || (this.IsCompletorActive) || (!this.IsDirty || this.LanguageService.IsParsing))
{
this.BeginParse();
}
}

How do I access the names of VB6 modules from code?

I am currently maintaining some code, which is likely to be refactored soon. Before that happens, I want to make the standard error handling code, which is injected by an Add-In, more efficient and take up less space. One thing that annoys me is that every module has a constant called m_ksModuleName that is used to construct a big string, which is then rethrown from the error handler so we can trace the error stack. This is all template code, i.e., repetitive, but I could easily strip it down to a procedure call. Now, I have fixed the code so that you can pass the Me reference to the procedure - but you can't do that for the BAS modules. Nor can you access the project name (the part which would be passed as part of a ProgramID, for instance) - although you get given it when you raise an error yourself.
All these strings are contained in the EXE, DLL or OCX - believe me, I've used a debugger to find them. But how can I access these in code?
AFAIK there's no way to get the name of a BAS module in code. The usual solution is to use a module-level constant as in Mike's answer.
AFAIK the only way to get the ProgID (programmatic ID, Project Name in project properties dialog) is to raise an error in a BAS module, trap it, and read the Err.Source.
It's all quite a hassle, and that's why we don't usually bother including the module name or the ProgID in our standard error handlers. We "roll our own" call stack, with the names of the routines. That's always enough information to find out which modules are involved. Routines in BAS modules usually have unique names, right?
Something like this, and you can add this automatically with the free MZTools VB6 add-in.
Sub / Function whatever
On Error Goto Handler
do some stuff
Exit Sub / Function
Handler:
Err.Raise Err.Number, "(function_name)->" & Err.source, Err.Description
End Sub
Every top-level routine in a DLL or OCX has a similar error handler but also includes App.ExeName so we can tell when errors cross component boundaries.
I'm not sure of an easy way to programmatically get the name of the module that you are in. The usual solution is to set a variable at the top of each method to the name of the module, and then it is available to the error handler for use in logging:
'In MyModule.bas'
Public Sub Foo()
Const MODULE_NAME As String = "MyModule"
On Error GoTo ErrorHandler
' Code here '
Exit Sub
ErrorHandler:
LogError Err.Number, Err.Description, MODULE_NAME
End Sub
If you are using an add-in such as MZTools, you have it generate this boilerplate code for you.
As for getting the current component name, you can access this using App.EXEName (despite the name, this works for other project types such as DLL's). This value is pulled from the Project Name field in the project's properties (Project -> Properties) when running in the IDE, and from the name of the compiled binary file (minus the file extension) when running outside the IDE.

Resources