VB6 dll working in VB6 application, not in ASP - dll

I'm working on an old project in asp
I've never worked with vb6 or asp before I am a .net developer
anyway
I made a .net dll and changed some compile options to make it work with vb6
the code doesnt matter
I made a "wrapper kinda" dll in vb6
Public Function EncryptWrapper(ByVal parameterstring As String, ByVal isShaIn As String, ByVal HashType As String) As String
Dim o
Set o = CreateObject("SHA1Module.Conversion")
EncryptWrapper = CStr(o.EncryptToSHA1(CStr(parameterstring), CBool(isShaIn), CLng(HashType)))
End Function
and a form in vb6 that calls it
Private Sub Command1_Click()
Dim message
Dim myObject
Set myObject = CreateObject("SHAModuleWrapper.Encryption")
message = myObject.EncryptWrapper(txtIn.Text, "1", "2")
Set myObject = Nothing
txtOut.Text = message
End Sub
this works perfectly
now in asp I try calling that dll and I get an error
<% Dim strMessage
Dim message
strMessage = "hello"
Dim myObject
Set myObject = Server.CreateObject("SHAModuleWrapper.Encryption")
message = myObject.EncryptWrapper("testdagtestdagtest", "1", "0")
Response.Write(message)
%>
this is the error message
SHAModuleWrapper error '800a0005'
Invalid procedure call or argument
/asptest/Default.asp, line 15
It's not the parameters or the output
it's this part that is causing the trouble
**Dim o
Set o = CreateObject("SHA1Module.Conversion")
EncryptWrapper = CStr(o.EncryptToSHA1(CStr(parameterstring), CBool(isShaIn), CLng(HashType)))**
Does anybody have an idea?

Dim o
Dim message
Dim myObject
These lines are cause for concern. These will be a variant as they are not a defined type.
Option Explicit is your friend in VB6 - use it always!
Have a look at this link: Avoid program bugs in VB6 with the Option Explicit statement for more information.

A lot of frustration and batch files later I found the solution.
I needed to create a strong name for my assembly and register it in the GAC
This is a good step by step tutorial on how to solve this issue
Tutorial
these 2 steps helped me
8) Generate a public/private key pair
sn -k MarkItUp.key
9) Add the attribute to my assembly for registering it:
<Assembly: AssemblyKeyFile("C:\MarkItUp.key")>

in your bad code you have
Set o = CreateObject("SHA1Module.Conversion")
should it be
Set o = CreateObject("SHA1Module.Encryption")

Check that IUSR_Machine has permission to execute your dlls.

Related

Creating a new IUI Automation Handler object in order to subscribe to an automation event

So, here it goes. To start, A disclaimer, I understand that MS Access is not built for this kind of work. It is my only option at this time.
I have done just a bit of Automation using UIAutomationClient and I have successfully used its other features, however I cannot for the life of me get it to subscribe to events.
Normally, it is supposed to be a bit like this:
Dim CUI as new CUIAutomation
Dim FocusHandler as IUIAutomationFocusChangedEventHandler
Set FocusHandler = new IUIAutomationFocusChangedEventHandler(onFocusChanged)
C.AddFocusChangedEventHandler(Element,TreeScope_Children, null, FocusHandler)
end function
'
'
Function onFocusChanged(src as Object, args as AutomationEventArgs)
''my code here
end function
Yet when I attempt this, I get the error "expected end of statement" on the line:
FocusHandler = new IUIAutomationFocusChangedEventHandler(onFocusChanged)
additionally, if I leave off the (onFocusChanged) I get the error "Invalid use of new Keyword".
It seems like I am missing a reference somewhere. The usual drop down when using "new" does not contain the IUI handler classes though they are in the object library.
I am not sure if there is just some piece I am not accounting for in the code since I am using vba, but all examples seem to be for .net or C#/C++. Any help would be appreciated.
Additionally, I have no problem finding the element in question and all other pieces work fine. If you need any other pieces of the code let me know.
Edit: added set to line 3. No change in the problem though.
After two years this probably isn't relevant any more, but perhaps somebody else encounters this problem... The answer is to create a new class that implements the HandleAutomationEvent method.
Here I created a class named clsInvokeEventHandler and (importantly) set the Instancing property to PublicNotCreatable:
Option Explicit
Implements IUIAutomationEventHandler
Private Sub IUIAutomationEventHandler_HandleAutomationEvent(ByVal sender As UIAutomationClient.IUIAutomationElement, ByVal eventId As Long)
Debug.Print sender.CurrentName
End Sub
And to use it:
Sub StartInvokeHandler()
Dim oUIA As New CUIAutomation8
Dim oRoot As IUIAutomationElement
Dim InvokeHandler As clsInvokeEventHandler
Set InvokeHandler = New clsInvokeEventHandler
Set oRoot = oUIA.GetRootElement
oUIA.AddAutomationEventHandler UIA_Invoke_InvokedEventId, oRoot, TreeScope_Descendants, Nothing, InvokeHandler
End Sub

