Make an ActiveX control work without a form? - c#

We are using Topaz Signature pads. They provide their APIs in the from of an ActiveX control which is to be put on a Winform control. Well, the way our project will work we do not want to have a form(at least not visible). We just want for the signature ActiveX control to get an image in the background.
static AxSigPlus sig = new AxSIGPLUSLib.AxSigPlus();
public static void Begin()
{
((System.ComponentModel.ISupportInitialize)(sig)).BeginInit();
sig.Name = "sig";
sig.Location = new System.Drawing.Point(0, 0);
sig.Size = new System.Drawing.Size(0, 0);
sig.Enabled = true;
sig.TabletState = 1; //error here
sig.SigCompressionMode = 0;
}
Ok so I get an error at the marked line. The exception is
Exception of type 'System.Windows.Forms.AxHost+InvalidActiveXStateException' was thrown.
What do I do to solve this problem? Would it just be easier to create a new hidden form and put the control on it so it's invisible?

Yes, that can't work this way. The AxHost wrapper requires its Handle to be created before it is usable. Which requires it to be a child control on a form whose Show() method is called.
You normally get two interop wrappers from an ActiveX control, an AxBlah.dll which contains the AxHost wrapper and a Blah.dll which wraps the COM interfaces. You'd only need to reference Blah.dll. Whether that will work is an open question, many ActiveX controls require a window handle to deal with thread synchronization.
If that doesn't work out, you'll need a host form. You can keep it invisible by pasting this code into the form class:
protected override void SetVisibleCore(bool value) {
if (!IsHandleCreated) CreateHandle();
value = false;
base.SetVisibleCore(value);
}
You have to call Application.Run() to pump the message loop.

You might be able to just use the COM object directly (it really depends how they implemented the control). Normally when you import the COM object into your references it will create a wrapper AxHost but it should also import the basic class objects. Find which that is then just create it as any normal class, do not use the AxHost version. If there doesn't seem to be any base class objects you can create the object using the Activator and either the CLSID or ProgID of the control. Something like:
object o = Activator.CreateInstance(Type.GetTypeFromProgID("prog.id"))

This is what I did (basically added invisible Ax control and invoked its methods thereafter):
using (AxRUNNERXLib.AxRunnerX crm = new AxRUNNERXLib.AxRunnerX ()) {
Controls.Add (crm);
crm.Visible = false;
crm.CustomerPrefix = m_SelCall.CustomerPrefix;
crm.LoadDefaultDescription ();
crm.SearchByID (m_SelCall.CustomerID);
crm.OperatorID = Form1.operatorID.ToString ();
crm.ShowHistory ();
Controls.Remove (crm);
}

Actually it ended up that Topaz provided an ActiveX control and a .Net wrapper around it. I switched to the .Net wrapper and it doesn't require being placed on a form or anything. I will leave the question up though because had it not been for that wrapper I would actually be dealing with it.

Related

Native call and The application called an interface that was marshalled for a different thread

