Get user picture - delphi

OS: Win7x64 (2008,2008r2).
Lang: Delphi Xe2.
How to receive a full path (and file name) to the image "user account picture"?
How to set new picture?
Example on delphi plz.
Need:
...function GetCurrentUserPicture:string;
...function GetUserPicture(UserName:String):string;
...function SetUserNewPicture(UserName, ImageFileName:String):bool;

There is an undocumented function in shell32.dll. On Windows XP its ordinal is 233, on Windows Vista and 7 its ordinal is 261.
Its function prototype (from Airesoft) is:
HRESULT WINAPI SHGetUserPicturePath (
LPCWSTR pwszPicOrUserName,
DWORD sguppFlags,
LPWSTR pwszPicPath,
UINT picPathLen
)
You can use this function to retrieve the path where the user picture is stored. Just pass the user name as pwszPicOrUserName, the buffer where you want to store the path to the picture as pwszPicPath and the size of the buffer in chars as picPathLen. You can set sguppFlags to 0 or to any of the other flags posssible.
There is also a undocumented function which you can use in order to set the user picture of a user. Its ordinal is 234 on Windows XP, 262 on Windows Vista and Windows 7.
Its function prototype (from Airesoft) is:
HRESULT WINAPI SHSetUserPicturePath (
LPWSTR pwszAcctName,
DWORD reserved,
LPCWSTR pwszPictureFile
)
Pass the name of the user whose picture should be changed as pwszAcctName and the path to the picture you want to set as pwszPictureFile. Set reserved to 0. You have to initialize COM prior to calling this function.
According to Microsoft you should not rely on undocumented function because they can be removed or changed with any patch which is installed on Windows.

According to MSDN:
In Windows 7 or later, each user profile has an associated image
presented as a user tile. These tiles appear to users on the User
Accounts Control Panel item and its Manage Accounts subpage.. The
image files for the default Guest and default User accounts also
appear here if you have Administrator access rights.
....
The user's tile image is stored as
C:\Users\<username>\Local\Temp folder as .bmp. Any slash
characters () are converted to plus sign characters (+). For example,
DOMAIN\user is converted to DOMAIN+user.
I could not find an API to obtain the image and since the official documentation is calling out this implementation detail I think that means that you are safe to rely on it. That is I think this is a supported way to obtain the tile image.

Related

Is there a way to determine the Physical Sector Size for removable drives with file systems other than NTFS (like FAT16, exFAT...)?

