My app has the ability to use a dual monitor configuration. In the app's settings I list the available displays where the user will choose his secondary screen.
I'm getting the (real) monitor device names using:
http://msdn.microsoft.com/en-us/library/aa394122%28VS.85%29.aspx
SelectQuery q = new SelectQuery("SELECT Name, DeviceID, ScreenHeight, ScreenWidth FROM Win32_DesktopMonitor");
using (ManagementObjectSearcher mos = new ManagementObjectSearcher(q))
{
foreach (ManagementObject mo in mos.Get())
{
...
}
}
But I also need the display bounds (top, left, etc) which this doesn't give me. But System.Windows.Forms.Screen does give me bounds but not real device names. I could use these together if I am certain that they return the devices in the same order every time. Will both of these always return "Device 1", "Device 2", etc in chronological order every time? Or is there a way that contains all my needed information?
[edit]
Hmm. Win32_DesptopMonitor isnt giving me my secondary monitors name. Its just calling it Default Monitor. And it's listing it before my primary.
[edit2]
Ok it's got the names and their resolutions messed up..... Anyone know whats going on here?
I have done this before using Win API calls. I pasted bits of the code below, which might be helpful to you...
public void Store()
{
Screens.Clear();
uint iAdaptorNum = 0;
Win.User32.DISPLAY_DEVICE adaptor = new Win.User32.DISPLAY_DEVICE();
adaptor.cb = (short)Marshal.SizeOf(adaptor);
Win.User32.DISPLAY_DEVICE dd = new Win.User32.DISPLAY_DEVICE();
dd.cb = (short)Marshal.SizeOf(dd);
while (Win.User32.EnumDisplayDevices(null, iAdaptorNum, ref adaptor, Win.User32.EDD_GET_DEVICE_INTERFACE_NAME))
{
uint iDevNum = 0;
while (Win.User32.EnumDisplayDevices(adaptor.DeviceName, iDevNum, ref dd, Win.User32.EDD_GET_DEVICE_INTERFACE_NAME))
{
log.WriteFormat(LogLevel.Debug, "Adaptor {0}:{1} {2}='{3}', Device {4}='{5}', State flags = {4}",
iAdaptorNum, iDevNum, adaptor.DeviceName, adaptor.DeviceString, dd.DeviceName, dd.DeviceString, dd.StateFlags);
if ((dd.StateFlags & Win.User32.DisplayDeviceStateFlags.AttachedToDesktop) > 0)
Screens.Add(new ScreenInfo(adaptor, dd));
iDevNum++;
}
iAdaptorNum++;
}
}
And this is what gets called behind new ScreenInfo:
public void StoreScreen(Win.User32.DISPLAY_DEVICE Adaptor, Win.User32.DISPLAY_DEVICE Device)
{
adaptor = Adaptor.DeviceName;
device = Device.DeviceName;
name = string.Format("{0} on {1}", Device.DeviceString, Adaptor.DeviceString);
Win.User32.DEVMODE dm = newDevMode();
if (Win.User32.EnumDisplaySettings(Adaptor.DeviceName, Win.User32.ENUM_CURRENT_SETTINGS, ref dm) != 0)
{
isAttached = (Adaptor.StateFlags & Win.User32.DisplayDeviceStateFlags.AttachedToDesktop) > 0;
isPrimary = (Adaptor.StateFlags & Win.User32.DisplayDeviceStateFlags.PrimaryDevice) > 0;
mode = findMode(Adaptor.DeviceName, dm);
if ((dm.dmFields & Win.User32.DM.PelsWidth) > 0) width = dm.dmPelsWidth;
if ((dm.dmFields & Win.User32.DM.PelsHeight) > 0) height = dm.dmPelsHeight;
if ((dm.dmFields & Win.User32.DM.BitsPerPixel) > 0) bpp = dm.dmBitsPerPel;
if ((dm.dmFields & Win.User32.DM.Orientation) > 0) orientation = dm.dmOrientation;
if ((dm.dmFields & Win.User32.DM.DisplayFrequency) > 0) frequency = dm.dmDisplayFrequency;
if ((dm.dmFields & Win.User32.DM.DisplayFlags) > 0) flags = dm.dmDisplayFlags;
if ((dm.dmFields & Win.User32.DM.Position) > 0)
{
posX = dm.dmPosition.x;
posY = dm.dmPosition.y;
}
}
}
private static Win.User32.DEVMODE newDevMode()
{
Win.User32.DEVMODE dm = new Win.User32.DEVMODE();
dm.dmDeviceName = new String(new char[31]);
dm.dmFormName = new String(new char[31]);
dm.dmSize = (short)Marshal.SizeOf(dm);
return dm;
}
Related
I have a C# console app that is processing huge data in a Parallel.For loop.
But after a while my app suspends periodically(CPU-Usage falls down ),exactly in the same For-loop with same process.
CPU doesn't do anything on my app based on profiling information.
I guess it may be related to memory because it happens when memory usage reaches above 90%.
Thank you for your help.
Image of CPU usage profiling when Main is Selected
feasiblePairs22222 = new List<Pair>();
Pair[] tempPair = new Pair[tripListSize];
Parallel.For(0, tripListSize, tri=> {
var PairingStack = new Stack<List<Trip>>();
var firstElement = new List<Trip>();
firstElement.Add(Program.tripList[tri]);
PairingStack.Push(firstElement);
while (PairingStack.Count > 0)
{
var tempPairing11 = PairingStack.Pop();
int start = tempPairing11[tempPairing11.Count - 1].index;
int startTime = tempPairing11[0].departureTime;
foreach (Trip candidToAdd in twoTripMatchable[start])
{
if (candidToAdd.araivalTime - startTime > Program.WorkingTimeLimit) { continue; }
if (candidToAdd.departureTime - tempPairing11[tempPairing11.Count - 1].araivalTime > 30) { continue; }
var newPairing = new List<Trip>();
newPairing.AddRange(tempPairing11);
newPairing.Add(candidToAdd);
PairingStack.Push(newPairing);
int workingTime = 0;
foreach (Trip currentTrip in newPairing) { workingTime = workingTime + currentTrip.Duration; }
if (workingTime <= 180) { continue; }
newPairing.ForEach(o => o.isCovered++);
lock (tempPair)
{
tempPair[tri] = new Pair();
tempPair[tri].PairTrips = newPairing.ToArray();
feasiblePairs22222.Add(tempPair[tri]);
}
}
}
});
Let me start by apologizing for the complexity of this post. hopefully I am missing something simple but in order to find out I have to make a lengthy explanation.
I'm building a staff tracking app that allows users to draw polygons on a map. The polygon is used as a zone. If the device location is inside the zone it will set them to one status such as "In" and then set them to another status like "Out" when they leave. I'm using several nugets; SQLite, TK.CustomMap, PopupPlugin, to accomplish as much of this as possible in the Shared Project. The SQLite data model is based on the structure of the remote database for the solution which also has a desktop application, web app, and many other interfaces so that structure must be maintained.
The tables involved in this operation are Zones, ZonePoints and StatusClass. When the Zone is saved the Points of the TK.Polygon are saved into the points table. The Statuses assigned to the in and out status of the Zone are assigned to the zone as is the zone name.
The process works this way - first the user clicks on a button to add the zone. This creates a new zone, saves it to the database and gets its id from the table. For now, the ZoneSys (Primary Key in the remote db) is also set to the id although when the API is ready this will be Auto Incremented in the remote db. Here is that command and the objects it references. I did not include the database method definitions given that they work on the first time through, but if anyone thinks they will help solve this riddle please let me know -
public static List<Position> ActiveZonePositions = new List<Position>();
public static int ActiveZoneID;
public static Zone ActiveZone;
public static int PointCount;
public static bool NewZoneOpen = false;
public Command<EventArgs> OpenNewZone
{
get
{
return new Command<EventArgs>(async e =>
{
NewZoneOpen = true;
PointCount = 0;
ActiveZonePositions.Clear();
Zone ZoneToAdd = new Zone
{
Contactsys = MobileUser.ContactSys,
ZoneTypeSys = 1,
OrganizationSys = MobileUser.OrganizationSys,
ZoneName = null
};
ActiveZoneID = await AddZoneToDBAsync(ZoneToAdd);
ZoneToAdd.ID = ActiveZoneID;
ZoneToAdd.ZoneSys = ActiveZoneID;
await AddZoneToDBAsync(ZoneToAdd);
ActiveZone = await App.Database.GetZoneAsync(ActiveZoneID);
});
}
}
As the user click points in the map the polygon is drawn using those positions and those positions are also used to create points which are added to a static list. Here is the MapClicked_Command -
public Command<Position> MapClickedCommand
{
get
{
return new Command<Position>(async position =>
{
if (NewZoneOpen)
{
bool isPointInPolygon = IsPointInAnyPolygon(position);
if (isPointInPolygon)
{
var action = await Application.Current.MainPage.DisplayActionSheet(
"Region Collides with Another Region",
"Cancel",
null,
"Try Again",
"Close Zone Editor");
if (action == "Close Zone Editor")
{
await RemoveZoneAsync(ActiveZoneID);
}
if (action == "Try Again")
{
return;
}
}
else if (!isPointInPolygon)
{
ActiveZonePositions.Add(position);
}
if (ActiveZonePositions.Count == 2)
{
ZonePolyLine.LineCoordinates = ActiveZonePositions;
_lines.Remove(ZonePolyLine);
_lines.Add(ZonePolyLine);
}
else if (ActiveZonePositions.Count == 3)
{
ActiveZonePositions.Add(position);
_lines.Remove(ZonePolyLine);
TKPolygon poly = new TKPolygon
{
StrokeColor = System.Drawing.Color.CornflowerBlue,
StrokeWidth = 2f,
Color = System.Drawing.Color.CornflowerBlue
};
foreach (Position pos in ActiveZonePositions)
{
poly.Coordinates.Add(pos);
}
_polygons.Add(poly);
_currentPolygon.Clear();
_currentPolygon.Add(poly);
currentPolygonRendering = true;
}
else if (ActiveZonePositions.Count > 3)
{
ActiveZonePositions.Add(position);
TKPolygon poly = new TKPolygon
{
StrokeColor = System.Drawing.Color.CornflowerBlue,
StrokeWidth = 2f,
Color = System.Drawing.Color.CornflowerBlue
};
foreach (Position pos in ActiveZonePositions)
{
poly.Coordinates.Add(pos);
}
_polygons.Remove(_polygons.Last());
_polygons.Add(poly);
_currentPolygon.Clear();
_currentPolygon.Add(poly);
}
var pin = new TKCustomMapPin
{
Position = new TK.CustomMap.Position(position.Latitude, position.Longitude),
Title = string.Format("Pin {0}, {1}", position.Latitude, position.Longitude),
IsVisible = true,
IsDraggable = true,
ShowCallout = true
};
_pins.Add(pin);
await CreatePointAsync(position);
PointCount++;
}
else if (EditZoneOpen)
{
ActiveZonePositions.Add(position);
var poly = _polygons[0];
poly.Coordinates.Clear();
foreach (Position pos in ActiveZonePositions)
{
poly.Coordinates.Add(pos);
}
_polygons.Remove(_polygons.Last());
_polygons.Add(poly);
_currentPolygon.Clear();
_currentPolygon.Add(poly);
var pin = new TKCustomMapPin
{
Position = new TK.CustomMap.Position(position.Latitude, position.Longitude),
Title = string.Format("Pin {0}, {1}", position.Latitude, position.Longitude),
IsVisible = true,
IsDraggable = true,
ShowCallout = true
};
_pins.Add(pin);
await CreatePointAsync(position);
PointCount++;
}
});
}
}
Here is the CreatePointAsyncMethod -
public async Task CreatePointAsync(TK.CustomMap.Position position)
{
var zone = await RetrieveZoneAsync(ActiveZoneID);
Model.Point PointToAdd = new Model.Point
{
ZoneSys = zone.ZoneSys,
PointName = "",
Latitude = position.Latitude,
Longitude = position.Longitude,
PointOrder = PointCount + 1
};
ActiveZonePoints.Add(PointToAdd);
}
Here is the IsPointInAnyPolygon method that checks against the list of polygons to ensure the point clicked is not inside any of them as well as its supporting methods.
private bool IsPointInAnyPolygon(Position position)
{
bool inBounds = false;
for (var i = 0; i < ZonePolygons.Count(); i++)
foreach (ZonePolygon zpoly in ZonePolygons)
{
TKPolygon tkpoly = zpoly.Zpolygon;
inBounds = IsPointInPolygon(position, tkpoly.Coordinates);
if (inBounds)
{
ActiveZoneID = zpoly.ID;
return inBounds;
}
}
return inBounds;
}
private bool IsPointInPolygon(TK.CustomMap.Position position, List<Position> coords)
{
int intersectCount = 0;
for (int j = 0; j < coords.Count() - 1; j++)
{
if (j+1 >= coords.Count())
{
if (rayCastIntersect(position, coords[j], coords[0]))
{
intersectCount++;
}
} else if (rayCastIntersect(position, coords[j], coords[j + 1]))
{
intersectCount++;
}
}
return ((intersectCount % 2) == 1); // odd = inside, even = outside;
}
private bool rayCastIntersect(TK.CustomMap.Position position, TK.CustomMap.Position vertA, TK.CustomMap.Position vertB)
{
double aY = vertA.Latitude;
double bY = vertB.Latitude;
double aX = vertA.Longitude;
double bX = vertB.Longitude;
double pY = position.Latitude;
double pX = position.Longitude;
if ((aY > pY && bY > pY) | (aY < pY && bY < pY)
| (aX < pX && bX < pX))
{
return false; // a and b can't both be above or below pt.y, and a or
// b must be east of pt.x
}
double m = (aY - bY) / (aX - bX); // Rise over run
double bee = (-aX) * m + aY; // y = mx + b
double x = (pY - bee) / m; // algebra is neat!
return x > pX;
}
Upon clicking the save button a popup opens that allows the user to give the Zone a name, define the statuses it will be assigned and the points are added to the database. There is a ZoneSys column in the Points table which allows the points to be matched to their respective zones when retrieved. This is done withe the UpdateZone command
public Command<EventArgs> UpdateZone
{
get
{
return new Command<EventArgs>(async e =>
{
Zone zone = await App.Database.GetZoneAsync(ActiveZoneID);
zone.ZoneName = ZoneParameters.ZoneName;
zone.StatusSys = ZoneParameters.InStatus.StatusSys;
zone.OutOfZoneStatusSys = ZoneParameters.OutStatus.StatusSys;
await AddZoneToDBAsync(zone);
if (MapPage.SaveZoneInfoPopupPageOpen)
{
SavePointsOnExit();
MapPage.SaveZoneInfoPopupPageOpen = false;
}
});
}
}
The UpdateZone command calls the SavePointsOnExit method
private async void SavePointsOnExit()
{
ActiveZonePoints.OrderBy(o => o.PointOrder);
for (var i = 0; i < ActiveZonePoints.Count(); i++)
{
Model.Point PointToAdd = new Model.Point();
PointToAdd = ActiveZonePoints[i];
ActivePointID = await AddPointToDBAsync(PointToAdd);
PointToAdd.ID = ActivePointID;
PointToAdd.PointSys = ActivePointID;
await AddPointToDBAsync(PointToAdd);
}
try
{
Zone zone = await RetrieveZoneAsync(ActiveZoneID);
}
catch
{
await Application.Current.MainPage.DisplayActionSheet("no zone returned", "database error", "cancel");
}
try
{
Zone zone = await RetrieveZoneAsync(ActiveZoneID);
await CreateZonedPolygonAsync(zone);
}
catch
{
await Application.Current.MainPage.DisplayActionSheet("Could not create ZonePolygon", "object error", "cancel");
}
ActiveZonePoints.Clear();
ActiveZonePositions.Clear();
NewZoneOpen = false;
ClearPins();
PointCount = 0;
PopulatePoints();
}
In addition to saving the points to the db the SaveZonePointsOnExit method also creates the ZonePolygon and adds it to an observable collection using the CreateZonedPolygonAsync method -
private async Task<ZonePolygon> CreateZonedPolygonAsync(Zone zone)
{
int StatusSys = zone.StatusSys;
var status = await App.Database.GetStatusBySysAsync(StatusSys);
int OutStatusSys = zone.OutOfZoneStatusSys;
var outStatus = await App.Database.GetStatusBySysAsync(OutStatusSys);
var points = await App.Database.GetZonePointsAsync(zone.ZoneSys);
ZonePolygon zonePolygon = new ZonePolygon
{
ID = zone.ID
};
TKPolygon poly = new TKPolygon();
foreach (Model.Point point in points)
{
poly.Coordinates.Add(new Position(point.Latitude, point.Longitude));
}
poly.Color = Color.FromHex(status.ColorCode);
poly.StrokeColor = Color.Firebrick;
poly.StrokeWidth = 5f;
_polygons.Add(poly);
ZonePolygons.Add(zonePolygon);
return zonePolygon;
}
So far all of this works to a point. I have been successful in creating the first Polygon. I don't run into a problem until I attempt to create a second Zone. When I click on the AddZone button a second time that works fine but when I click on the map to begin creating the second zone a nullreference exception occurs.
Given that the first zone is created without issue I think the problem must be arising from something that occurs when the IsPointInAnyPolygon method no longer immediately returns false because the ZonePolygons list is no longer empty. So something about the retrieving of zones from the database to check against is the problem or possibly adding coordinates when the TKPolygon is created. I don't know what has a null reference. I would think that since I am creating the Zones directly from the database that all the objects would be saved properly and their previous references wouldn't matter. I'm very stuck on this.
TL;DR there is an issue with either the CreateZonedPolygonAsync Method or the IsPointInAnyPolygon method
I figured this out. I feel rather silly because I have been stuck on this for several hours spread out over a couple of weeks. Kept coming back to it and couldn't figure it out. The issue was that in the CreateZonedPolygonAsync method I never assigned the TKPolygon created via points to the ZonePolygon object being created. So when I tried to reference it it didn't exist. All that existed was the ID. Can't believe I missed this for this long.
Of course now I'm having brand new problems but at least this is fixed.
All I had to do was add zonePolygon.Zpolygon = poly; as shown here and it works now
private async Task<ZonePolygon> CreateZonedPolygonAsync(Zone zone)
{
int StatusSys = zone.StatusSys;
var status = await App.Database.GetStatusBySysAsync(StatusSys);
int OutStatusSys = zone.OutOfZoneStatusSys;
var outStatus = await App.Database.GetStatusBySysAsync(OutStatusSys);
var points = await App.Database.GetZonePointsAsync(zone.ZoneSys);
ZonePolygon zonePolygon = new ZonePolygon
{
ID = zone.ID
};
TKPolygon poly = new TKPolygon();
foreach (Model.Point point in points)
{
poly.Coordinates.Add(new Position(point.Latitude, point.Longitude));
}
poly.Color = Color.FromHex(status.ColorCode);
poly.StrokeColor = Color.Firebrick;
poly.StrokeWidth = 5f;
zonePolygon.Zpolygon = poly;
_polygons.Add(poly);
ZonePolygons.Add(zonePolygon);
return zonePolygon;
}
I am using this code from a C# application to find a tab in Google Chrome:
Process[] procsChrome = Process.GetProcessesByName("chrome");
foreach (Process chrome in procsChrome)
{
// the chrome process must have a window
if (chrome.MainWindowHandle == IntPtr.Zero)
{
continue;
}
AutomationElement root = AutomationElement.FromHandle(chrome.MainWindowHandle);
/*
Condition condNewTab = new PropertyCondition(AutomationElement.NameProperty, "Nueva pestaƱa");
AutomationElement elmNewTab = root.FindFirst(TreeScope.Descendants, condNewTab);
// get the tabstrip by getting the parent of the 'new tab' button
TreeWalker treewalker = TreeWalker.ControlViewWalker;
AutomationElement elmTabStrip = treewalker.GetParent(elmNewTab);
*/
// loop through all the tabs and get the names which is the page title
Condition condTabItem = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem);
foreach (AutomationElement tabitem in root.FindAll(TreeScope.Descendants, condTabItem))
{
Console.WriteLine(tabitem.Current.Name);
// I NEED TO ACTIVATE THE TAB HERE
break;
}
Condition condUrl = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit);
foreach (AutomationElement edit in root.FindAll(TreeScope.Descendants, condUrl))
{
string value = ((System.Windows.Automation.ValuePattern)edit.GetCurrentPattern(ValuePattern.Pattern)).Current.Value;
Console.WriteLine(value);
}
}
I need to select certain tab item using UI Automation. How can I do it?
For those desperate souls, still searching for an answer. Here is my method, based solely on UI Automation API, without focusing windows and sending click events or hotkeys. To use the code below you need to use interop reference for UIAutomationCore.dll as described by Guy Barker.
Process[] allChromeProcesses = Process.GetProcessesByName("chrome");
Process[] mainChromes = allChromeProcesses.Where(p => !String.IsNullOrEmpty(p.MainWindowTitle)).ToArray();
//...
//Here you need to check if you have found correct chrome instance
//...
var uiaClassObject = new CUIAutomation();
IUIAutomationElement chromeMainUIAElement = uiaClassObject.ElementFromHandle(mainChromes[0].MainWindowHandle);
//UIA_ControlTypePropertyId =30003, UIA_TabItemControlTypeId = 50019
IUIAutomationCondition chromeTabCondition = uiaClassObject.CreatePropertyCondition(30003, 50019);
var chromeTabCollection = chromeMainUIAElement.FindAll(TreeScope.TreeScope_Descendants, chromeTabCondition);
//UIA_LegacyIAccessiblePatternId = 10018, 0 -> Number of Chrome tab you want to activate
var lp = chromeTabCollection.GetElement(0).GetCurrentPattern(10018) as IUIAutomationLegacyIAccessiblePattern;
lp.DoDefaultAction();
The only thing you need to remember is that searching of tabs for minimized Chrome window is impossible.
I needed to solve similar problem. Since Chrome doesn't fully implement Windows Automation features, it has to be implemented differently.
Thanks to this GitHub project I was able to activate the correct Chrome tab. The trick is to press Ctrl+tab index to activate the tab in the case its position is between 1 and 8 (9 switches to the last tab, see Chromebook keyboard shortcuts). For tabs appearing further in the collection Ctrl+Tab is pressed repeatedly until the desired tab is reached.
However, it is not that easy, since sometimes the tabs can appear in the UI automation collection out of order. I have fixed this by calling the TryGetClickablePoint method for each tab and sorting the tabs by the X coordinate of the point returned.
bool ActivateChromeTab(string title)
{
Process[] procsChrome = Process.GetProcessesByName("chrome");
foreach (Process proc in procsChrome)
{
if (proc.MainWindowHandle == IntPtr.Zero)
{
continue;
}
AutomationElement root = AutomationElement.FromHandle(proc.MainWindowHandle);
Condition condNewTab = new PropertyCondition(AutomationElement.NameProperty, "New Tab");
AutomationElement elmNewTab = root.FindFirst(TreeScope.Descendants, condNewTab);
TreeWalker treewalker = TreeWalker.ControlViewWalker;
AutomationElement elmTabStrip = treewalker.GetParent(elmNewTab);
Condition condTabItem = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem);
var index = 0;
var tabItems = elmTabStrip.FindAll(TreeScope.Children, condTabItem);
var coll = new List<AutomationElement>();
foreach (AutomationElement element in tabItems)
{
coll.Add(element);
}
bool NameMatch(string name)
{
return name == title || name.StartsWith(title + " ");
}
// short-circuit the search when no searched string cannot be found
if (!coll.Any(e => NameMatch(e.Current.Name)))
{
continue;
}
var t = new Stopwatch();
t.Start();
var withPoints = coll.AsParallel().Select(e =>
{
var point = new System.Windows.Point(int.MaxValue, int.MaxValue);
if (e.TryGetClickablePoint(out point))
{
}
return new
{
Name = e.Current.Name,
Element = e,
Point = point
};
}).OrderBy(e => e.Point.X);
foreach (var tabItem in withPoints)
{
index++;
var name = tabItem.Name;
if (NameMatch(name))
{
SetForegroundWindow(proc.MainWindowHandle); // activate window
Select(index); // select tab
return true;
}
}
}
return false;
}
And the method to select the tab:
public void Select(int tabIndex)
{
const int maxShortcutNumber = 8;
if (tabIndex <= 0) { return; }
KeyDown(LCtrl);
if (tabIndex <= maxShortcutNumber)
{
KeyPress(GetKeyNumber(tabIndex));
}
else
{
KeyPress(GetKeyNumber(maxShortcutNumber));
for (var i = 0; i < tabIndex - maxShortcutNumber; i++)
{
i.Dump();
const int timeToDigestPreviousKeyPress = 75;
Thread.Sleep(timeToDigestPreviousKeyPress);
KeyPress(Tab);
}
}
KeyUp(LCtrl);
}
And keyboard handling methods (adapted from KeyboardSend class)
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
public static byte GetKeyNumber(int number)
{
if (number < 0 || number > 9)
throw new ApplicationException("Invalid number for key press.");
return (byte)(0x30 + number);
}
public static void KeyDown(byte vKey)
{
keybd_event(vKey, 0, KEYEVENTF_EXTENDEDKEY, 0);
}
public static void KeyUp(byte vKey)
{
keybd_event(vKey, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
public static void KeyPress(byte vKey)
{
KeyDown(vKey);
KeyUp(vKey);
}
public static byte LCtrl = 0xA2; //VK_LCONTROL
public static byte LWin = 0x5B; //VK_LWIN
public static byte LAlt = 0xA4; //VK_LMENU
public static byte Tab = 0x09; //VK_TAB
private const int KEYEVENTF_EXTENDEDKEY = 1;
private const int KEYEVENTF_KEYUP = 2;
I need to obtain the Maximum supported screen resolution of a monitor, not the current resolution which is easy. Any help would be appreciated.
Edit: This is the updated solution that worked for me.
public Size GetMaximumScreenSizePrimary()
{
var scope = new System.Management.ManagementScope();
var q = new System.Management.ObjectQuery("SELECT * FROM CIM_VideoControllerResolution");
using (var searcher = new System.Management.ManagementObjectSearcher(scope, q))
{
var results = searcher.Get();
UInt32 maxHResolution = 0;
UInt32 maxVResolution = 0;
foreach (var item in results)
{
if ((UInt32)item["HorizontalResolution"] > maxHResolution)
maxHResolution = (UInt32)item["HorizontalResolution"];
if ((UInt32)item["VerticalResolution"] > maxVResolution)
maxVResolution = (UInt32)item["VerticalResolution"];
}
log.Debug("Max Supported Resolution " + maxHResolution + "x" + maxVResolution);
}
return new Size(maxHResolution, maxVResolution);
}
Get the results from the Management Scope.
var scope = new System.Management.ManagementScope();
var q = new System.Management.ObjectQuery("SELECT * FROM CIM_VideoControllerResolution");
using (var searcher = new System.Management.ManagementObjectSearcher(scope, q))
{
var results = searcher.Get();
foreach (var item in results)
{
Console.WriteLine(item["Caption"]);
}
}
For more information about what information is available, refer to the CIM_VideoControllerResolution page.
Obtain newWidth & newHeight of screen resolution as below and use them where u required
Screen scr = Screen.PrimaryScreen;
int newWidth = scr.Bounds.Width;
int newHeight = scr.Bounds.Height;
Use primary screen property
http://msdn.microsoft.com/en-us/library/system.windows.forms.screen.primaryscreen.aspx
Regards.
I try to get the selected files of a folder which the user is using. I have the following code which is already running, but only on desktop files:
private string selectedFiles()
{
// get the handle of the desktop listview
IntPtr vHandle = WinApiWrapper.FindWindow("Progman", "Program Manager");
vHandle = WinApiWrapper.FindWindowEx(vHandle, IntPtr.Zero, "SHELLDLL_DefView", null);
vHandle = WinApiWrapper.FindWindowEx(vHandle, IntPtr.Zero, "SysListView32", "FolderView");
//IntPtr vHandle = WinApiWrapper.GetForegroundWindow();
//Get total count of the icons on the desktop
int vItemCount = WinApiWrapper.SendMessage(vHandle, WinApiWrapper.LVM_GETITEMCOUNT, 0, 0);
//MessageBox.Show(vItemCount.ToString());
uint vProcessId;
WinApiWrapper.GetWindowThreadProcessId(vHandle, out vProcessId);
IntPtr vProcess = WinApiWrapper.OpenProcess(WinApiWrapper.PROCESS_VM_OPERATION | WinApiWrapper.PROCESS_VM_READ |
WinApiWrapper.PROCESS_VM_WRITE, false, vProcessId);
IntPtr vPointer = WinApiWrapper.VirtualAllocEx(vProcess, IntPtr.Zero, 4096,
WinApiWrapper.MEM_RESERVE | WinApiWrapper.MEM_COMMIT, WinApiWrapper.PAGE_READWRITE);
try
{
for (int j = 0; j < vItemCount; j++)
{
byte[] vBuffer = new byte[256];
WinApiWrapper.LVITEM[] vItem = new WinApiWrapper.LVITEM[1];
vItem[0].mask = WinApiWrapper.LVIF_TEXT;
vItem[0].iItem = j;
vItem[0].iSubItem = 0;
vItem[0].cchTextMax = vBuffer.Length;
vItem[0].pszText = (IntPtr)((int)vPointer + Marshal.SizeOf(typeof(WinApiWrapper.LVITEM)));
uint vNumberOfBytesRead = 0;
WinApiWrapper.WriteProcessMemory(vProcess, vPointer,
Marshal.UnsafeAddrOfPinnedArrayElement(vItem, 0),
Marshal.SizeOf(typeof(WinApiWrapper.LVITEM)), ref vNumberOfBytesRead);
WinApiWrapper.SendMessage(vHandle, WinApiWrapper.LVM_GETITEMW, j, vPointer.ToInt32());
WinApiWrapper.ReadProcessMemory(vProcess,
(IntPtr)((int)vPointer + Marshal.SizeOf(typeof(WinApiWrapper.LVITEM))),
Marshal.UnsafeAddrOfPinnedArrayElement(vBuffer, 0),
vBuffer.Length, ref vNumberOfBytesRead);
string vText = Encoding.Unicode.GetString(vBuffer, 0,
(int)vNumberOfBytesRead);
string IconName = vText;
//Check if item is selected
var result = WinApiWrapper.SendMessage(vHandle, WinApiWrapper.LVM_GETITEMSTATE, j, (int)WinApiWrapper.LVIS_SELECTED);
if (result == WinApiWrapper.LVIS_SELECTED)
{
return vText;
}
}
}
finally
{
WinApiWrapper.VirtualFreeEx(vProcess, vPointer, 0, WinApiWrapper.MEM_RELEASE);
WinApiWrapper.CloseHandle(vProcess);
}
return String.Empty;
}
I tried to get the window handle with GetForegroundWindow() and then call the SHELLDLL_DefView without success.
So how can I change the first 3 rows to get me the handle of the current folder in use?
That's a lot of hacking to do something that is explicitly supported by the various shell objects and interfaces. Granted the documentation doesn't make it easily discoverable, but the functionality is there. Raymond Chen wrote a great article about using these interfaces. There doesn't appear to be a way to get the "current" folder, though I guess you could get the HWNDs and see if any is the foreground window.
thank you very much. You gave me the right direction. It is possible to get the selected files of a folder:
/// <summary>
/// Get the selected file of the active window
/// </summary>
/// <param name="handle">Handle of active window</param>
/// <returns></returns>
public String getSelectedFileOfActiveWindow(Int32 handle)
{
try
{
// Required ref: SHDocVw (Microsoft Internet Controls COM Object)
ShellWindows shellWindows = new SHDocVw.ShellWindows();
foreach (InternetExplorer window in shellWindows)
{
if (window.HWND == handle)
return ((Shell32.IShellFolderViewDual2)window.Document).FocusedItem.Path;
}
}
catch (Exception)
{
return null;
}
return null;
}