I'm writing Windows / Windows Phone 8.1 application that has needs to invoke a native C++/CX class in the background.
At the moment I have a code like this (inside an async method(
var list = await Task.Run(()=> {
var parser = new NativeParser();
return parser.process("someData"); //here I get the exception
});
on the call of .process() I get an exception saying WinRT information: The application called an interface that was marshalled for a different thread.
The problem is that I'd like to what exactly is the problem - isn't the native class also created on background (inside Task.Run?)
Edit:
I tried to do the same inside a ThreadPool call - and the same thing happens. Is there some weird C# to C++/CX interop thing that I'm not aware of?
IAsyncAction asyncAction = ThreadPool.RunAsync((workItem) =>
{
var parser = new NativeParser();
return parser.process("someData");
});
asyncAction.Completed = new AsyncActionCompletedHandler(
(IAsyncAction asyncInfo, AsyncStatus asyncStatus) =>
{
Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
// update UI
}
});
Found the culprit - while stepping through the code I discovered that it crashed on the line where my C++/CX code was creating a ref new Foo();, where Foo was derived from Windows::UI::Xaml::DependencyObject (seemed like a nice base class at the moment as the only possible public unsealed types are those found under the Windows::UI::Xaml namespace, and users are not able to create their own public unsealed types).
Apparently you can only create and access XAML elements that inherit from DependencyObject from the XAML UI thread of an app, so I have to refactor the code to avoid inheriting from that one.

Is there a publicly accessible event to mark a ModalDialog close?

I recently made a custom ribbon in Sitecore. The two buttons in it fire off a command which activate a Xaml application using SheerResponse.ShowModalDialog. These applications effect the state of a database being read by another component on the ribbon.
I either need to be able to fire a custom event or function from the Xaml application to make the other ribbon component, or I need to be able to make the component on the ribbon aware that it needs to re-render when the ModalDialogs close. I don't see any obvious events which would do this, and I've gone about as far as I can when looking through the raw code with DotPeek and I haven't seen anything which even looks promising.
Apparently, the answer was there the whole time and I had missed it.
SheerResponse has a five parameter version of ShowModalDialog which accepts a boolean as a final parameter. This means I can couple it with ClientPage.Start:
Context.ClientPage.Start(this, "Run", kv);
}
private void Run(ClientPipelineArgs args)
{
var id = args.Parameters["id"];
if(!args.IsPostBack)
{
string controlUrl = string.Format("{0}&id={1}", UIUtil.GetUri("control:AltDelete"), id);
SheerResponse.ShowModalDialog(controlUrl,"","","",true);
args.WaitForPostBack();
}
else
{
Logger.LogDebug("post back");
}
Logger.LogDebug("out of if");
}

Trying to close a form after the next one is shown in C# cf

I've been studying Android lately and I tried to port one of its functions to C# compact framework.
What I did is create an Abstract class that I call Activity.
This class looks like this
internal abstract class Activity
{
protected Form myForm;
private static Activity myCurrentActivity = null;
private static Activity myNextActivity = null;
internal static void LoadNext(Activity nextActivity)
{
myNextActivity = nextActivity;
if (myNextActivity != null)
{
myNextActivity.Show();
if (myCurrentActivity != null)
{
myCurrentActivity.Close();
myCurrentActivity = null;
}
myCurrentActivity = myNextActivity;
myNextActivity = null;
}
}
internal void Show()
{
//PROBLEM IS HERE
Application.Run(myForm);
//myForm.Show();
//myForm.ShowDialog();
//
}
internal void Close()
{
myForm.Close();
}
internal void GenerateForm()
{
///Code that uses the Layout class to create a form, and then stores it in myForm
//then attaches click handlers on all the clickable controls in the form
//it is besides the point in this problem
}
protected abstract void Click(Control control);
//this receives all the click events from all the controls in the form
//it is besides the point in this problem
}
The problem I have is with running the part of the Show() command
Basically all my classes implement the above class, load an xml file and display it.
When I want to transition to a new class/form (for example going from ACMain to ACLogIn)
I use this code
Activity.LoadNext(new ACLogIn);
Which is supposed to load the next form, show it , and unload the current form
I have tried these solutions (in the Show() method) and here is the problem with each one
using myForm.ShowDialog()
This works, but blocks execution, which means that the old form does not close, and the more I move between the forms the more the process stack increases
using myForm.Show()
This works, closes the old form after the old one is shown, but immediately after that closes the program and terminates it
using Application.Run(myForm)
This works only on the first form loaded, when I move to the next form, it shows it then throws an exception saying "Value does not fall within the expected range"
Can someone help me fix this or find an alternative?
If you're really after creating your own framework for this navigation, you need to re-work you thinking. The Form instance passed into Application.Run must never close - when it does, Application.Run finishes execution and (typically) your static void Main entry point exits and the app terminates.
What I would propose is that you change your Activity to either being a UserControl:
public abstract class Activity : UserControl
{
....
}
or Composing one
public abstract class Activity
{
private UserControl m_control;
....
}
Then instead of closing and showing Forms, parent all of the Activities inside the main Form as a container.
As fair warning, this is going to get complex when you start wanting to show things in a Tab motif instead of a Stack, or having split views. Frameworks seem simple to create, but they're not so I'd at least consider using something already done unless you have compelling reasons to want to roll your own.
Application.Run is generally used with the overload that takes a Form parameter. This would be the "main" form that would be responsible for starting/showing other forms. This "main" form could be "hidden". But, I think that's a little awkward.
Alternatively, you don't need a main form, you can use Application.Run() to start a message pump to process Windows messages; but, then the thread is busy processing messages and cannot show dialogs (they must be shown in the thread that is running Application.Run). You can get around this by creating one or more form objects before calling Application.Run and these form objects could create a Timer object that would call Form.Show() or Form.ShowDialog() on the Timer.Tick event handler so that for form is shown after the call to Run. I think this is a little awkward as well.
Both of these solutions kind of circumvent the way you're expected to use Windows and WinForms; so, I think you need to think about re-designing this application to work with the way that Windows and .NET works.

