FindSystemTimeZoneById.UTC is different than GetSystemTimeZones UTC? - c#

I've been searching high and low and can't find an answer to this. How come the TZIs are different??
I've done some digging on MSDN and seen this:
http://msdn.microsoft.com/en-us/library/system.timezoneinfo.findsystemtimezonebyid.aspx
Which explicitly states:
FindSystemTimeZoneById tries to match id to the subkey names of the HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Time Zones branch of the registry under Windows XP and Windows Vista. This branch does not necessarily contain a comprehensive list of time zone identifiers.
So I assume that means it's going to the registry every time?
But then this confuses the issue:
http://msdn.microsoft.com/en-us/library/system.timezoneinfo.utc.aspx
And says:
This is a built-in object; information about this TimeZoneInfo object is not retrieved from the registry.
So it appears my call to FindSystemTimeZoneById() is actually short circuiting and returning TimeZoneInfo.UTC, and not going to the registry at all! This is not idea though because I want the other version's DisplayName. What gives???

This quirk is explained because of the different ways you searched for the timezone. The top one with the full name came from the registry and started life by you using GetSystemTimeZones(), it enumerates the registry keys.
The bottom one was produced by FindSystemTimeZoneById(), it has a short-cut:
public static TimeZoneInfo FindSystemTimeZoneById(string id)
{
if (string.Compare(id, "UTC", StringComparison.OrdinalIgnoreCase) == 0)
{
return Utc;
}
// etc..
}
So you get the pre-baked one with the short name.

Related

Find directory rights (weird rights entries)

DirectorySecurity fs;
string FolderPath = "C:/Program Files";
fs = Directory.GetAccessControl(FolderPath, AccessControlSections.All);
foreach (FileSystemAccessRule fileSystemAccessRule in fs.GetAccessRules(true,true,typeof(System.Security.Principal.NTAccount)))
{
userNameDomain = fileSystemAccessRule.IdentityReference.Value;
userRights = fileSystemAccessRule.FileSystemRights.ToString();
string[] row = { userNameDomain, userRights };
var listViewItem = new ListViewItem(row);
lv_perm.Items.Add(listViewItem);
}
When doing this on "regular" files and folders (ex: C:/Users/Julien/Desktop/New folder), everything seems good:
ListView:
But, when I'm doing this on a folder with "special" rights (ex: C:/Program Files), I got duplicate IdentityReference.Value associated to strange numbers for rights:
Listview not good:
I don't have as many rights entries with strange numbers when I open the Permissions tab in C:/Program Files properties.
Maybe I'm doing something bad?
EDIT: From that page Here:
Using .NET you may think that determining which permissions are
assigned to a directory/file should be quite easy, as there is a
FileSystemRights Enum defined that seems to contain every possible
permission that a file/directory can have and calling
AccessRule.FileSystemRights returns a combination of these values.
However, you will soon come across some permissions where the value in
this property does not match any of the values in the FileSystemRights
Enum (I do wish they wouldn’t name some properties with the same name
as a Type but hey).
The end result of this is that for some files/directories you simply
cannot determine which permissions are assigned to them. If you do
AccessRule.FileSystemRights.ToString then for these values all you see
is a number rather than a description (e.g Modify, Delete, FullControl
etc). Common numbers you might see are:
-1610612736, –536805376, and 268435456
To work out what these permissions actually are, you need to look at
which bits are set when you treat that number as 32 separate bits
rather than as an Integer (as Integers are 32 bits long), and compare
them to this diagram:
msdn.microsoft.com/en-us/library/aa374896(v=vs.85).aspx
So for example, -1610612736 has the first bit and the third bit set,
which means it is GENERIC_READ combined with GENERIC_EXECUTE. So now
you can convert these generic permissions into the specific file
system permissions that they correspond to.
You can see which permissions each generic permission maps to here:
msdn.microsoft.com/en-us/library/aa364399.aspx. Just be aware
that STANDARD_RIGHTS_READ, STANDARD_RIGHTS_EXECUTE and
STANDARD_RIGHTS_WRITE are all the same thing (no idea why, seems
strange to me) and actually all equal the
FileSystemRights.ReadPermissions value.
So I think, because GetAccessRules are unable to group for ex:
NT SERVICE\TrustedInstaller FullControl
and
NT SERVICE\TrustedInstaller 268435456
He create 2 distinct entry.
I have to correct the FileSystemRights so they fit to the enumeration.
268435456 - FullControl
-536805376 - Modify, Synchronize
-1610612736 - ReadAndExecute, Synchronize
This issue exist since 2014. And still exist today.
You're not doing anything bad. The access mask is actually represented as an int internally (and on the file system), but the enum FileSystemRights is incomplete.
Therefore the visualizers and those functions converting a FileSystemRights value to a string will be at a loss and simply give you the numeric value (but as a string).
This means in order to make sense of them you'd have to inspect WinNT.h (from the Windows SDK) and look up all the possible access mask values - including generic ones - and provide a manual way of converting the numeric representation to a more human-readable string.
What you encountered are two distinct ACEs with different (but semantically equivalent) access masks, it seems. This is perfectly fine and happens in the wild (as your screenshot proves!). The .NET framework, however, chooses to ignore the issue.
If you look at the ACL with Powershell's Get-Acl or with icacls (a tool which has been on board since Windows 2000), you can see that there are potentially differences in how the individual ACEs are inherited or propagate down the filesystem hierarchy.
Another alternative would be to call the MapGenericMask() and have it perform the mapping. So when you would give it GENERIC_ALL (== 0x10000000) it would return 0x001f01ff, which corresponds to FileSystemRights.FullControl. This way you could "bend" the generic access mask into a form understood by the .NET framework.

