I'm using Microsoft.Office.Interop.Access to open access db using code like this :
Access.Application AccApp = new Access.Application();
AccApp.Visible = true;
AccApp.OpenCurrentDatabase(databasePathAndFileName, false, databasePassword);
The point is when access opens the window's size is small I need to maximize the access window after opening it .
Thanks
The VBA command for this is
DoCmd.RunCommand acCmdAppMaximize
which should be callable from C# interop as follows:
const int acCmdAppMaximize = 10;
AccApp.DoCmd.RunCommand(acCmdAppMaximize);
Obviously, you can (and should) skip the redeclaration of the acCmdAppMaximize constant if it is already provided by the interop library.
Thanks to #Heinzi who pointed me to the right direction , This worked for me :
Microsoft.Office.Interop.Access.Application AccApp = new Microsoft.Office.Interop.Access.Application();
AccApp.Visible = true;
AccApp.OpenCurrentDatabase("D:\\Settings.accdb", false, "017014A");
AccApp.RunCommand(AcCommand.acCmdAppMaximize);
Related
I'm using WinAPI ChangeDisplaySettingsEx to switch my windows 10 screens config.
There are more than two screens, so ScreenSwitch.exe is not enough for me.
I referenced this:
https://www.codeproject.com/Articles/178027/How-to-create-a-display-switcher-for-Windows-XP?msg=3850767#xx3850767xx
and successed disable a screen in these code:
string displayName = #"\\.\DISPLAY3";
DEVMODE devMode= new DEVMODE();
devMode.dmPosition.x = 0;
devMode.dmPosition.y = 0;
devMode.dmPelsWidth = 0;
devMode.dmPelsHeight = 0;
devMode.dmFields = DEVMODE_Flags.DM_PELSHEIGHT | DEVMODE_Flags.DM_PELSWIDTH | DEVMODE_Flags.DM_POSITION;
devMode.dmSize = (ushort)Marshal.SizeOf(devMode);
ChangeDisplaySettingsEx(displayName, ref devMode, IntPtr.Zero, (int)(DeviceFlags.CDS_RESET | DeviceFlags.CDS_UPDATEREGISTRY), IntPtr.Zero);
But I can't enable screen:
...
devMode.dmPosition.x = -3840;
devMode.dmPosition.y = -1059;
devMode.dmPelsWidth = 3840;
devMode.dmPelsHeight = 2160;
...
ChangeDisplaySettingsEx got -1 result means CHANGE_FAILED
I guess that screen has disabled, so enable it need more information?
I tried save DEVMODE when the screen enabled, and send it to ChangeDisplaySettingsEx when screen disabled. Not works.
Thanks for any suggest
Thanks Strive Sun's answer.
It work.
I can't enable my "\.\DISPLAY3" directly,
My "Screen2" will be active first, although the argument is "Screen3".
But it can workaround easily, like this:
enableScreen(2);
enableScreen(3);
disableScreen(2);
I also tried use EnumDisplayDevices to get the deviceName of my monitor.
I got "\.\DISPLAY3\Monitor0".
But it will fail in ChangeDisplaySettingsEx, got -5 result (means BAD_PARAM).
If I want to create a word document in C# using Interop.Word, I can create the document without ever opening the program:
Microsoft.Office.Interop.Word.Application wordApp = new Microsoft.Office.Interop.Word.Application();
wordApp.Visibile = false;
I'm trying to find an equivalent when using Interop.Powerpoint, but I have been unable to find the appropriate property.
Any help would be much appreciated.
EDIT
Sorry, my question was not clear. I have tried:
Microsoft.Office.Interop.Powerpoint.Application pptApp = new Microsoft.Office.Interop.Powerpoint.Application();
pptApp.Visible = Microsoft.Office.Core.MsoTriState.msoFalse;
However, I received the following error:
Application (unknown member) : Invalid request. Hiding the application window is not allowed.
You can prevent from showing the window while opening the Presentation:
pptApp = new Microsoft.Office.Interop.Powerpoint.Application();
pptApp.Presentations.Open(fileName, WithWindow:Microsoft.Office.Core.MsoTriState.msoFalse);
I know you already utilized Open XML, but maybe someone else will need this.
MChmurski's answer inspired me but when I was trying it doesn't work as expected.
The signature for Presentations.Open() is as following:
Presentation Open(
string FileName,
MsoTriState ReadOnly,
MsoTriState Untitled,
MsoTriState WithWindow
)
I think we'd be set the last TriState option instead of the 2nd. So I changed it as following and it works perfectly:
var objApp = new Microsoft.Office.Interop.PowerPoint.Application();
var objPres = objApp.Presentations.Open(filePath, MsoTriState.msoTrue, MsoTriState.msoTrue, MsoTriState.msoFalse);
I have written a c# service to reset my windows XP password. As of now i learned few things about windows service. The main thing is windows service is incompatible with UI. I know that using service cant use form UI(Here is the link). So, by using my service code At least the hard coded password should work. Here i have given the form code. I just want to call the ResetAdminPass("DillGates"); function in service.
ResetAdminPass("DillGates");//By calling this method works fine in windows form.
private static void ResetAdminPass(string NewPass)
{
//Create New Process
Process QProc = new Process();
// Do Something To hide Command(cmd) Window
QProc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
QProc.StartInfo.CreateNoWindow = true;
// Call Net.exe
QProc.StartInfo.WorkingDirectory = "C:\\windows\\SYSTEM32";
QProc.StartInfo.FileName = "net.exe";
QProc.StartInfo.UseShellExecute = false;
QProc.StartInfo.RedirectStandardError = true;
QProc.StartInfo.RedirectStandardInput = true;
QProc.StartInfo.RedirectStandardOutput = true;
QProc.StartInfo.Arguments = #" user 5mine " + NewPass;
QProc.Start();
// MyProc.WaitForExit();
QProc.Close();
}
Please do favor for me, with solution/suggestion for my service code. Thanks in advance.
In the image below there is an area, which has an unknown (custom) class. That's not a Grid or a Table.
I need to be able:
to select Rows in this area
to grab a Value from each cell
The problem is since that's not a common type element - I have no idea how to google this problem or solve it myself. So far the code is following:
Process[] proc = Process.GetProcessesByName("programname");
AutomationElement window = AutomationElement.FromHandle(proc [0].MainWindowHandle);
PropertyCondition xEllist2 = new PropertyCondition(AutomationElement.ClassNameProperty, "CustomListClass", PropertyConditionFlags.IgnoreCase);
AutomationElement targetElement = window.FindFirst(TreeScope.Children, xEllist2);
I've already tried to threat this Area as a textbox, as a grid, as a combobox, but nothing solved my problem so far. Does anybody have any advice how to grab data from this area and iterate through rows?
EDIT: sorry I've made a wrong assumption. Actually, the header(column 1, column 2, column 3) and the "lower half" of this area are different control-types!!
Thanks to Wininspector I was able to dig more information regarding these control types:
The header has following properties: HeaderControl 0x056407DC (90441692) Atom: #43288 0xFFFFFFFF (-1)
and the lower half has these: ListControl 0x056408A4 (90441892) Atom: #43288 0x02A6FDA0 (44498336)
The code that I've showed earlier - retrieved the "List" element only, so here is the update:
Process[] proc = Process.GetProcessesByName("programname");
AutomationElement window = AutomationElement.FromHandle(proc [0].MainWindowHandle);
//getting the header
PropertyCondition xEllist3 = new PropertyCondition(AutomationElement.ClassNameProperty, "CustomHeaderClass", PropertyConditionFlags.IgnoreCase);
AutomationElement headerEl = XElAE.FindFirst(TreeScope.Children, xEllist3);
//getting the list
PropertyCondition xEllist2 = new PropertyCondition(AutomationElement.ClassNameProperty, "CustomListClass", PropertyConditionFlags.IgnoreCase);
AutomationElement targetElement = window.FindFirst(TreeScope.Children, xEllist2);
After giving it a further thought I've tried to get all column names:
AutomationElementCollection headerLines = headerEl.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.HeaderItem));
string headertest = headerLines[0].GetCurrentPropertyValue(AutomationElement.NameProperty) as string;
textBox2.AppendText("Header 1: " + headertest + Environment.NewLine);
Unfortunately in debug mode element count in "headerLines" is 0 so the program throws an error.
Edit 2: Thanks to the answer below - I've installed Unmanaged UI Automation, which holds better possibilities than the default UIA. http://uiacomwrapper.codeplex.com/
How do you use the legacy pattern to grab data from unknown control-type?
if((bool)datagrid.GetCurrentPropertyValue(AutomationElementIdentifiers.IsLegacyIAccessiblePatternAvailableProperty))
{
var pattern = ((LegacyIAccessiblePattern)datagrid.GetCurrentPattern(LegacyIAccessiblePattern.Pattern));
var state = pattern.Current.State;
}
Edit 3. IUIAutoamtion approach (non-working as of now)
_automation = new CUIAutomation();
cacheRequest = _automation.CreateCacheRequest();
cacheRequest.AddPattern(UiaConstants.UIA_LegacyIAccessiblePatternId);
cacheRequest.AddProperty(UiaConstants.UIA_LegacyIAccessibleNamePropertyId);
cacheRequest.TreeFilter = _automation.ContentViewCondition;
trueCondition = _automation.CreateTrueCondition();
Process[] ps = Process.GetProcessesByName("program");
IntPtr hwnd = ps[0].MainWindowHandle;
IUIAutomationElement elementMailAppWindow = _automation.ElementFromHandle(hwnd);
List<IntPtr> ls = new List<IntPtr>();
ls = GetChildWindows(hwnd);
foreach (var child in ls)
{
IUIAutomationElement iuiae = _automation.ElementFromHandle(child);
if (iuiae.CurrentClassName == "CustomListClass")
{
var outerArayOfStuff = iuiae.FindAllBuildCache(interop.UIAutomationCore.TreeScope.TreeScope_Children, trueCondition, cacheRequest.Clone());
var outerArayOfStuff2 = iuiae.FindAll(interop.UIAutomationCore.TreeScope.TreeScope_Children, trueCondition);
var countOuter = outerArayOfStuff.Length;
var countOuter2 = outerArayOfStuff2.Length;
var uiAutomationElement = outerArayOfStuff.GetElement(0); // error
var uiAutomationElement2 = outerArayOfStuff2.GetElement(0); // error
//...
//I've erased what's followed next because the code isn't working even now..
}
}
The code was implemented thanks to this issue:
Read cell Items from data grid in SysListView32 of another application using C#
As the result:
countOuter and countOuter2 lengths = 0
impossible to select elements (rows from list)
impossible to get ANY value
nothing is working
You might want to try using the core UI automation classes. It requires that you import the dll to use it in C#. Add this to your pre-build event (or do it just once, etc):
"%PROGRAMFILES%\Microsoft SDKs\Windows\v7.0A\bin\tlbimp.exe" %windir%\system32\UIAutomationCore.dll /out:..\interop.UIAutomationCore.dll"
You can then use the IUIAutomationLegacyIAccessiblePattern.
Get the constants that you need for the calls from:
C:\Program Files\Microsoft SDKs\Windows\v7.1\Include\UIAutomationClient.h
I am able to read Infragistics Ultragrids this way.
If that is too painful, try using MSAA. I used this project as a starting point with MSAA before converting to all UIA Core: MSSA Sample Code
----- Edited on 6/25/12 ------
I would definitely say that finding the proper 'identifiers' is the most painful part of using the MS UIAutomation stuff. What has helped me very much is to create a simple form application that I can use as 'location recorder'. Essentially, all you need are two things:
a way to hold focus even when you are off of your form's window Holding focus
a call to ElementFromPoint() using the x,y coordinates of where the mouse is. There is an implementation of this in the CUIAutomation class.
I use the CTRL button to tell my app to grab the mouse coordinates (System.Windows.Forms.Cursor.Position). I then get the element from the point and recursively get the element's parent until I reach the the desktop.
var desktop = auto.GetRootElement();
var walker = GetRawTreeWalker();
while (true)
{
element = walker.GetParentElement(element);
if (auto.CompareElements(desktop, element) == 1){ break;}
}
----- edit on 6/26/12 -----
Once you can recursively find automation identifiers and/or names, you can rather easily modify the code here: http://blog.functionalfun.net/2009/06/introduction-to-ui-automation-with.html to be used with the Core UI Automation classes. This will allow you to build up a string as you recurse which can be used to identify a control nested in an application with an XPath style syntax.
I'd like to create a small application that can collect system information (Win32_blablabla) using WinRM as opposed to WMI. How can i do that from C#?
The main goal is to use WS-Man (WinRm) as opposed to DCOM (WMI).
I guess the easiest way would be to use WSMAN automation. Reference wsmauto.dll from windwos\system32 in your project:
then, code below should work for you. API description is here: msdn: WinRM C++ API
IWSMan wsman = new WSManClass();
IWSManConnectionOptions options = (IWSManConnectionOptions)wsman.CreateConnectionOptions();
if (options != null)
{
try
{
// options.UserName = ???;
// options.Password = ???;
IWSManSession session = (IWSManSession)wsman.CreateSession("http://<your_server_name>/wsman", 0, options);
if (session != null)
{
try
{
// retrieve the Win32_Service xml representation
var reply = session.Get("http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Service?Name=winmgmt", 0);
// parse xml and dump service name and description
var doc = new XmlDocument();
doc.LoadXml(reply);
foreach (var elementName in new string[] { "p:Caption", "p:Description" })
{
var node = doc.GetElementsByTagName(elementName)[0];
if (node != null) Console.WriteLine(node.InnerText);
}
}
finally
{
Marshal.ReleaseComObject(session);
}
}
}
finally
{
Marshal.ReleaseComObject(options);
}
}
hope this helps, regards
I've got an article that describes an easy way to run Powershell through WinRM from .NET at http://getthinktank.com/2015/06/22/naos-winrm-windows-remote-management-through-net/.
The code is in a single file if you want to just copy it and it's also a NuGet package that includes the reference to System.Management.Automation.
It auto manages trusted hosts, can run script blocks, and also send files (which isn't really supported but I created a work around). The returns are always the raw objects from Powershell.
// this is the entrypoint to interact with the system (interfaced for testing).
var machineManager = new MachineManager(
"10.0.0.1",
"Administrator",
MachineManager.ConvertStringToSecureString("xxx"),
true);
// will perform a user initiated reboot.
machineManager.Reboot();
// can run random script blocks WITH parameters.
var fileObjects = machineManager.RunScript(
"{ param($path) ls $path }",
new[] { #"C:\PathToList" });
// can transfer files to the remote server (over WinRM's protocol!).
var localFilePath = #"D:\Temp\BigFileLocal.nupkg";
var fileBytes = File.ReadAllBytes(localFilePath);
var remoteFilePath = #"D:\Temp\BigFileRemote.nupkg";
machineManager.SendFile(remoteFilePath, fileBytes);
Hope this helps, I've been using this for a while with my automated deployments. Please leave comments if you find issues.
I would like to note that this shows an interop error by default in Visual Studio 2010.
c.f. http://blogs.msdn.com/b/mshneer/archive/2009/12/07/interop-type-xxx-cannot-be-embedded-use-the-applicable-interface-instead.aspx
There appear to be two ways to solve this. This first is documented in the article listed above and appears to be the correct way to handle the problem. The pertinent changes for this example is:
WSMan wsManObject = new WSMan();
This is in lieu of IWSMan wsman = new WSManClass(); which will throw the error.
The second resolution is to go to the VS2010—>Solution Explorer—>Solution—>Project—>References and select WSManAutomation. Right click or hit Alt-Enter to access the properties. Change the value of the "Embed Interop Types" property of the wsmauto reference.