How to launch a Windows Form from within a .dll launched at runtime

I have researched this a fair bit and cannot establish the correct approach. My problem is as follows: I have a winForms applications and from within it I wish to launch a time intesive .dll. I can do this using System.Reflection no problem like this
// Execute the method from the requested .dll using reflection (System.Reflection).
//[System.Runtime.InteropServices.DllImport(strDllPath)]
DLL = Assembly.LoadFrom(strDllPath);
classType = DLL.GetType(String.Format("{0}.{0}", ListUfCmdParams[1]));
classInst = Activator.CreateInstance(classType);
XmlExpInfo = classType.GetMethod(DllParams[0]);
XmlExpInfo.Invoke(classInst, paramObj);
// Return something.
return String.Format("Method '{0}' from '{1}{2}' successfully executed!",
ListUfCmdParams[2], ListUfCmdParams[1], strDotDll);
this works great but the process being called is so time intensive I want to display to the user what is happening. To do this I have included in the .dll file a WinForm which has a progressBar and some other attributes. When I do this I get an exception. This occurs when "Activator.CreateInstance()" attempts to do its work: MissingMethodException "Cannot create an abstract class". I have come across this error before when I using partial classes and I had to remove the "partial" keyword from my classes to enable the .dll to execute correctly (which I just about got away with!). I cannot remove this "partial" keyword from the above winForms class so, the question is "How do I call a winForm from within my .dll (if indeed it is possible)?" so that the .dll can show its progress as it executes from the calling application?
Thanks for your time,
Nick
Ps. I have read the following threads and they are somewhat ambiguous:
A DLL with WinForms that can be launched from A main app
et al.
You should not make a callee (the dll) aware of it's caller (the form). Instead you could enrich the class in your dll that performs the time intensive method with a ProgressUpdated event:
public event ProgressUpdatedHandler ProgressUpdated;
public delegate void ProgressUpdatedHandler(object sender, int stepsCompleted, int stepsTotal)
This way the form could simply assign a handler for that event, and the dll could raise the event whenever it can indicate what the progress is.
I have just seen this question again and thought I would update as to how I eventually did this.
In the end I found the following to be the most effective way of performing the above for what I wanted. First you launch a WinForm which holds your progress information. Second youu envoke your "worker" method from within the "Shown" event.
The code for the first part i.e. to call the WinForm using Reflection is provided below:
// Execute the method from the requested .dll using reflection (System.Reflection).
Assembly DLL = Assembly.LoadFrom(strDllPath);
Type classType = DLL.GetType(String.Format("{0}.{0}", strNsCn));
object classInst = Activator.CreateInstance(classType, paramObj);
Form dllWinForm = (Form)classInst;
dllWinForm.ShowDialog();
I hope this helps someone else.

ActiveX control without a form