How can I create or set JodaTime DateTime objects with/to maximum value?

I am translating some C#-code to Java, and have chosen JodaTime's DateTime class, to replace C#'s System.DateTime.
In C# the DateTime class has a Field called MaxValue and one called MinValue, which returns the biggest and smallest possible value that the DateTime object can hold.
I am trying to achieve the same with the JodaTime api. I have read some suggestions on other posts
This one: Java equivalent of .NET DateTime.MinValue, DateTime.Today answers how to make today's date in JodaTime, but when answering the second half of the question, about Min Values, they turn to Calendar and Date
Likewise I have seen suggestions about passing a maximized long value as constructor parameter, but it was criticized for being dependant on classes that might be changed in the future, and therefor might not be compatible or accurat after API updates.
So, is there a single positively correct way to do this? If not, is there a good way to achieve this?
Java 8 LocalDate has two values. LocalDate.MAX and LocalDate.MIN
LocalDate.MAX - The maximum supported LocalDate, '+999999999-12-31'. This could be used by an application as a "far future" date.
LocalDate.MIN - The minimum supported LocalDate, '-999999999-01-01'. This could be used by an application as a "far past" date.
Note: these do not translate to Long.MIN_VALUE or Long.MAX_VALUE.
I suggest using Java 8 if migrating from C# and how date/time works is important to you, as it has closures AND a new DateTime API based on JodaTime. This new DateTime API is the one you should be using if you are worried about the future of an API.
I think you can assume that Long.MIN_VALUE and Long.MAX_VALUE will never change as they are based on the definition of how a signed 64-bit values work. (How 64-bit values work was standardised before you were born, most likely) You can also assume that Date will not change as it hasn't change much since it was released and since it has been replaced there is even less reason to change it. In theory it might be deprecated, but in reality there is still too much code which uses it.
IMHO, I use long to represent a time in milli-seconds ala System.currentTimeMillis() and I use Long.MIN_VALUE and Long.MAX_VALUE.
If you are concerned about using good API and future proofing your code, I suggest you avoid using Calendar. Not that it is all bad, but there are good reasons to want to replace it.

GetSystemTimeZones missing GMT Standard Time