Why Dim as New and Dim/Set in VBA behave differently when I call a COM server?

I have made an out-of-process COM server (C++) that is called from VBA.
For an unknown reason when I call it multiple times (at least two times in the same sub) I'm only able to call it using Dim xx As New xxx.
When I try to call it using Dim xxx As xxx and then Set xx = new xxx , my com server raises a violation reading exception and VBA returns the error code 800706BE.
The following code does work (pseudo code - I removed the irrelevant part). Note that the 'Main' sub call the 'aux' function and that both the Sub and the 'aux' function call my COM server (two different classes).
Function aux() As Double()
Dim com As New COMServer.classe2
Dim Returns() As Double
Returns = com.Method2 'actual call to the COM Server
aux = Returns
End Function
Sub Main()
Dim Resultat() As Double
Dim com1 As New COMServer.classe1
Dim Returns() As Double
Returns = aux ' call Function aux
Resultat = com1.Method1(Returns) 'actual call to the COM Server
End Sub
The following does not work :
Function aux() As Double()
Dim com As COMServer.classe2
Set com = New COMServer.classe2
Dim Returns() As Double
Returns = com.Method2 'actual call to the COM Server
aux = Returns
End Function
Sub Main()
Dim Resultat() As Double
Dim com1 As COMServer.classe1
Set com1 = New COMServer.classe1
Dim Returns() As Double
Returns = aux ' call Function aux
Resultat = com1.Method1(Returns) 'a violation reading (c++) Exception is thrown here
End Sub
Can someone explain me why my code only works in the first case ?
Also note that if I only call the server once in the sub (no call to aux), then both methods ( Dim as New and Dim/Set ) work.
EDIT
I have noticed that in case 1 (the case that works) : my server automatically start and stop two times consecutively (seen in the Windows Task Manager ).
Whereas in second case (the buggy one) : my server start only once - didn't stop and raise the error.
Now I have just modified the second case in the following manner and the exception disappears :
Sub Main()
Dim Resultat() As Double
Dim Returns() As Double
Returns = aux ' call Function aux
Dim com1 As COMServer.classe1
Set com1 = New COMServer.classe1
Resultat = com1.Method1(Returns) 'no more Exception
End Sub
The only difference is that I set my server just before to call it (instead to initialize it before to call my 'aux" function).
Does it makes sense to someone ?
Dim statements aren't executable. Set statements are.
When you do Dim foo As New Bar you're creating an auto-instantiated object variable, which incurs a bit of overhead in the VBA runtime (every call against it validates whether there's a valid object reference).
This is how auto-instantiated objects bite:
Dim foo As New Collection
Set foo = Nothing
foo.Add 42 'runtime error 91? nope.
Debug.Print foo.Count ' prints 1
Set foo = Nothing
Debug.Print foo.Count ' runtime error 91? nope. prints 0
So As New makes VBA go out of its way to ensure there's always a valid object reference for that pointer, no matter what. Every member call on object variables declared As New is valid: VBA will create a new instance before making the member call if the reference points to Nothing - that's the overhead I mentioned earlier, and contradicts LS_dev's answer. Auto-instantiated object variables aren't "only instantiated on first member call" - they're instantiated whenever they need to be.
The answer is likely in your C++ code, not in the client VBA code. Something is wrong with how you're cleaning things up, there's loose ends somewhere - using As New to work around a sloppy COM server doesn't strike me as a good idea (As New should generally be avoided, as a matter of fact, for the unintuitive behavior depicted above).
Problem may be in sequence of call. From my experience, objects declare with As New are only instantiated in first member call, while Set ... = New instantiate object immediately.
Said so, in first case classe2 is created before classe1 which is only created when you call com1.Method1.
In second case, classe1 is created in Set, before classe2.
taking this into account, it seams your COM code somehow create a memory violation if classe1 is created before classe2.

Proper release of COM objects in code