I need a function to get the Physical Sector Size for all kind of system drives, in Win7 or higher.
This is the code that I've used until today, when I found out that it's not working with my external USB HDD (exFAT file system) and with my USB MP3 Player (FAT16). In these cases the function DeviceIoControl fails and I get the exception: "System Error. Code 50. The request is not suported". But it works very well with NTFS volumes.
function GetSectorSize(Drive:Char):DWORD;
var h:THandle;
junk:DWORD;
Query:STORAGE_PROPERTY_QUERY;
Alignment:STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR;
begin
result:=0;
h:=CreateFileW(PWideChar('\\.\'+UpperCase(Drive)+':'),0,FILE_SHARE_READ or FILE_SHARE_WRITE,nil,OPEN_EXISTING,0,0);
if h=INVALID_HANDLE_VALUE then RaiseLastOSError;
try
FillChar(Query,SizeOf(Query),0);
Query.PropertyId:=StorageAccessAlignmentProperty;
Query.QueryType:=PropertyStandardQuery;
if not DeviceIoControl(h,IOCTL_STORAGE_QUERY_PROPERTY,#Query,SizeOf(Query),#Alignment,SizeOf(Alignment),junk,nil) then RaiseLastOSError;
result:=Alignment.BytesPerPhysicalSector;
finally
CloseHandle(h);
end;
end;
According to MSDN:
File Buffering
Most current Windows APIs, such as IOCTL_DISK_GET_DRIVE_GEOMETRY and GetDiskFreeSpace, will return the logical sector size, but the physical sector size can be retrieved through the IOCTL_STORAGE_QUERY_PROPERTY control code, with the relevant information contained in the BytesPerPhysicalSector member in the STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR structure. For an example, see the sample code at STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR. Microsoft strongly recommends that developers align unbuffered I/O to the physical sector size as reported by the IOCTL_STORAGE_QUERY_PROPERTY control code to help ensure their applications are prepared for this sector size transition.
This same quote also appears in the following MSDN document:
Advanced format (4K) disk compatibility update
Which includes the following additional information:
The below list summarizes the new features delivered as part of Windows 8 and Windows Server 2012 to help improve customer and developer experience with large sector disks. More detailed description for each item follow.
...
•Provides a new API to query for physical sector size (FileFsSectorSizeInformation)
...
Here’s how you can query for the physical sector size:
Preferred method for Windows 8
With Windows 8, Microsoft has introduced a new API that enables developers to easily integrate 4K support within their apps. This new API supports even greater numbers of scenarios than the legacy method for Windows Vista and Windows 7 discussed below. This API enables these calling scenarios:
•Calling from an unprivileged app
•Calling to any valid file handle
•Calling to a file handle on a remote volume over SMB2
•Simplified programming model
The API is in the form of a new info class, FileFsSectorSizeInformation, with associated structure FILE_FS_SECTOR_SIZE_INFORMATION
FILE_FS_SECTOR_SIZE_INFORMATION structure
This information can be queried in either of the following ways:
•Call FltQueryVolumeInformation or ZwQueryVolumeInformationFile, passing FileFsSectorSizeInformation as the value of FileInformationClass and passing a caller-allocated, FILE_FS_SECTOR_SIZE_INFORMATION-structured buffer as the value of FileInformation.
•Create an IRP with major function code IRP_MJ_QUERY_VOLUME_INFORMATION.
•Call FsRtlGetSectorSizeInformation with a pointer to a FILE_FS_SECTOR_SIZE_INFORMATION-structured buffer. The FileSystemEffectivePhysicalBytesPerSectorForAtomicity member will not have a value initialized by the file system when this structure is returned from FsRtlGetSectorSizeInformation. A file system driver will typically call this function and then set its own value for FileSystemEffectivePhysicalBytesPerSectorForAtomicity.
Your principal error is that you try to get physical sector size from a volume handle rather than from that of an underlying physical device (\\.\PhysicalDriveX). Device's physical sector size doesn't depend on FS and shouldn't be confused with a logical sector size defined by FS properties.

Toggle show/hide system files from Delphi

Is there any built-in Delphi function to toggle between show and hide system files (protected operating system files) under Windows? Or maybe a registry entry in HKCU? Or maybe an API function able to do this?
I don't ask for a trick to show/hide this kind of files in my application, I need something to work even for Windows Explorer.
Operating systems : Win XP SP1+, Vista, 7
I don't mind even if I have to pass over an UAC notification.
This is a gross hack use it on your own risk
User Key: [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced]
Value Name: ShowSuperHidden
Data Type: REG_DWORD (DWORD Value)
Value Data: (1 = show hidden, 2 = do not show)
This registry value enables you to show or hide the system files.Thus those files with the attribute hidden

How to define Location and Display language from Windows Control panel

Delphi xe.
For Tab Administrative - Unicode lang
use GetSystemDefaultLangID
For Tab Formats -
use GetUserDefaultLangID
But what do I use for For Tab Location?
For Tab "Keyboard and Language"
for Vista and above: Getlocaleinfo with key LOCALE_CUSTOM_UI_DEFAULT
Function GetLocaleInformation(flag: integer): string;
var
pclca: array[0..20] of char;
begin
if (GetLocaleInfo(
//locale_system_default - Always identical values returns
LOCALE_CUSTOM_UI_DEFAULT // work only Vista-Win7, not Xp **
,flag,pclca,19) <= 0 ) then begin
pclca[0] := #0;
end;
Result := pclca;
end;
How do I define Location in Xp+Win7 and Display Language in Xp?
Can be a universal key for definition "Display Language" both for Xp and for Win7
How to receive the list of the established languages of the interface?
1.1 - How to get selected geographical location (geographic ID) ?
Use the GetUserGeoID function which returns the geographical location currently selected by user.
1.2 - How to get selected display language for Multilingual User Interface (MUI) in Windows XP ?
Use the GetUserDefaultUILanguage function which returns the language identifier currently selected by user.
2 - Is there an universal way how to get the selected display language supported since Windows XP till Windows 7 ?
Yes, it is. It's just the previously mentioned GetUserDefaultUILanguage function. There's a remark:
If the user UI language is part of a Language Interface Pack (LIP) and
corresponds to a supplemental locale, this function returns
LOCALE_CUSTOM_UI_DEFAULT.
It is supported since Windows 2000 and it should return selected display language even for Windows Vista above (LOCALE_CUSTOM_UI_DEFAULT).
3 - How to get the list of available user interface languages ?
Use the EnumUILanguages function. In Windows XP, it passes the language identifiers to the EnumUILanguagesProc callback function. Since Windows Vista you can even specify additional flags which supplies to pass the language names to that callback function or you can specify the filtering for licensed languages or for the languages allowed by the group policy.

Reading and writing DEVMODE.dmColor

I'm having trouble with the dmColor field fo the DEVMODE structure.
My default printer is a color printer, if I default output color of the printer properties through the control panel to black and white the DEVMODE.dmColor field always returns DMCOLOR_COLOR instead of DMCOLOR_MONOCHROME.
Even if I default my printer to a black and white only printer, DEVMODE.dmColor still always returns DMCOLOR_COLOR
All of the other DEVMODE fields such as dmDeviceName, dmCopies, dmDuplex, etc work fine. I have also tried to query DC_COLORDEVICE using the DeviceCapabilities function, microsoft documentation says it should return 1 if the device supports color, 0 if it does not and -1 if an error occured. This function is always returning -1 but the error code returned by GetLastError translates to "The operation completed successfully".
I'm running under windows Vista and I have specified DM_COLOR in DEVMODE.dmFields, does anyone know why this happens?
I've solved the issue, it seems like the color setting along with other settings are stored in the private drive data section below the DEVMODE structure. The size of the private data is stored in DEVMODE.dmDriverExtra. Copying the private driver data returned from the printer properties dialog box to the printing device has fixed the problem.
This might be a driver issue.
I'm having the exactly opposite on my HP 2840 color multifunctional: the XP specific drivers work well (allowing both color and monochrome), but they are not supported on Vista and higher.
From Vista on, you need to use the Generic HP drivers, which always return monochrome.
--jeroen

How to get Excel version and macro security level

Microsoft has recently broken our longtime (and officially recommended by them) code to read the version of Excel and its current omacro security level.
What used to work:
// Get the program associated with workbooks, e.g. "C:\Program Files\...\Excel.exe"
SHELLAPI.FindExecutable( 'OurWorkbook.xls', ...)
// Get the version of the .exe (from it's Properties...)
WINDOWS.GetFileVersionInfo()
// Use the version number to access the registry to determine the security level
// '...\software\microsoft\Office\' + VersionNumber + '.0\Excel\Security'
(I was always amused that the security level was for years in an insecure registry entry...)
In Office 2010, .xls files are now associated with "“Microsoft Application Virtualization DDE Launcher," or sftdde.exe. The version number of this exe is obviously not the version of Excel.
My question:
Other than actually launching Excel and querying it for version and security level (using OLE CreateOLEObject('Excel.Application')), is there a cleaner, faster, or more reliable way to do this that would work with all versions starting with Excel 2003?
Use
function GetExcelPath: string;
begin
result := '';
with TRegistry.Create do
try
RootKey := HKEY_LOCAL_MACHINE;
if OpenKey('SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\excel.exe', false) then
result := ReadString('Path') + 'excel.exe';
finally
Free;
end;
end;
to get the full file name of the excel.exe file. Then use GetFileVersionInfo as usual.
As far as I know, this approach will always work.
using OLE CreateOLEObject('Excel.Application'))
you can get installed Excel versions by using the same registry place, that this function uses.
Basically you have to clone a large part of that function registry code.
You can spy on that function call by tools like Microsoft Process Monitor too see exactly how does Windows look for installed Excel - and then to do it exactly the same way.
You have to open registry at HKEY_CLASSES_ROOT\ and enumerate all the branches, whose name starts with "Excel.Application."
For example at this my workstation I only have Excel 2013 installed, and that corresponds to HKEY_CLASSES_ROOT\Excel.Application.15
But on my another workstation I have Excel 2003 and Excel 2010 installed, testing different XLSX implementations in those two, so I have two registry keys.
HKEY_CLASSES_ROOT\Excel.Application.12
HKEY_CLASSES_ROOT\Excel.Application.14
So, you have to enumerate all those branches with that name, dot, and number.
Note: the key HKEY_CLASSES_ROOT\Excel.Application\CurVer would have name of "default" Excel, but what "default" means is ambiguous when several Excels are installed. You may take that default value, if you do not care, or you may decide upon your own idea what to choose, like if you want the maximum Excel version or minimum or something.
Then when for every specific excel branch you should read the default key of its CLSID sub-branch.
Like HKEY_CLASSES_ROOT\Excel.Application.15\CLSID has nil-named key equal to
{00024500-0000-0000-C000-000000000046} - fetch that index to string variable.
Then do a second search - go into a branch named like HKEY_CLASSES_ROOT\CLSID\{00024500-0000-0000-C000-000000000046}\LocalServer ( use the fetched index )
If that branch exists - fetch the nil-named "default key" value to get something like C:\PROGRA~1\MICROS~1\Office15\EXCEL.EXE /automation
The last result is the command line. It starts with a filename (non-quoted in this example, but may be in-quotes) and is followed by optional command line.
You do not need command line, so you have to extract initial commanlind, quoted or not.
Then you have to check if such an exe file exists. If it does - you may launch it, if not - check the registry for other Excel versions.

Resources