I have been trying to use TimeZoneInfo.GetSystemTimeZones in .net4 to replace our old method which uses COM to call into some MFC code. However, I've had to revert to the COM method because GetSystemTimeZones doesn't return all time zones. Being based in the UK and not including GMT Standard Time in our list of options is a problem.
When I look in the registry, I find that GMT Standard Time has a Dynamic DST subkey with no rules defined. I downloaded the .net4 source code and, in TimeZoneInfo.cs, GetSystemTimeZones eventually calls TryCreateAdjustmentRules which appears to return false if the Dynamic DST key has no FirstEntry or LastEntry defined.
//
// loop over all of the "<time_zone_name>\Dynamic DST" hive entries
//
// read FirstEntry {MinValue - (year1, 12, 31)}
// read MiddleEntry {(yearN, 1, 1) - (yearN, 12, 31)}
// read LastEntry {(yearN, 1, 1) - MaxValue }
// read the FirstEntry and LastEntry key values (ex: "1980", "2038")
Int32 first = (Int32)dynamicKey.GetValue(c_firstEntryValue, -1, RegistryValueOptions.None);
Int32 last = (Int32)dynamicKey.GetValue(c_lastEntryValue, -1, RegistryValueOptions.None);
if (first == -1 || last == -1 || first > last) {
rules = null;
return false;
}
As TryCreateAdjustmentRules returns false, TryGetTimeZoneByRegistryKey throws an InvalidTimeZoneException which means GMT Standard Time doesn't get added into the time zone collection. I've tried deleting the empty Dynamic DST subkeys but something adds them back in again (probably Windows Update).
I've done alot of searching but haven't seen anyone else report this problem. I'm not sure whether there is a GetSystemTimeZones fix or whether I can stop the empty Dynamic DST subkey appearing in the first place. Any ideas?
I'm guessing this is just a registry issue.
Something similar is outlined here for WinXP / Server 2003 SP1.
Please see if the following helps:
http://blogs.technet.com/b/dst2007/archive/2007/03/06/missing-time-zones-in-registry.aspx
My guess is you could export the entire registry Key from another machine, and apply it to your problematic box(es).
It turns out that the problem is with our COM object and not with the .NET code. The code to read the registry should only be reading but it mistakenly calls RegCreateKey to optimise multiple calls to the same registry branch.
When the COM object is registered (with admin rights) because of a new version, it loads the time zones and creates Dynamic DST for the local time zone which in my case is GMT/UTC.
Administrators, I guess this question should be marked for deletion.
After looking it over your problem and even running the code you provided in the comments to print out a list of Time Zones I am not able to get GMT to show up on my system. I am running Windows 7 Professional and selecting GMT is just not an option. I know that doesn't solve your problem and you - like a lot of other people - sound like you really need to get this to work with GMT.
However if at all possible, if you see a way to use UTC then I would check out these links:
Windows 7 Lack of Support for GMT
Converting UTC to GMT
Just another possible answer to your problem, is there anyway you can create a wrapper around the UTC values to display GMT? I ask because this problem doesn't seem like it is going to go away anytime soon. Even if you get it to work now - in the future it might break again. If I come up with a method for this I will update my answer.

Microsoft.Win32.Registry's GetValue Doesn't Use Default Value