We are required to use a 3rd party ActiveX control.
The only issue is, the layer in our software is a business layer and has no access to a window or form. It also runs on separate threads (and should work from any thread) that are not STA.
Rather than breaking our separation of UI from business logic, we used this workaround to make it work:
Thread thread = new Thread((ThreadStart)
delegate
{
_myActiveX = new MyActiveXType();
_myActiveX.CreateControl();
//more initialize work
Application.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
Then anytime we need to reference the control, we call _myActiveX.BeginInvoke() or Invoke().
On disposing of this class (exiting our app), we dispose the control and abort the thread.
My question is, are there any problems with this? Is there a better way to handle this?
Is there a better built in way to work with an ActiveX control from within an unknown multi-threaded environment? We are trying to write our class in a way that wraps the control but will work from any thread.
UPDATE: As an answer suggested, we really would rather use the standard COM object and not use a control at all. Our issue with that was we would get the error "(Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED)" upon the first method or property we call on the COM object. This is a pretty generic error that we don't get when using the ActiveX, any ideas?
UPDATE: Our ocx is "CX25.ocx", using tlbimp.exe we get CX25Lib.dll. Using aximp.exe, we get AxCX25Lib.dll and CX25Lib.dll. CX25Lib.dll does not work in either case. AxCX25Lib.dll works.
I'm assuming this is the proper way to go about this.
We've been using my code above in test environments for the past few weeks with no issues.
If anyone has to use an ActiveX without a form, I assume this is one way to do it.
Just make sure to call _yourActiveXControl.CreateControl() directly after your ActiveX object's constructor. This simplified many issues we had originally.
If you are calling the ActiveX control from a business layer, that means that it must be able to be used without a UI, e.g. just by calling its public methods. Why not just create an interop RCW for the ActiveX control class and call its methods directly?
My solution is to create a hidden winform that host the activex control
I know this is an old post, but I would recommend using the TPL in our modern era.
It's better to use the task parallel library instead of the old threading API because of the features around exception handling, cancellation, continuation, and returning results.
Here's an example:
using (var sta = new StaTaskScheduler(1))
{
var taskResult = await Task.Factory.StartNew(() =>
{
var results = new List<ResultType>();
using (var ax = new MyActiveXType())
{
// important to call this just after constructing ActiveX type
ax.CreateControl();
ax.SomeIterativeEvent += (s, e) => results.Add(e.SomeThing);
// if applicable, you can tear down the message pump
ax.SomeFinalEvent += (s, e) => Application.ExitThread();
//more initialize work
// start message pump
Application.Run();
return results;
}
}, CancellationToken.None, TaskCreationOptions.None, sta);
return taskResult;
}
Some points:
StaTaskScheduler is a type found in the ParallelExtensionsExtras nuget package. You'll need this to schedule tasks to execute in a Single Threaded Apartment.
I'm passing 1 to the constructor of StaTaskScheduler so that it only ever creates a single thread for me.
Application.ExitThread() is called to stop the message pump, which in turn allows execution to pass by Application.Run() so that some result can be returned to the caller.
The CreateControl() method is from AxHost and requires System.Windows.Forms as a dependency.
If you want to use ActiveX without UI you can directly create COM object of ocx using native call.
[DllImport("ole32.dll", PreserveSig = false)]
[return: MarshalAs(UnmanagedType.Interface)]
public static extern object CoCreateInstance([In] ref Guid clsid,[MarshalAs(UnmanagedType.Interface)] object punkOuter,int context, [In] ref Guid iid);
public object createComObject(){
Guid IID_IUnknown = new Guid("{00000000-0000-0000-C000-000000000046}");
var gid = "{6bf52a52-394a-11d3-b153-00c04f79faa6}"; //your ocx guid
var clsid = new Guid(gid);
object yourOCX = CoCreateInstance(ref clsid, (object)null, 1, ref IID_IUnknown);
return yourOCX ;
}
You can later cast the COM object to required interfaces
IOleObject iole = yourOCX as IOleObject;
IWMPCore iwmp = yourOCX as IWMPCore;
I have created Windows Media Player ActiveX without UI or AxHost in C# over this link. It might help someone trying to run ActiveX without UI.

Categories