I have just started to migrate some code from VBA to VB.Net. So I am an absolute beginner in VB.Net – but I want to do things right. Maybe some of my questions are stupid but I guess that is because I am a beginner.
So as a first exercise I have developed my first piece of code (see below). Now I thought I have to release ALL COM objects again. Two of them throw errors already while writing the code. And others throw errors at runtime.
But the funny thing is: Weather I release the rest of the COM objects or not (by making the relevant not yet commented lines of Marshal.Release to comments as well – then all lines starting with Marshal.Release are comment lines) the behavior of the code is absolutely the same to my eyes.
Can anybody tell me where I can see/find the difference?
The internet tells me that there must be a difference?
But I guess I just don’t understand (till now).
Besides this many more questions are in my head:
Does every “Dim” statement create a COM Object - that has to be released later on?
If not how do I detect whether a COM object has been created or not? Which “Dim” statements create COM object and which don't?
In this example: Dim ActiveWindow As Object = Nothing Try ActiveWindow = Me.HostApplication.ActiveWindow() Catch End Try
Is
Marshal.ReleaseComObject(ActiveWindow)
identical to
Marshal.ReleaseComObject(Me.HostApplication.ActiveWindow())?
According to this:
http://www.codeproject.com/Tips/235230/Proper-Way-of-Releasing-COM-Objects-in-NET
Would it not be better to release each "level" separately like this:
Marshal.ReleaseComObject(Me.HostApplication.ActiveWindow())
Marshal.ReleaseComObject(Me.HostApplication)
Marshal.ReleaseComObject(Me)
Overall: Am I trying to release too much? Or is it correct / good practie?
And what does "GC.Collect()" and "… = Null" have to do with all this? I have not used it at all. Should I better use it? Why? ( "... = Null" I have seen here:
http://www.codeproject.com/Tips/162691/Proper-Way-of-Releasing-COM-Objects-in-NET)
Why do I get “ShapeCount was not declared …” - Error if I try to do “Marshal.ReleaseComObject(ShapeCount)”? The same with “ShRange”. I think these are COM objects as well?!?
How do I notice when is the best time to release the COM object again? When I process/debug my code step by step with F11 will it be possible for me to determine the best (soonest) point of release? So far I have no “feeling” about when the COM object is not needed anymore and I can release it.
Any help and explanations very welcome.
Here is the code I am talking about:
Imports System.Runtime.InteropServices
Imports System.ComponentModel
Imports System.Windows.Forms
Imports AddinExpress.MSO
Imports PowerPoint = Microsoft.Office.Interop.PowerPoint
'Add-in Express Add-in Module
<GuidAttribute("D75C609E-7632-400F-8A6F-6A6E6E744E75"),
ProgIdAttribute("MyAddin8.AddinModule")> _
Public Class AddinModule
Inherits AddinExpress.MSO.ADXAddinModule
#Region " Add-in Express automatic code "
[…]
#End Region
Public Shared Shadows ReadOnly Property CurrentInstance() As AddinModule
Get
Return CType(AddinExpress.MSO.ADXAddinModule.CurrentInstance, AddinModule)
End Get
End Property
Public ReadOnly Property PowerPointApp() As PowerPoint._Application
Get
Return CType(HostApplication, PowerPoint._Application)
End Get
End Property
Private Sub AdxRibbonButton2_OnClick(sender As Object, control As IRibbonControl, pressed As Boolean) Handles AdxRibbonButton2.OnClick
MsgBox(GetInfoString2())
End Sub
Friend Function GetInfoString2() As String
Dim ActiveWindow As Object = Nothing
Try
ActiveWindow = Me.HostApplication.ActiveWindow()
Catch
End Try
Dim Result As String = "No document window found!"
If Not ActiveWindow Is Nothing Then
Select Case Me.HostType
Case ADXOfficeHostApp.ohaPowerPoint
Dim Selection As PowerPoint.Selection =
CType(ActiveWindow, PowerPoint.DocumentWindow).Selection
Dim WindowViewType As PowerPoint.PpViewType = PowerPoint.PpViewType.ppViewNormal
Dim SlideRange As PowerPoint.SlideRange = Selection.SlideRange
Dim SlideCountString = SlideRange.Count.ToString()
If WindowViewType = 9 And SlideCountString < 2 Then
Dim ShRange As PowerPoint.ShapeRange = Nothing
Try
ShRange = Selection.ShapeRange
Catch
End Try
If Not ShRange Is Nothing Then
Dim ShapeCount = ShRange.Count.ToString()
Result = "You have " + ShapeCount _
+ " shapes selected."
Else
Result = "You have 0 shapes selected."
End If
End If
'Marshal.ReleaseComObject(ShapeCount)
'Marshal.ReleaseComObject(ShRange)
'Marshal.ReleaseComObject(WindowViewType)
'Marshal.ReleaseComObject(SlideCountString)
Marshal.ReleaseComObject(SlideRange)
Marshal.ReleaseComObject(Selection)
Case Else
Result = AddinName + " doesn't support " + HostName
End Select
'Marshal.ReleaseComObject(Me.HostType)
'Marshal.ReleaseComObject(Result)
Marshal.ReleaseComObject(Me.HostApplication.ActiveWindow())
Marshal.ReleaseComObject(Me.HostApplication)
'Marshal.ReleaseComObject(Me)
End If
Return Result
End Function
End Class
The ReleaseComObject method of the Marshal class decrements the reference count of the specified Runtime Callable Wrapper (RCW) associated with the specified COM object, it doesn't release an object. It comes from the COM nature.
Typically you need to release every object returned from the Office (PowerPoint in your case) object model. Exceptions are objects passed to event handlers as parameters.
You may read more about that and find answers to your multiple questions in the When to release COM objects in Office add-ins developed in .NET article.
FinalReleaseComObject calls ReleaseComObject til it returns 0 which means release of COM object. Calling them in reverse order as in Excel objects(Application, Workbook, Worksheet) is the proper way to dispose of COM objects that are related.
Exception Condition
ArgumentException
o is not a valid COM object.
ArgumentNullException
o is null.

Visual Basic: dynamically create objects using a string as the name

Is there a way to dynamically create an object using a string as the class name?
I've been off VB for several years now, but to solve a problem in another language, I'm forced to develop a wrapper in this one. I have a factory method to dynamically create and return an object of a type based on input from elsewhere. The provided input is meant to be the class name from which to create an object from. Normal syntax means that the entire class has to be explicitly spelled out. To do it this way, there could literally be hundreds of if/then's or cases to handle all the available class/object choices within the referenced libs:
If c_name = "Button" then obj = new System.Windows.Forms.Button
If c_name = "Form" then obj = new System.Windows.Forms.Form
....
I'm hoping instead to reduce all this case handling to a single line: IE...
my_class_name = "whateverclass"
obj = new System.Windows.Forms.my_class_name()
In PHP, this is handled like so...
$my_class_name = "whateverclass";
$obj = new $my_class_name();
Edit: Looking at some of the answers, I think I'm in way over my head here. I did manage to get it working using this CreateInstance method variation of the Assembly class, even though I'm more interested in this variation giving more options, including supplying construct parameters...
my_type_name = "System.Windows.Forms.Button"
asmb_name = "System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
button1 = Reflection.Assembly.Load(asmb_name).CreateInstance(my_type_name)
In other words, it takes a method to do this, and not any inherent language syntax? This Activator variation also worked when the full assembly string and class path is used. I'm suspicious CreateInstance may not have the full ability to let me treat objects as if they were called normally, ie obj = new System.Windows.Forms.Button. This is why I can't use simply CreateObject. If there is no natural language feature allowing you to substitute a class name for a string, does anyone have any insight into what sort of limitations I can expect from using CreateInstance?
Also, is there even a difference between basic Activator.CreateInstance (after Unwrap) and Assembly.CreateInstance methods?
This will likely do what you want / tested working; switch the type comment at the top to see.
Imports System.Reflection
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' Dim fullyQualifiedClassName as String = "System.Windows.Forms.TextBox"
Dim fullyQualifiedClassName As String = "System.Windows.Forms.Button"
Dim o = fetchInstance(fullyQualifiedClassName)
' sometime later where you can narrow down the type or interface...
Dim b = CType(o, Control)
b.Text = "test"
b.Top = 10
b.Left = 10
Controls.Add(b)
End Sub
Private Function fetchInstance(ByVal fullyQualifiedClassName As String) As Object
Dim nspc As String = fullyQualifiedClassName.Substring(0, fullyQualifiedClassName.LastIndexOf("."c))
Dim o As Object = Nothing
Try
For Each ay In Assembly.GetExecutingAssembly().GetReferencedAssemblies()
If (ay.Name = nspc) Then
o = Assembly.Load(ay).CreateInstance(fullyQualifiedClassName)
Exit For
End If
Next
Catch
End Try
Return o
End Function
I'm pretty sure Activator is used for remoting. What you want to do is use reflection to get the constor and invoke it here's an example http://www.eggheadcafe.com/articles/20050717.asp
EDIT: I was misguided about Activator until jwsample corrected me.
I think the problem your having is that your assembly is the one that GetType is using to try and find Button. You need to call it from the right assembly.
This should do it
Dim asm As System.Reflection.Assembly = System.Reflection.Assembly.LoadWithPartialName("System.Windows.Forms")
Dim obj As Object = Activator.CreateInstance(asm.GetType("System.Windows.Forms.Button"))
Take a look at the Activator.CreateInstance(Type) method.
If your input is the name of a class you should be able do this:
Dim obj As Object = Activator.CreateInstance(GetType("Name_Of_Your_Class"))
You'll have to fiddle with the GetType call to make sure you give it enough information but for most cases just the name of the class should work.
Here is a really easy way I have found while rummaging through the internet:
dynamicControl = Activator.CreateInstance(Type.GetType("MYASSEMBLYNAME." + controlNameString))

Typecast exception from ShellBrowserWindow object to ShellFolderView object

Looking for help trying to figure out why this typecast is not working on my machine.
This code was provided as an answer to another question I had and it's not working for me. It works for the answer poster on their machine, but I'm get a an exception on the line trying to typecast from ShellBrowserWindow to ShellFolderView.
I am using Visual Studio Express 2013, running on Windows 7 Pro X64 Sp1. The target framework for the project is .Net Framework 4. I've added references to Microsoft Internet Controls and Microsoft Shell Controls and Automation and I've added the Imports statements for Shell32 and SHDocVw. DLL versions are as follows: shell32.dll = 6.1.7601.18517 and shdocvw.dll = 6.1.7601.1822 I'm not sure what I could be missing.
The code looks like this. (This code is in a form object)
Imports EdmLib
Imports Shell32
Imports SHDocVw
Public Class BlankForm
Private Sub BlankForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim bar As String() = GetExplorerSelectedFiles()
Exit Sub
'The rest of my program is below this line - I'm just trying to test this one function right now...
End Sub
'Uses the windows shell to get the files selected in explorer
Public Function GetExplorerSelectedFiles() As String()
Dim ExplorerFiles As New List(Of String)
Dim exShell As New Shell32.Shell
Dim SFV As Shell32.ShellFolderView
For Each window As SHDocVw.ShellBrowserWindow In DirectCast(exShell.Windows, SHDocVw.IShellWindows)
If (window.Document).GetType.Name <> "HTMLDocumentClass" Then
SFV = CType(window.Document, ShellFolderView) '<--This is where it fails!!
For Each fi As FolderItem In SFV.SelectedItems
ExplorerFiles.Add(fi.Path)
Next
End If
Next
Return ExplorerFiles.ToArray
End Function
End Class
The line SFV = CType(window.Document, ShellFolderView) results in the following message:
An unhandled exception of type 'System.InvalidCastException' occurred
in LaunchTemplateEPDM.exe
Additional information: Unable to cast COM object of type
'System.__ComObject' to interface type 'Shell32.ShellFolderView'. This
operation failed because the QueryInterface call on the COM component
for the interface with IID '{29EC8E6C-46D3-411F-BAAA-611A6C9CAC66}'
failed due to the following error: No such interface supported
(Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
I've taken a screenshot of a quickwatch on the window object. A quickwatch on the window.document object shows an error saying it's either undefined or inaccessible.
I ran the query Microsoft.VisualBasic.Information.TypeName(window.document) and it returns "IShellFolderViewDual3".
I fixed it.
Not sure why this happens on my system and not yours.
What I found was that GetType.Name always just returns "System.__ComObject", regardless of whether the object is of type ShellFolderView, HTMLDocumentClass or something else. So what was happening was no matter what the actual type of the object was, it was passing the <>"HTMLDocumentClass" test because it was always evaluating to "System.__ComObject". Then when we tried to run the CType function on an object that didn't implement the ShellFolderView interface, it would throw that exception.
I eventually stumbled upon this article which led me to experiment with the TypeName Function which seems to return the actual type, and so I ended up with the working code below:
Public Function GetExplorerSelectedFiles() As String()
Dim ExplorerFiles As New List(Of String)
Dim exShell As New Shell32.Shell
For Each window As SHDocVw.ShellBrowserWindow In DirectCast(exShell.Windows, SHDocVw.IShellWindows)
If TypeName(window.Document) Like "IShellFolderViewDual*" Then
For Each fi As FolderItem In DirectCast(window.Document, ShellFolderView).SelectedItems
ExplorerFiles.Add(fi.Path)
Next
End If
Next
Return ExplorerFiles.ToArray
End Function