I have a legacy (I didn't build it) application running on an x64 environment (Win7). I have a sneaking suspicion it was run on a 32-bit environment before.
Anyway, I see calls to Registry.GetValue(key, value, default).
It seems like the default value is ignored.
Check out this crazy code:
// Up above the sky, so high
using Microsoft.Win32;
// ...
string location = "HKEY_LOCAL_MACHINE\SOFTWARE\..."; // ...
// ...
string registryValue = (string)Registry.GetValue(location, "Uri", "http://localhost/");
if (string.isNullOrEmpty(registryValue) {
throw new Exception("What the ... ?!");
}
In a comparable example, the exception is seriously being thrown. (Actually, a null-reference exception appears despite the default value).
And I checked that I have the registry keys all the way up to the last level; they're all in my registry.
This works for someone, but not for me.
Is this a bug? What's going on here?
Most likely you are being caught out by registry redirection. You have a 32 bit process running on a 64 bit system. So HKLM\Software is redirected to HKLM\Software\Wow6432Node.
When the key does not exist, the Registry.GetValue returns null rather than the default value and so the exception is thrown.
If the name is not found in the specified key, returns a default value that you provide, or null if the specified key does not exist.
The default value is only returned if the specified key (that is the first parameter, i.e. location in your example) is found but a value with the specified name (the second parameter, "Uri" in your example) does not exist within that key.
If the key itself does not exist a null reference is returned.
This is fairly well documented on MSDN.
Probably the key you are looking for does not exist, probably because you are running on a 64-bit environment now which means that in case your application is a 32-bit process the HKLM\Software key gets mapped to HKLM\Software\Wow6432Node.
I know this is ancient, but in case anybody else stumbles upon this issue, I found an approach that works well for me. I'm using OpenSubKey, instead of GetValue.
RegistryKey key = Registry.CurrentUser.OpenSubKey(#"Software\MyProduct");
string data = key.GetValue("MyValue") as string;
The registry's terminology caused me some confusion. It is not simply a key -> value store, it is more like key -> value -> data.
I've no idea why but i solved using
My.Computer.Registry.CurrentUser.GetValue("Software\Mykey","Default Value")
instead of
My.Computer.Registry.GetValue("HKEY_CURRENT_USER\Software","Mykey","Default Value")
If the key doesn't exist the first example returns "Default Value", the second a null object!

Getting the Windows System Error Code title/description from its hex number

I'm messing around with some windows functions using p/invoke. Occasionally, I get an error code that is not ERROR_SUCCESS (such an odd name).
Is there a way to look these up within the program? Forexample, if I get error 1017. Can I tell the user
The system has attempted to load or
restore a file into the registry, but
the specified file is not in a
registry file format.
(ERROR_NOT_REGISTRY_FILE: 0x3F9)
Instead of
Error Code: 1017
I'm not sure if there's a niifty .NET wrapper, but you could call the FormatMessage API using P/Invoke.
See this answer for how it would normally be called from native code. Though the question refers to grabbing error codes from HRESULTs, the answer also applies for retreiving codes from the regular OS error codes coming from GetLastError/GetLastWin32Error).
EDIT: Thanks Malfist for pointing me to pinvoke.net, which includes alternative, managed API:
using System.ComponentModel;
string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message;
Console.WriteLine(errorMessage);
You could take the defines from winerror.h at Rensselaer Polytechnic Institute, and put them into an Enum:
public enum Win32ErrorCode : long
{
ERROR_SUCCESS = 0L,
NO_ERROR = 0L,
ERROR_INVALID_FUNCTION = 1L,
ERROR_FILE_NOT_FOUND = 2L,
ERROR_PATH_NOT_FOUND = 3L,
ERROR_TOO_MANY_OPEN_FILES = 4L,
ERROR_ACCESS_DENIED = 5L,
etc.
}
Then if your error code is in a variable error_code you would use :
Enum.GetName(typeof(Win32ErrorCode), error_code);
I landed on this page while in search of a managed alternative to calling FormatMessage through P/Invoke.
As others have said, there is no way to get those capitalized, underscored names, short of looking them up in winerror.h, which I have seen reproduced online in various places where I landed in the course of searching for information about resolving specific status codes. A quick Google search, for winerror.h, itself, uncovered a page, at Rensselaer Polytechnic Instutute, where someone has helpfully extracted the #define statements from it.
Looking at it gave me an idea; I think there may be a way to get there, working from the source code of winerror.h, which I have, as part of the Windows Platform SDK that ships with every recent version of Microsoft Visual Studio.
Right now, I am in the middle of sorting out a pressing issue in the .NET assembly that brought me to this page. Then, I'll see what I can cobble together; this kind of challenge is right up my alley, and somebody threw down a gauntlet.
Yes there's a function that does that but I don't remember what it is. In the mean time, you can use the error lookup tool (Tools->Error Lookup) to see what a particular code means from within Visual Studio.

Categories

Resources