InteropForms class method not visible in VB6 - vb6-migration

I have built a simple InteropForms class using the project template in VS 2010. It builds successfully and registers the library in the system. I can see it and reference it in VB6 but none of the public methods or properties I add to the class in VS2010 are visible.
What am I doing wrong?
Imports Microsoft.InteropFormTools
<InteropForm()> _
Public Class frmWebBrowserPreview
Private Sub frmWebBrowserPreview_KeyUp(sender As System.Object, e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyUp
If e.KeyCode = Windows.Forms.Keys.Escape Then Hide()
End Sub
Private Sub frmWebBrowserPreview_MouseUp(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseUp
Hide()
End Sub
Private Sub wbrPreview_DocumentCompleted(sender As Object, e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles wbrPreview.DocumentCompleted
wbrPreview.Visible = True
End Sub
''' <summary>
''' Navigate to the specified URL
''' </summary>
''' <param name="strURL">The URL string</param>
Public Function Navigate(strURL As String) As Boolean
wbrPreview.Navigate(strURL)
End Function
End Class

The template comes from the toolkit: VB6 InteropForm Library
It's not supported in VS2012 (yet...)...
Toolkit for VS2012
I figured it out. You have to add an InteropFormMethod attribute to the method in question and then rebuild the wrapper.
''' <summary>
''' Navigate to the specified URL
''' </summary>
''' <param name="strURL">The URL string</param>
<InteropFormMethod()> _
Public Function Navigate(strURL As String) As Boolean
wbrPreview.Navigate(strURL)
End Function

Related

Get Ranorex to use same user code for all tests

Is it possible to configure Ranorex to use the same user code to identify buttons in an application (instead of renaming them for each test) and also to have a set of user defined code for any new tests. I.e. a common user code base for all tests?
Yes it is possible and very handy. What you do is have a code module library that inherits from ITestModule, e.g.
public class GenericActionsLibrary : ITestModule
and then in the user code section of the recording module have the class inherit from your library.
public class TestLoginScreen : GenericActionsLibrary
In the recording module, each time you add a user code action, the drop-down list is filled with methods from both the user code module and the GenericActionsLibrary.
Your GenericActionsLibrary will need its own static reference to the repository.
Here is how I did it. I'm using Visual Basic (VB) and not C# CS in Ranorex.
In Ranorex
"Add Code Module" MainLibrary
"Add Code Module" StartBrowser
Comment out three code blocks in the code module MainLibrary:
The first is
'Implements ITestModule
The second is
''' <summary>
''' Constructs a new instance.
''' </summary>
' Public Sub New()
' ' Do not delete - a parameterless constructor is required!
' End Sub
The third location is
''' <summary>
''' Performs the playback of actions in this module.
''' </summary>
''' <remarks>You should not call this method directly, instead pass the module
''' instance to the <see cref="TestModuleRunner.Run(Of ITestModule)"/> method
''' that will in turn invoke this method.</remarks>
' Sub Run() Implements ITestModule.Run
' Mouse.DefaultMoveTime = 300
' Keyboard.DefaultKeyPressTime = 100
' Delay.SpeedFactor = 1.0
' End Sub
Add Sub(s) for the action(s) you want to call from the other code module(s)
Public Sub OpenBrowser
Host.Local.OpenBrowser("http://www.ranorex.com", "IE", "", False, False)
End Sub
In the code module, you are calling the method that's in MainLibrary. Add the Inherits statement before the Implements statement, then call the method from the MainLibrary in the ITestModule.Run code block:
Public Class StartBrowser
Inherits MainLibrary
Implements ITestModule
''' <summary>
''' Constructs a new instance.
''' </summary>
Public Sub New()
' Do not delete - a parameterless constructor is required!
End Sub
''' <summary>
''' Performs the playback of actions in this module.
''' </summary>
''' <remarks>You should not call this method directly, instead pass the module
''' instance to the <see cref="TestModuleRunner.Run(Of ITestModule)"/> method
''' that will in turn invoke this method.</remarks>
Sub StartBrowser_Run() Implements ITestModule.Run
Mouse.DefaultMoveTime = 300
Keyboard.DefaultKeyPressTime = 100
Delay.SpeedFactor = 1.0
'Call the public method from MainLibrary Class.
OpenBrowser()
End Sub
End Class
On Ranorex's Website, it shows about creating library's that comes in handy when reusing for different projects.

IProgressCallBack between VB6 EXE and VB.NET DLL

I am currently upgrading our software from VB6 to VB.NET and doing so one DLL at a time. The EXE will be last since it has a lot of third party UI controls.
One issue that I found is that the VB6 version of the DLL housed an IProgressCallBack class that was acting like an interface class (which does not officially exist in VB6) and allowed the EXE to get progress reports from the DLL and display it on the screen for the user.
When this DLL is migrated the IProgressCallBack class can be set as an Interface class, but then it cannot be 'Set' to the instance of the form using it. But if I create it as just a normal class, it still will not let me 'Set' it to the instance of the form using it since they are two different object types.
I need to know how do I either make the IProgressCallBack class work between VB6 and VB.NET or what is an alternate solution to keep the VB6 UI informed of the progress of the .NET DLL?
Here is an example of the VB6 version of both and how they work:
VB6 DLL: IProgressCallBack
Option Explicit
Public Function NotifyProgress(ByVal Progress As Single, ByRef isCancel As Boolean) As Boolean
End Function
VB6 DLL: MainFunctions Class
Public ProgressNotify As IProgressCallBack
Public Sub DoWork()
Dim l As Long
For l = 1 to 100
Sleep 10 'sleep for 1/100 of a second
ProgressNotify.NotifyProgress 1, False
Next
End Sub
VB6 EXE
Implements IProgressCallBack
Dim m_oMainFunc As MainFunctions
Private Sub cmdStart_Click()
Set m_oMainFunc = New MainFunctions
Set m_oMainFunc.ProgressNotify = Me
m_oMainFunc.DoWork
Set m_oMainFunc = Nothing
End Sub
Public Function IProgressCallBack_NotifyProgress(ByVal Progress As Single, isCancel As Boolean) As Boolean
lblStatus.Caption = CStr(Round(Progress)) & "%"
pbStatus.Value = Round(Progress)
Me.Refresh
End Function
Thanks,
Chris
I have not exactly found the answer to the question I posted above, but I have found a nice workaround.
Essentially I pass in the form as an object to the class pretending to be an interface and directly call the interface method that resides on the form to update the screen.
Here is the code sample of how I do this:
VB.NET DLL: IProgressCallBack Class
Dim m_oForm As Object
Public Sub New(ByRef oForm As Object)
m_oForm = oForm
End Sub
Public Function NotifyProgress(ByVal Progress As Single, ByRef isCancel As Boolean) As Boolean
m_oForm.IProgressCallBack_NotifyProgress(Progress, isCancel)
End Function
VB.NET DLL: MainFunctions Class
Public ProgressNotify As IProgressCallBack
Public Sub New()
'Need Public Sub New() with no parameters for all Com Classes
MyBase.New()
End Sub
Public Sub Initialize(ByRef oForm As Object)
ProgressNotify = New IProgressCallBack(oForm)
End Sub
Public Sub DoWork()
For l As Long = 1 to 100
Threading.Thread.Sleep(10) 'sleep for 1/100 of a second
ProgressNotify.NotifyProgress(l,False)
Next
End Sub
VB6 EXE
Dim m_oMainFunc As TestDLL_Net.MainFunctions
Private cmdStart_Click()
Set m_oMainFunc = New TestDLL_Net.MainFunctions
m_oMainFunc.Initialize Me
m_oMainFunc.DoWork
Set m_oMainFunc = Nothing
End Sub
Public Function IProgressCallBack_NotifyProgress(ByVal Progress As Single, isCancel As Boolean) As Boolean
DoEvents
lblStatus.Caption = CStr(Round(Progress)) & "%"
Me.Refresh
pbStatus.Value = Round(Progress)
End Function
This provides the same result as the VB6 DLL to VB6 EXE example posted above, and the changes in the EXE are minimal to make it work.
Thanks,
Chris

MVC3 & Unity.Mvc

Strange issue I am having with my MVC3 project. I have followed a simple example of IOC using Unity.Mvc.
It works fine if my object and it's interface are in the web project itself (in this case IMessageService and MessageService). They clearly are working, no problems there.
But when I try to register my business service objects from an external assembly, they never get set to anything (always null). There are no errors in App-Start when they get registered, etc.
Anyone have any ideas? Desperate here....
UPDATE:
#Region "Imports"
Imports MyProject.Services
Imports MyProject.Services.Interfaces
Imports MyProject.Web.Mvc.Bootstrap
Imports MyProject.Web.Mvc.Services
Imports Microsoft.Practices.Unity
Imports Unity.Mvc3
#End Region
#Region "Assembly Meta"
' This tells the app to run the "Start" method prior to running the App_Start method in Global.asax
<Assembly: WebActivator.PreApplicationStartMethod(GetType(UnityDI), "Start")>
#End Region
Namespace MyProject.Web.Mvc.Bootstrap
''' <summary>
''' Class to setup dependency injection and register types/services.
''' </summary>
''' <remarks></remarks>
Public NotInheritable Class UnityDI
''' <summary>
''' Method to register the Unity dependency injection component.
''' </summary>
''' <remarks>
''' This line of code below could alternatively be placed in Global.asax App_Start(), doing
''' so in this manner ensures that this gets run "PreStart".
''' </remarks>
Public Shared Sub Start()
' Set DI resolver
' NOTE: ECD - The UnityDependencyResolver below is part of the Unity.Mvc3 assembly
DependencyResolver.SetResolver(New UnityDependencyResolver(RegisterIocServices()))
End Sub
''' <summary>
''' Registers the IOC types/services.
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Private Shared Function RegisterIocServices() As IUnityContainer
' Create Unity dependency container
Dim dependencyContainer As IUnityContainer = New UnityContainer
' Register the relevant types/services for the container here through classes or configuration
With dependencyContainer
.RegisterType(Of IFormsAuthenticationService, FormsAuthenticationService)()
.RegisterType(Of IContactService, ContactService)()
.RegisterType(Of IProductItemService, ProductItemService)()
.RegisterType(Of ICustomerProductItemService, CustomerProductItemService)()
.RegisterType(Of ISystemTableItemService, SystemTableItemService)()
.RegisterType(Of ICatalogCodeService, CatalogCodeService)()
.RegisterType(Of IOrderService, OrderService)()
' TEST: This one is in the MVC project and works, the above are an external library
.RegisterType(Of IMessageService, MessageService)()
End With
Return dependencyContainer
End Function
End Class
End Namespace
Above code is my registration process. I have also tried putting this directly in the global.asax and have the same behavior.
UPDATE 2
Figured out my issue.
In my controller, I have the following properties:
<Dependency()>
Private Property CatalogCodeService As ICatalogCodeService
<Dependency()>
Private Property ContactService As IContactService
<Dependency()>
Private Property CustomerProductItemService As ICustomerProductItemService
But accessing the services in an action method always threw an error that there was no instance of any of these objects. So I assumed it was the original code I posted or something in there in the way I was registering.
Turns out it was not my registration code, which is perfectly fine.
The issue?
The properties have to be "Public"!! Private, Protected, Friend all do not work for IOC. Once I changed those properties to "Public", everything started working perfectly fine.
I have not verified that this is the same in C#, so if anyone can add their two cents, please by all means do so.
Go figure...
UPDATE II:
The above implementation was using public properties, which follows the "Property Injection" pattern of dependency injection.
I have since switched to the more appropriate "Constructor Injection" method.
With this change, that property for my services that my controller(s) use can be private AND read only.
"Dependency Injection in .NET" by Mark Seemann, great book. I highly suggest it for anyone implementing dependency injection or those just wanting to learn more about it.

Using ASP.NET MVC, Linq To SQL, and StructureMap causing DataContext to cache data

I'll start by telling my project setup:
ASP.NET MVC 1.0
StructureMap 2.6.1
VB
I've created a bootstrapper class shown here:
Imports StructureMap
Imports DCS.Data
Imports DCS.Services
Public Class BootStrapper
Public Shared Sub ConfigureStructureMap()
ObjectFactory.Initialize(AddressOf StructureMapRegistry)
End Sub
Private Shared Sub StructureMapRegistry(ByVal x As IInitializationExpression)
x.AddRegistry(New MainRegistry())
x.AddRegistry(New DataRegistry())
x.AddRegistry(New ServiceRegistry())
x.Scan(AddressOf StructureMapScanner)
End Sub
Private Shared Sub StructureMapScanner(ByVal scanner As StructureMap.Graph.IAssemblyScanner)
scanner.Assembly("DCS")
scanner.Assembly("DCS.Data")
scanner.Assembly("DCS.Services")
scanner.WithDefaultConventions()
End Sub
End Class
I've created a controller factory shown here:
Imports System.Web.Mvc
Imports StructureMap
Public Class StructureMapControllerFactory
Inherits DefaultControllerFactory
Protected Overrides Function GetControllerInstance(ByVal controllerType As System.Type) As System.Web.Mvc.IController
Return ObjectFactory.GetInstance(controllerType)
End Function
End Class
I've modified the Global.asax.vb as shown here:
...
Sub Application_Start()
RegisterRoutes(RouteTable.Routes)
'StructureMap
BootStrapper.ConfigureStructureMap()
ControllerBuilder.Current.SetControllerFactory(New StructureMapControllerFactory())
End Sub
...
I've added a Structure Map registry file to each of my three projects: DCS, DCS.Data, and DCS.Services. Here is the DCS.Data registry:
Imports StructureMap.Configuration.DSL
Public Class DataRegistry
Inherits Registry
Public Sub New()
'Data Connections.
[For](Of DCSDataContext)() _
.HybridHttpOrThreadLocalScoped _
.Use(New DCSDataContext())
'Repositories.
[For](Of IShiftRepository)() _
.Use(Of ShiftRepository)()
[For](Of IMachineRepository)() _
.Use(Of MachineRepository)()
[For](Of IShiftSummaryRepository)() _
.Use(Of ShiftSummaryRepository)()
[For](Of IOperatorRepository)() _
.Use(Of OperatorRepository)()
[For](Of IShiftSummaryJobRepository)() _
.Use(Of ShiftSummaryJobRepository)()
End Sub
End Class
Everything works great as far as loading the dependecies, but I'm having problems with the DCSDataContext class that was genereated by Linq2SQL Classes.
I have a form that posts to a details page (/Summary/Details), which loads in some data from SQL. I then have a button that opens a dialog box in JQuery, which populates the dialog from a request to (/Operator/Modify). On the dialog box, the form has a combo box and an OK button that lets the user change the operator's name. Upon clicking OK, the form is posted to (/Operator/Modify) and sent through the service and repository layers of my program and updates the record in the database. Then, the RedirectToAction is called to send the user back to the details page (/Summary/Details) where there is a call to pull the data from SQL again, updating the details view.
Everything works great, except the details view does not show the new operator that was selected. I can step through the code and see the DCSDataContext class being accessed to update the operator (which does actually change the database record), but when the DCSDataContext is accessed to reload the details objects, it pulls in the old value. I'm guessing that StructureMap is causing not only the DCSDataContext class but also the data to be cached?
I have also tried adding the following to the Global.asax, but it just ends up crashing the program telling me the DCSDataContext has been disposed...
Private Sub MvcApplication_EndRequest(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.EndRequest
StructureMap.ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects()
End Sub
Can someone please help?
Got this response back from Jeremy Miller on the StructureMap google group:
Easy money, you're creating an instance of your DataContext object -yourself- in the registration, which de facto makes that a singleton throughout the StructureMap ecosystem.
This code:
'Data Connections.
[For](Of DCSDataContext)() _
.HybridHttpOrThreadLocalScoped _
.Use(New DCSDataContext())
Needs to define the DataContext using -deferred- execution rather than using the pre-built "New DCSDataContext()"
If you were in C# (because I don't know the VB syntax), you would do:
For<DCSDataContext>().HybridHttpOrThreadLocalScoped().Use(() => new DCSDataContext());
I ran this through a C# to VB converter and it gave me this:
[For](Of DCSDataContext)() _
.HybridHttpOrThreadLocalScoped _
.Use(Function() New DCSDataContext())
Which works great!

Problem Implementing StructureMap in VB.Net Conversion of SharpArchitecture

I work in a VB.Net environment and have recently been tasked with creating an MVC environment to use as a base to work from. I decided to convert the latest SharpArchitecture release (Q3 2009) into VB, which on the whole has gone fine after a bit of hair pulling. I came across a problem with Castle Windsor where my custom repository interface (lives in the core/domain project) that was reference in the constructor of my test controller was not getting injected with the concrete implementation (from the data project). I hit a brick wall with this so basically decided to switch out Castle Windsor for StructureMap.
I think I have implemented this ok as everything compiles and runs and my controller ran ok when referencing a custom repository interface. It appears now that I have/or cannot now setup my generic interfaces up properly (I hope this makes sense so far as I am new to all this). When I use IRepository(Of T) (wanting it to be injected with a concrete implementation of Repository(Of Type)) in the controller constructor I am getting the following runtime error:
"StructureMap Exception Code: 202 No Default Instance defined for PluginFamily SharpArch.Core.PersistenceSupport.IRepository`1[[DebtRemedy.Core.Page, DebtRemedy.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], SharpArch.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b5f559ae0ac4e006"
Here are my code excerpts that I am using (my project is called DebtRemedy).
My structuremap registry class
Public Class DefaultRegistry
Inherits Registry
Public Sub New()
''//Generic Repositories
AddGenericRepositories()
''//Custom Repositories
AddCustomRepositories()
''//Application Services
AddApplicationServices()
''//Validator
[For](GetType(IValidator)).Use(GetType(Validator))
End Sub
Private Sub AddGenericRepositories()
''//ForRequestedType(GetType(IRepository(Of ))).TheDefaultIsConcreteType(GetType(Repository(Of )))
[For](GetType(IEntityDuplicateChecker)).Use(GetType(EntityDuplicateChecker))
[For](GetType(IRepository(Of ))).Use(GetType(Repository(Of )))
[For](GetType(INHibernateRepository(Of ))).Use(GetType(NHibernateRepository(Of )))
[For](GetType(IRepositoryWithTypedId(Of ,))).Use(GetType(RepositoryWithTypedId(Of ,)))
[For](GetType(INHibernateRepositoryWithTypedId(Of ,))).Use(GetType(NHibernateRepositoryWithTypedId(Of ,)))
End Sub
Private Sub AddCustomRepositories()
Scan(AddressOf SetupCustomRepositories)
End Sub
Private Shared Sub SetupCustomRepositories(ByVal y As IAssemblyScanner)
y.Assembly("DebtRemedy.Core")
y.Assembly("DebtRemedy.Data")
y.WithDefaultConventions()
End Sub
Private Sub AddApplicationServices()
Scan(AddressOf SetupApplicationServices)
End Sub
Private Shared Sub SetupApplicationServices(ByVal y As IAssemblyScanner)
y.Assembly("DebtRemedy.ApplicationServices")
y.With(New FirstInterfaceConvention)
End Sub
End Class
Public Class FirstInterfaceConvention
Implements ITypeScanner
Public Sub Process(ByVal type As Type, ByVal graph As PluginGraph) Implements ITypeScanner.Process
If Not IsConcrete(type) Then
Exit Sub
End If
''//only works on concrete types
Dim firstinterface = type.GetInterfaces().FirstOrDefault()
''//grabs first interface
If firstinterface IsNot Nothing Then
graph.AddType(firstinterface, type)
Else
''//registers type
''//adds concrete types with no interfaces
graph.AddType(type)
End If
End Sub
End Class
I have tried both ForRequestedType (which I think is now deprecated) and For.
IRepository(Of T) lives in SharpArch.Core.PersistenceSupport.
Repository(Of T) lives in SharpArch.Data.NHibernate.
My servicelocator class
Public Class StructureMapServiceLocator
Inherits ServiceLocatorImplBase
Private container As IContainer
Public Sub New(ByVal container As IContainer)
Me.container = container
End Sub
Protected Overloads Overrides Function DoGetInstance(ByVal serviceType As Type, ByVal key As String) As Object
Return If(String.IsNullOrEmpty(key), container.GetInstance(serviceType), container.GetInstance(serviceType, key))
End Function
Protected Overloads Overrides Function DoGetAllInstances(ByVal serviceType As Type) As IEnumerable(Of Object)
Dim objList As New List(Of Object)
For Each obj As Object In container.GetAllInstances(serviceType)
objList.Add(obj)
Next
Return objList
End Function
End Class
My controllerfactory class
Public Class ServiceLocatorControllerFactory
Inherits DefaultControllerFactory
Protected Overloads Overrides Function GetControllerInstance(ByVal requestContext As RequestContext, ByVal controllerType As Type) As IController
If controllerType Is Nothing Then
Return Nothing
End If
Try
Return TryCast(ObjectFactory.GetInstance(controllerType), Controller)
Catch generatedExceptionName As StructureMapException
System.Diagnostics.Debug.WriteLine(ObjectFactory.WhatDoIHave())
Throw
End Try
End Function
End Class
The initialise stuff in my global.asax
Dim container As IContainer = New Container(New DefaultRegistry)
ControllerBuilder.Current.SetControllerFactory(New ServiceLocatorControllerFactory())
ServiceLocator.SetLocatorProvider(Function() New StructureMapServiceLocator(container))
My test controller
Public Class DataCaptureController
Inherits BaseController
Private ReadOnly clientRepository As IClientRepository()
Private ReadOnly pageRepository As IRepository(Of Page)
Public Sub New(ByVal clientRepository As IClientRepository(), ByVal pageRepository As IRepository(Of Page))
Check.Require(clientRepository IsNot Nothing, "clientRepository may not be null")
Check.Require(pageRepository IsNot Nothing, "pageRepository may not be null")
Me.clientRepository = clientRepository
Me.pageRepository = pageRepository
End Sub
Function Index() As ActionResult
Return View()
End Function
The above works fine when I take out everything to do with the pageRepository which is IRepository(Of T).
Any help with this would be greatly appreciated.
I had a similar issue yesterday with instantiating IRepository(Of MyEntity).
I had to state y.ConnectImplementationsToTypesClosing(GetType(IRepository(Of ))) in my Scan delegate to make StructureMap map generic types to their implementation.
Like this:
Private Shared Sub SetupCustomRepositories(ByVal y As IAssemblyScanner)
y.Assembly("DebtRemedy.Core")
y.Assembly("DebtRemedy.Data")
y.WithDefaultConventions()
y.ConnectImplementationsToTypesClosing(GetType(Of ));
End Sub
Make sure you are only creating one container.
I also converted a C# project from Castle Windsor to StructureMap. The original CW-based project instantiated a Container in Application_Start() (MVC2 project) and passed it around for configuration. I kept the same approach without thinking, kinda when you translate from Spanish to English litterally, and it's just as bad. :)
What happened is that I ended up creating a second SM container. StructureMap's container is static, and so there's always one "in the background". If you new up a container, you actually create a second, independent container. if you aren't careful, you end up sometimes using one, sometimes the other, and get a plague of " No Default Instance" errors at various points when you know it's defined..
The way I came across it is that I ended up littering my code with WhatDoIHave() calls, which was fortunate because I noted that sometimes I saw a configured container (the second) and sometimes I saw the static one (the first), which had not been configured. Different GUID names was the giveaway.
Check if the same is happening in your VB code.
Not that familiar with this, but it looks like it may not be registered with the container or because the resolver is greedy it might choose a constructor that does not have registered items. The following URL looks very similar to the same problem take a look...
http://learningbyfailing.com/2010/02/structuremap-exception-no-default-instance-defined-for-pluginfamily-iformsauthentication/

Resources