I have built a WinForms application which consists of just a RichTextBox and ive built it into an EXE.
The purpose of this EXE is to act as a logger so that when im running tests the log is output onto this EXE.
Important note is that this EXE is referenced in a separate Unit Test (to be run by Microsoft Test Manager) solution by adding the EXE as a reference in the project. This seems to expose the objects I need.
I've had some success using HTTP through the ChannelFactory interfaces, but i'd prefer to talk to the EXE directly.
These unit tests I have are essentially sending and receiving data from OpenVMS, and some of these tests can take some time to complete.
So I built a new Console project to test the public methods I've exposed in my logger.exe and so far heres my code:
TerminalLogger.Logger term = new TerminalLogger.Logger();
term.TerminalLog("Test");
When I run this the form opens, but nothing loads in. So im assuming thats because the form runs on the same thread? Do I need to have this form running on its own thread?
I notice that if I add "term" to watch in Visual Studio and inspect the richtextbox I can see that it has actually written the value "Test" to the object, but of course I cannot see this as the form hasnt fully rendered in.
I still need to be able to call methods like term.LogMessage("Example Message") and get it to display on the form.
If you need extra info please add a comment and i'll do my best to elaborate more on my question.
Well I asked one of the web developers at my organisation on the offchance they might be able to help, and apparently calling a redraw fixed my issue!.
I simply added:
LogConsole.TextChanged += (sender, e) =>
{
if (this.Visible)
{
this.Refresh();
}
};
Here is how I call the code from my unit test:
TerminalLogger.Logger term = new TerminalLogger.Logger();
term.Show();
term.TerminalLog("Test1");
term.TerminalLog("Test2");
And I can send messages to it without it locking up.
Related
I'm looking for some help. I am in need of figuring out how to get an object reference to Microsoft Access 2013 so that I can (through Automation) call some of the already defined functions in the accdb. For instance; I want to automate the process of "RelinkODBCTables" function which repoints the linked tables to another data source from my .net core 3.0 c# application.
I've not been able to successfully get a reference to interop but I may not be doing it correctly.
Any help would be greatly appreciated.
D-
If you want to
Create a instnce of Access.
Call a VBA sub (say your relink code).
Close the the database.
quit access.
You could use this code:
{
object AccessApp;
AccessApp = Interaction.CreateObject("Access.Application");
AccessApp.OpenCurrentDatabase(#"c:\test\test44.accdb");
AccessApp.Run("MyLinker");
AccessApp.CloseCurrentDatabase();
AccessApp.Quit();
}
So, you don't need any referance at all. Just create a instance of the given applicatin (word, Excel or as per above Access).
At that point, you have full use of the object model, and can use run to call some VBA routine. In above, we call a VBA Sub called MyRelinker.
About the only caution here is that when you create the instance of that object, then all startup code of the application will run. So, if on startup the forms and UI that the developer of the Access program launches any prompt, then you can't "answer" that prompt. So, how well this works will VERY much depend on how nice the application plays on startup, and that calling any of those VBA routines does not trigger some kind of prompt(s) in that Access application. If it does, then you in trouble, since you can't "answer" any of the forms or code prompts that access may very well throw up at the end user.
And, if you do want some "inteli-sense" during coding, then you can add a office "interop" reference to your project. Its not required, but if you not really fluent in the Access VBA + object model, then in place of CreateObject("Access.Application"), if you do referance the office assemby, say this one:
Microsoft.Office.Interop.Access
C:\Program Files (x86)\Microsoft Visual Studio 12.0\
Visual Studio Tools for Office\PIA\Office14\
Microsoft.Office.Interop.Access.dll
Then you code becomes this:
{
Microsoft.Office.Interop.Access.Application AccessApp =
new Microsoft.Office.Interop.Access.Application();
AccessApp.OpenCurrentDatabase(#"c:\test\test44.accdb");
AccessApp.Run("MyLinker");
AccessApp.CloseCurrentDatabase();
AccessApp.Quit();
}
However, while you get stronger typing with the reference, you often will "tie" you code to a given version of Access, and a simple use of CreateObject() quite much means that you can create a instance of Any Access installed on the target computer, and it should work going back all the way to office 2000 - a good 20 years of "coverage".
Keep in mind that you CAN NOT create a instance of the Access runtime, the target computer will requite a full version to "create" a instance of the Access.Application object.
You "can" automate the runtime version. This involves launching Access runtime (via Shell()), and then grabbing an instance with "GetObject()" in place of CreateObject().
Edit
I should point out that in the 2nd above code example, and using the office interop-assembly reference, I choose office 14, which is office 2010. In your case, you have to use office 15 (2013).
I have a PushButton in a revit API ribbon and would like to simulate a press on it in order to do some tests (I need a ExternalCommandData object from the currently active document). However I cannot seem to find anything like a PushButton.Click() function.
var panel = Application.CreateRibbonPanel("a", "b")
var buttonData = new PushButtonData(name, name, ApplicationInfo.AddInPath, "TestZone.Commands." + "DefaultCommand");
var button = panel.AddItem(buttonData) as PushButton;
With Application being of course the default UIControlledApplication on the OnStartup function. Anyway to know simulate a button click so that I can obtain an ExternalCommandData object of the currently opened document (In the final version there will be checks to ensure that a document is already open ext.) Or is there another way to obtain an externalCommandData?
Note that this question may require you to know the revit API, I doubt that just knowledge of c# will be enough to answer this.
I had many of the same issues with unit testing Revit - and the other users are right, there is no way to get an ExternalCommandData object without running a command. Fortunately, there's a framework that makes a lot of this possible by automating the startup and running of Revit externally.
https://github.com/DynamoDS/RevitTestFramework
The Dynamo group built this framework to automate their tests, and it offers a lot of great functionality.
Most pertinently for you, it actually exposes a valid ExternalCommandData object
Here is some example code from their framework.
/// <summary>
/// Using the TestModel parameter, you can specify a Revit model
/// to be opened prior to executing the test. The model path specified
/// in this attribute is relative to the working directory.
/// </summary>
[Test]
[TestModel(#"./bricks.rfa")]
public void ModelHasTheCorrectNumberOfBricks()
{
var doc = RevitTestExecutive.CommandData.Application.ActiveUIDocument.Document;
var fec = new FilteredElementCollector(doc);
fec.OfClass(typeof(FamilyInstance));
var bricks = fec.ToElements()
.Cast<FamilyInstance>()
.Where(fi => fi.Symbol.Family.Name == "brick");
Assert.AreEqual(bricks.Count(), 4);
}
RevitTestExecutive.CommandData offers the ExternalCommandData you are looking for.
Note that there's an issue with installing the RTF as an admin on your machine. I recommend installing it to a local directory as a local user so you don't run into Windows UAC issues.
There is no way to obtain an ExternalCommandData object without running a command.
You may be able to use UI Automation to programmatically click on your PushButton. It may be simpler to configure a keyboard shortcut for your command and use UI Automation to simulate the keypresses for you.
See Jeremy Tammik's blog for information on using UI Automation in Revit: http://thebuildingcoder.typepad.com/blog/automation/
You cannot simulate the click to launch an external command, and you cannot create a valid ExternalCommandData object yourself. Only Revit can do that when calling your event handler and providing it with a valid Revit API context in a call-back function, i.e., Revit event handler such as the external command Execute method.
You can however launch an external command from some other valid Revit API context, just as you can a built-in Revit command, using the PostCommand API:
http://thebuildingcoder.typepad.com/blog/about-the-author.html#5.3
In my VS2012 C# project, I am wiring a code that is using VC6 composed ActiveX EXE through its auto generated assembly equivalent that, I suppose, some plumbing is done with TLBIMP.exe when it is referenced in my C# project.
When the code is executed I see the ActiveX EXE being launched in a separate process and is terminated upon the termination of the C# code that it is referenced from.
It seems working as I expected, but I have hard time looking for documentation from which I can rest assure that it is the correct usage of ActiveX EXE in C# project.
Can anyone give some advice?
It is a good sign that you can see the process running. A very easy way to prove success and gain 100% confidence would be to add logging to your VC6 exe and examine the log to ensure it is behaving as you expect. For example, if your VC6 exe receives command line arguments, you could log what they are to ensure you are correctly executing it from your C# program. If you cannot change the VC6 exe, you are left with black box testing: With specific inputs, do you get the expected outputs? I suppose you could use fancier and more time consuming methods, but you might not need to if my suggestions are sufficient.
I am looking to convert a C# (Windows platform application) into a commandline version.
The scenario is: I have implemented a C# (Windows application) in VS 2010. The output of this application is to generate a txt (log) file (in simple explanation).
Now the case is, there is one other application which need to use my this C# application, by calling my C# application from the command line at the run time.
My question is, how is it possible to convert an already existing C# application into commandline application, so that this C# application can be called from the calling (other) program? There is one input parameter which need to be passed on the commandline to my C# application. And then this C# application will process the data according to input parameter and then generate the output log(txt) file.
Added explanation
I am really impressed by the solutions here. Just a bit more expertise is required from readers. I want one application only to work as both commandline application as well Windows-application (forget to mention it before, sorry!), depending on the number of input parameter pass to the application. From this point of view, I have two options to implement it,
1) Make separate functions for both applications (commandline and windows-forms). Call them according to the input parameter pass. In each function implement the complete functionality of each application without disturbing (or going into the code of other application). Also I will be able to re-use 2 main functions, already built in windows-form application into my commandline application after some editing.
Disadvantage: This will make the code size nearly 50% more than case 2.
2) The second idea is same as describe by one of the expert here, to use the same application/functions for commandline as that of already built windows-form application. The only way to distinguish is to look at the input parameter pass, and decide accordingly whether to show the GUI interface or just use the commandline input (and do processing).
Disadvantage: This case will make the code bit messy and difficult to maintain/implement due to extra adding of check for number of input parameter decisions.
Which strategy should I follow for implementation?
Sure - just:
Create a new VS2010 command-line project
You'll now have a "main ()" (or, in MS-Land, "_tmain()") function instead of a root class.
Cut and paste the relevant code into "main()" (or into a function called by main (), or into a class created from main() - your choice).
Do a search-and-destroy mission to find anyplace where you're doing GUI input, and substitute command line parameters instead.
Parse your command line.
Voila! Done!
You don't have to convert it. Your application can stay as a Windows application. You simply need to handle command line arguments.
To get the command line arguments from ANYWHERE in the application, just use Environment.GetCommandLineArgs();
You want to get value from command line is not a good reason to convert winform app to console app. You may use,
string[] args = Environment.GetCommandLineArgs();
However you can change application type by opening project properties (right click on project name) and change the Output type.
Just don't show the GUI if you get paramater passed in, as when called from the other program.
I'm looking to show window (WPF) that is defined in separate class library project as new separate process. Is there any way to do this?
I need to start the second project instance in new process, because there stay occupied memory when I start it by this way:
secondProject.WPFWindow win = new secondProject.WPFWindow();
win.Show();
I have ONE solution with multiple projects.
StartUp project is WPF app., output type: Windows application (exe file).
All other projects are WFP app., output type: Class library (dll file).
Now I am running "applications" (other projects in this one solution built as dll) by this code:
secondProject.WPFWindow win = new secondProject.WPFWindow();
win.Show();
I want is runnig that apps in new process... Normally I would use Process.Start(), but I can't is this case because it needs exe file as agrument and I have (and want) DLLs.
You could pass command line arguments to the main .exe to tell it which of the 'sub-apps' to run. Then the main .exe can just launch itself in a new process and tell the new instance which sub-app to run. For example in the main .exe app, put logic like this in your Application class:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
//See if exactly one command line argument was passed
if (e.Args.Length == 1)
{
//See if the argument is one of our 'known' values
switch (e.Args[0])
{
case "launchApp2":
secondProject.WPFWindow win2 = new secondProject.WPFWindow();
win2.Show();
break;
case "launchApp3":
thirdProject.OtherWPFWindow win3 = new thirdProject.OtherWPFWindow();
win3.Show();
break;
}
}
//Probably want to call the base class always?
base.OnStartup(e);
}
}
Then anytime you want to launch one of the sub-app in a new process, you can do so like this:
public void LaunchApp2()
{
//Start a new process that is ourself and pass a command line parameter to tell
// that new instance to launch App2
Process.Start(Assembly.GetEntryAssembly().Location, "launchApp2");
}
Let's assume you have a solution with 2 projects - one project compiles to an application (EXE), while the second compiles to a class library (DLL). I'll assume that the DLL has some type defined (say, a window) which you want to start from the EXE.
The simplest way to do this, is simply add a reference to the DLL. Right-click on the EXE project in the Solution Explorer, and choose Add Reference.... Wait a minute while the dialog opens. From the Projects tab, select the DLL project. Click OK.
Now, in your EXE project, WPFWindow will available as an imported type. You need to add a
using secondProject;
to the top of each code file that uses WPFWindow. I normally do this automatically using the keyboard shortcut CTRL + Period.
The method I've described is the standard method of using DLLs in C#. You can load them manually, but that is a little more complex, and likely isn't what you want to do.
Edit:
Alexei is correct. I think what we have here is an XY Problem. What you're trying to do is probably very easy, but the approach (instantiating a window defined in a DLL) is not.
Be aware that any code you run (in your case, your WPFWindow) has to originate from an application, even though the code itself is defined in a DLL. A DLL by itself normally provides no information to the operating system about how to run any of the code contained within.
Consider adding another EXE project which runs your WPFWindow which you call using Process. This suggestion might be wrong, though, as we still don't know what your end goal is. You're asking "How do I flap my wings like a bird?" when the correct question could be "How do I buy a plane ticket?"