Is there any Win32/MFC API to get the CSIDL_LOCAL_APPDATA for any user that I want (not only the currently logged on one)? Let's say I have a list of users in the form "domain\user" and I want to get a list of their paths - is that possible?
You can get the SID for the user and then look it up under HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList and get the ProfileImagePath value.
Once you have this path, you can get CLSID_LOCAL_APPDATA for your user, convert the absolute path to a relative path to your profile and then append that relative path to the other user profile path.
However, keep in mind that this is relying on an undocumented registry key and can break in future versions of the OS. (Or, as Raymond Chan would say: "Now that you know how to do it, let me tell you why you shouldn't do it this way..." :-))
If you have a token representing the user, you can use the SHGetFolderPath or SHGetKnownFolderPath (on Vista and up). However, there are certain security restrictions and you should read up on MSDN for details.
SHGetFolderPath - http://msdn.microsoft.com/en-us/library/bb762181(VS.85).aspx
SHGetKnownFolderPath - http://msdn.microsoft.com/en-us/library/bb762188(VS.85).aspx
Related
TPath.GetTempFileName (which wraps the WinAPI GetTempFileName) replies "The directory name is invalid" when called from an application run by a user who is logged into a domain.
if they use a login that isn't using the domain, it works.
The customer having a problem is in another country and I am also not familiar with how a domain controller's configuration could be changed to avoid this problem.
I assume that since my application is the one that isn't working correctly, I should be getting a temporary file name in a different way.
"run as administrator" doesn't help.
I have directed them to ensure they have full control over the folders mentioned in the TEMP & TMP system environment variables and apparently they do but it still gives the same error.
My application as a Win32 Delphi desktop application but since Windows is the source of the error, I assume this information to be of limited usefulness.
Windows 10 is the OS.
TPath.GetTempFileName calls TPath.GetTempPath at the very beginning but does not check it before calling Winapi.Windows.GetTempFileName using the returned path.
It is very likely that the call to TPath.GetTempPath returns an empty or invalid path.
MSDN says:
The GetTempPath function checks for the existence of environment variables in the following order and uses the first path found:
The path specified by the TMP environment variable.
The path specified by the TEMP environment variable.
The path specified by the USERPROFILE environment variable.
The Windows directory.
If it would return the Windows directory, the call wouldn't fail with the said message. So, probably, there is a wrong path in one of those three environment variables.
Your customer should check these variables and validate them, in terms of existence.
You say, that the paths are "apparently" okay.
Experience taught me to doubt what customers say they checked... You could make a call to TPath.GetTempPath on your own before calling TPath.GetTempFileName to check if it exists. Alternatively you can call it in case of failure as part of handling the raised exception and add the path to the error message.
I've searched around online but can't find what I'm after. Basically, during an install, we fire off a separate executable that basically brute forces a few folders to be read/write enabled for the user group "EVERYONE".
Now, the person that wrote this never took into consideration system language. I had a call with a customer in France that kept failing installation because "EVERYONE" isn't what we would expect.
I'm after an API call to Windows that would return a security group name which would be "safe" to use in a localized environment. Essentially I'm looking to safely edit this code so instead of hardcoding in "EVERYONE", we call a function instead.
The fundamental mistake here is not so much the use of EVERYONE, but rather that the code is using names at all. Instead of using names you should use the well-known SIDs. In your case you need S-1-1-0.
I'm trying to save a CFPropertyList to a location in the user's home folder. Using the code below I'm getting errorCode = -10 (unknown error).
CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("~/testfile.txt"), kCFURLPOSIXPathStyle, false );
SInt32 errorCode;
Boolean status = CFURLWriteDataAndPropertiesToResource(fileURL, xmlData, NULL, &errorCode);
If I change the path to something like "/testfile.txt" without the '~' then everything works. How can one save a property list to the current user's home folder? Must one obtain the user's name first and include it in the path such as /users/toffler/testfile.txt?
With Foundation, you can call the NSHomeDirectory function to get the absolute path to the user's home directory. You can then use the path-manipulation methods of NSString or of NSURL, or the equivalent function for CFURL, to tack a sub-path onto that.
However, please don't put files into the top level of my Home folder unless I, as the user, tell you to.
If you want to save a file at the user's request, run a save panel, and then save it where the user told you to.
If you want to save a preferences file, you probably should be using NSUserDefaults or CFPreferences, instead of handling plists yourself.
If you have some other reason to save a user-specific file, it should generally go into either the chewable items folder, the Caches folder, or the Preferences folder. The two functions that I linked to are the easiest ways to access those two of those three folders; the harder way, and the only one that works on all three, is the FSFindFolder function. Unlike most of the Folder Manager, FSFindFolder is not deprecated and is available in 64-bit.
Updates from the year 2012
Nowadays, you should use URLs, not paths. NSFileManager has a method for getting a URL to a desired directory.
Stapling paths (or file URLs) together does not work in a sandboxed application, because you don't have authorization to access the path you just made up. You need to get the path (or URL) from a system API, whether it's NSFileManager, NSSavePanel, or something else.
For saving and restoring file references, use NSURL's security-scoped bookmarks feature.
NSUserDefaults and CFPreferences work as expected in a sandbox.
The Folder Manager is now fully deprecated as of 10.8.
Polluting the user's Home folder is still bad manners.
Automatic ~ expansion is a feature of the shell.
If you are using Cocoa/Foundation, you can use the NSString methods
- (NSString *)stringByAbbreviatingWithTildeInPath;
- (NSString *)stringByExpandingTildeInPath;
otherwise, you'll have to write some code yourself to do this. Getting the user's login name and constructing the path /Users/login-name/ is not the correct way to do this. (While most users will have their home directory here, some will not.)
I used to be able to launch a locally installed helper application by registering a given mime-type in the Windows registry. This enabled me to allow users to be able to click once on a link to the current install of our internal browser application. This worked fine in Internet Explorer 5 (most of the time) and Firefox but now does not work in Internet Explorer 7.
The filename passed to my shell/open/command is not the full physical path to the downloaded install package. The path parameter I am handed by IE is
"C:\Document and Settings\chq-tomc\Local Settings\Temporary Internet Files\
EIPortal_DEV_2_0_5_4[1].expd"
This unfortunately does not resolve to the physical file when calling FileExists() or when attempting to create a TFileStream object.
The physical path is missing the Internet Explorer hidden caching sub-directory for Temporary Internet Files of "Content.IE5\ALBKHO3Q" whose absolute path would be expressed as
"C:\Document and Settings\chq-tomc\Local Settings\Temporary Internet Files\
Content.IE5\ALBKHO3Q\EIPortal_DEV_2_0_5_4[1].expd"
Yes, the sub-directories are randomly generated by IE and that should not be a concern so long as IE passes the full path to my helper application, which it unfortunately is not doing.
Installation of the mime helper application is not a concern. It is installed/updated by a global login script for all 10,000+ users worldwide. The mime helper is only invoked when the user clicks on an internal web page with a link to an installation of our Desktop browser application. That install is served back with a mime-type of "application/x-expeditors". The registration of the ".expd" / "application/x-expeditors" mime-type looks like this.
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\.expd]
#="ExpeditorsInstaller"
"Content Type"="application/x-expeditors"
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\ExpeditorsInstaller]
"EditFlags"=hex:00,00,01,00
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\ExpeditorsInstaller\shell]
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\ExpeditorsInstaller\shell\open]
#=""
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\ExpeditorsInstaller\shell\open\command]
#="\"C:\\projects\\desktop2\\WebInstaller\\WebInstaller.exe\" \"%1\""
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\MIME\Database\Content Type\application/x-expeditors]
"Extension"=".expd"
I had considered enumerating all of a user's IE cache entries but I would be concerned with how long it may take to examine them all or that I may end up finding an older cache entry before the current entry I am looking for. However, the bracketed filename suffix "[n]" may be the unique key.
I have tried wininet method GetUrlCacheEntryInfo but that requires the URL, not the virtual path handed over by IE.
My hope is that there is a Shell function that given a virtual path will hand back the physical path.
I believe the sub-directories created by IE are randomly generated, so you won't be able guarantee that it will be named the same every time, and the problem I see with the registry method is that it only works when the file is still in the cache...emptying the cache would purge the file requiring yet another installation.
Would it not be better to install this helper into application data?
I'm not sure about this but perhaps this may lead you in the right direction: try using URL cache functions from the wininet DLL: FindFirstUrlCacheEntry, FindNextUrlCacheEntry, FindCloseUrlCache for enumeration and when you locate an entry whose local file name matches the given path maybe you can use RetrieveUrlCacheEntryFile to retrieve the file.
I am using a similar system with the X-Appl browser to display WAML web applications and it works perfectly. Maybe you should have a look at how they managed to do it.
It looks like iexplore is passing the shell namespace "name" of the file rather than the filesystem name.
I dont think there is a documented way to be passed a shell item id on the command line - explorer does it to itself, but there are marshaling considerations as shell item ids are (pointers to) binary data structures that are only valid in a single process.
What I might try doing is:
1. Call SHGetDesktopFolder which will return the root IShellFolder object of the shell namespace.
2. Call the IShellFolder::ParseDisplayName to turn the name you are given back into a shell item id list.
3. Try the IShellFolder::GetDisplayNameOF with the SHGDN_FORPARSING flag - which, frankly, feels like w'eve just gone in a complete circle and are back where we started. Because I think its this API thats ultimately responsible for returning the "wrong" filesystem relative path.
Some follow-up to close out this question.
Turned out the real issue was how I was creating the file handle using TFileStream. I changed to open with fmOpenRead or fmShareDenyWrite which solved what turned out to be a file locking issue.
srcFile := TFileStream.Create(physicalFilename, fmOpenRead or fmShareDenyWrite);
I'm looking for a way to find a the windows login associated with a specific group. I'm trying to add permissions to a tool that only allows names formatted like:
DOMAIN\USER
DOMAIN\GROUP
I have a list of users in active directory format that I need to add:
ou=group1;ou=group2;ou=group3
I have tried adding DOMAIN\Group1, but I get a 'user not found' error.
P.S. should also be noted that I'm not a Lan admin
Programatically or Manually?
Manually, i prefer AdExplorer, which is a nice Active directory Browser. You just connect to your domain controller and then you can look for the user and see all the details. Of course, you need permissions on the Domain Controller, not sure which though.
Programatically, it depends on your language of couse. On .net, the System.DirectoryServices Namespace is your friend. (I don't have any code examples here unfortunately)
For Active Directory, I'm not really an expert apart from how to query it, but here are two links I found useful:
http://www.computerperformance.co.uk/Logon/LDAP_attributes_active_directory.htm
http://en.wikipedia.org/wiki/Active_Directory (General stuff about the Structure of AD)
You need to go to the Active Directory Users Snap In after logging in as a domain admin on the machine:
Go to start --> run and type in mmc.
In the MMC console go to File -->
Add/Remove Snap-In Click Add Select
Active Directory Users and Computers and select Add.
Hit Close and then hit OK.
From here you can expand the domain tree and search (by right-clicking on the domain name).
You may not need special privileges to view the contents of the Active Directory domain, especially if you are logged in on that domain. It is worth a shot to see how far you can get.
When you search for someone, you can select the columns from View --> Choose Columns. This should help you search for the person or group you are looking for.
You do not need domain admin rights to look at the active directory. By default, any (authenticated?) user can read the information that you need from the directory.
If that wasn't the case, for example, a computer (which has an associated account as well) could not verify the account and password of its user.
You only need admin rights to change the contents of the directory.
I think it is possible to set more restricted permissions, but that's not likely the case.
OU is an Organizational Unit (sort of like a Subfolder in Explorer), not a Group, Hence group1, 2 and 3 are not actually groups.
You are looking for the DN Attribute, also called "distinguishedName". You can simply use DOMAIN\DN once you have that.
Edit: For groups, the CN (Common Name) could also work.
The full string from Active Directory normally looks like this:
cn=Username,cn=Users,dc=DomainName,dc=com
(Can be longer or shorter, but the important bit is that the "ou" part is worthless for what you're trying to achieve.
Well, AdExplorer runs on your Local Workstation (which is why I prefer it) and I believe that most users have read access to AD anyway because that's actually required for stuff to work, but I'm not sure about that.
Install the "Windows Support Tools" that is on the Windows Server CD (CD 1 if it's Windows 2003 R2). If your CD/DVD drive is D: then it will be in D:\Support\Tools\SuppTools.msi
This gives you a couple of additional tools to "get at" AD:
LDP.EXE - good for reading information in AD, but the UI kinda stinks.
ADSI Edit - another snap-in for MMC.EXE that you can both browse AD with and get to all those pesky AD attributes you're looking for.
You can install these tools on your local workstation and access AD from there without domain admin privileges. If you can log on to the domain, you can at least query/read AD for this information.
Thanks adeel825 & Michael Stum.
My problem is, though, i'm in a big corporation and do not have access to log in as the domain admin nor to view the active directory, so i guess my solution is to try and get that level of access.