I am asking about Win32 Device Instance Path names. You see these types of paths in the Device Manager. An example device instance path name is ACPI\DLLK0706\3&11583659&0 for a keyboard.
Are there any restrictions on Device Instance Path names? For instance, I am not seeing any path names that exceed 255 characters in length, or use any non-ASCII characters, but are these restrictions real or just a coincidence?
Device Instance Path returned by PDO device when it handle IRP_MN_QUERY_ID. and exist several restrictions for length (must be less than MAX_DEVICE_ID_LEN characters long ) and can not use any non-ASCII characters (all must be in [0x20, 0x80) range and must not be ';' in string )
If a driver returns an ID with an illegal character, the system will
bug check. Characters with the following values are illegal in an ID
for this IRP:
Less than or equal to 0x20 (' ')
Greater than 0x7F
Equal to 0x2C (',')
A driver must conform to the following length restrictions for IDs:
Each hardware ID or compatible ID that a driver returns in this IRP must be less than MAX_DEVICE_ID_LEN characters long. This constant
currently has a value of 200 as defined in sdk\inc\cfgmgr32.h.
The container ID that a driver returns in this IRP must be formatted as a globally unique identifier (GUID), and must be
MAX_GUID_STRING_LEN characters, which includes the null terminator.
If a bus driver supplies globally unique instance IDs for its child devices (that is, the driver sets DEVICE_CAPABILITIES.UniqueID for
the devices), then the combination of device ID plus instance ID must
be less than (MAX_DEVICE_ID_LEN - 1) characters. The operating
system requires the additional character for a path separator.
If a bus driver does not supply globally unique instance IDs for its child devices, then the combination of device ID plus instance
ID must be less than (MAX_DEVICE_ID_LEN - 28). The value of
this equation is currently 172.
The Debug API reports DLL load events through a LOAD_DLL_DEBUG_INFO event. One of the structure's data members optionally holds the DLL's file name (lpImageName).
The character encoding of this field is described as:
If fUnicode is a nonzero value, the name string is Unicode; otherwise, it is ANSI.
Unicode presumably means UTF-16. Though it's unclear which codepage to use to interpret the ANSI encoding. There are multiple potential contenders (e.g. the originating process' default codepage, the system's codepage, the receiving process' default codepage, the receiving thread's current codepage, etc.).
Which codepage is it?
initially the debug event comes in the form DBGUI_WAIT_STATE_CHANGE
if use WaitForDebugEvent[Ex] api - it internally convert DBGUI_WAIT_STATE_CHANGE to DEBUG_EVENT by using DbgUiConvertStateChangeStructure[Ex]
when section (file mapping in win32 terms) created with SEC_IMAGE mapped in process, which is being debugged, the DbgLoadDllStateChange message send to debugger. DbgUiConvertStateChangeStructure[Ex] convert it to LOAD_DLL_DEBUG_INFO
note that original DBGKM_LOAD_DLL not containing any info about are in ansi or unicode was NamePointer. this is "unknown". the DbgUiConvertStateChangeStructure[Ex] always hard-code fUnicode = TRUE. this string, if exist, always in unicode.
This member is strictly optional. Debuggers must be prepared to handle
the case where lpImageName is NULL or *lpImageName (in the address
space of the process being debugged) is NULL. Specifically, the system
will never provide an image name for a create process event, and it
will not likely pass an image name for the first DLL event. The system
will also never provide this information in the case of debugging
events that originate from a call to the DebugActiveProcess function.
note, that lpImageName is pointer to pointer of a string (WCHAR** lpImageName can be say). in current implementation - this is always point to NT_TIB.ArbitraryUserPointer (not containing value of ArbitraryUserPointer but address of ArbitraryUserPointer)
formally can say lpImageName = &ptib->ArbitraryUserPointer where NT_TIB* ptib.
so lpImageName by self never 0, but *lpImageName (of course in target process address space) can be 0. when LdrLoadDll (or LoadLibrary) load dll, before map image section (call to ZwMapViewOfSection) set ArbitraryUserPointer to unicode string passed to LdrLoadDll as is. and restore original value of ArbitraryUserPointer after this. in case image name for a create process event, and image name for the first DLL (ntdll) here (in ArbitraryUserPointer 0) also it of course not valid when we receive debug events latter (case of DebugActiveProcess). so use lpImageName not reliable.
also interesing that in case load and unload image section (this is not always mean dll load/unload) (dwProcessId, dwThreadId) not of process/thread in which the debugging event occurred, but process/thread which call ZwMapViewOfSection or ZwUnmapViewOfSection. this is in general case different things, because possible map/unmap section in another process. however this is rarely case, but many debuggers (including windbg and from msvc) wrong handle this case and hung on it
I am using WIA2.0 on VB6.
I could do scanning without anyissues..
But, the problem is i could not figure out the number of pages scanned when it's ADF.
I could see something like this in msdn.
WIA_DPS_ENDORSER_STRING with a token as
$PAGE_COUNT$ The number of pages transferred.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms630195(v=vs.85).aspx
But, i don't know how to access this in VB6.
Any help would be appriciated.
Thanks.
-Dinakaran.AS
As far as I can tell this count is probably strictly local to the scanner itself when it has an endorser printer. It may even be a "hardware" counter much like photocopier counters. It probably can only be reset using a physical key or administrative password at the scanner to unlock and reset it. Looks as if it is meant for auditing purposes.
WIA_DPS_ENDORSER_CHARACTERS (ScannerDeviceEndorserCharacters)
Contains all the valid characters that an application can use to
create valid endorser strings. An endorser is a printer installed on a
scanner that imprints a text message on every page scanned. The
minidriver should validate the setting of the WIA_DPS_ENDORSER_STRING
property against the valid character set in this property. The
minidriver creates and maintains this property.
WIA_DPS_ENDORSER_STRING (ScannerDeviceEndorserString)
Contains a string that is to be endorsed (in other words, printed) on
each page that the minidriver scans. An application sets this property
using the valid character set that is reported in the
WIA_DPS_ENDORSER_CHARACTERS property. The minidriver should endorse
documents only if a string is set in this property. An empty string
means that the endorser functionality is disabled.
Then we have:
WIA_IPS_PAGES (ScannerPicturePages)
Note: This property is supported only by Windows Vista and later.
Contains the current number of pages to be acquired from an automatic
document feeder. The minidriver creates and maintains this property.
Type: VT_I4; Access: Read/Write; Valid values: WIA_PROP_RANGE This is
zero through the maximum number of pages that the scanner can scan.
The value is ALL_PAGES (= 0) if the scanner can scan continuously.
An application reads this property to determine the document feeder's
page capacity. The application also sets this property to the number
of pages it is going to scan.
I'm writing a very long registry Key name (it's a list of programs for a combined uninstall) and I think it's too big.
What's the max size the key can be (in characters) ?
(The smallest maximum among Win xp, vista, 7 since it'll need to work on all of them)
Key Name: 255 characters
Value name: 16,383 characters
Value: Available memory (latest format)
or 1 MB (standard format)
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724872%28v=vs.85%29.aspx
According to this support article, it is 255 characters.
here's a key that's longer than 255:
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\DeviceClasses{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}##?#STORAGE#VOLUME#_??_USBSTOR#DISK&VEN_LEXAR&PROD_USB_FLASH_DRIVE&REV_1100#AANL1B891R5GCDV6&0#{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}#
I found this when I was writing a tool to search all keys in the registry. I created a buffer that was 256 which caused a stack corruption exception.
When I tried to view this key using regedit I noticed it shows an arrow indicating there are subkeys but won't respond when clicked on. I only guess at the final '#' key because other keys in that area end with it.
When I doubled the buffer everything went smoothly.
I have come up against this problem a few times at inopportune moments:
Trying to work on open source Java projects with deep paths
Storing deep Fitnesse wiki trees in source control
An error trying to use Bazaar to import my source control tree
Why does this limit exist?
Why hasn't it been removed yet?
How do you cope with the path limit?
And no, switching to Linux or Mac OS X is not a valid answer to this question ;)
Quoting this article https://learn.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
Maximum Path Length Limitation
In the Windows API (with some exceptions discussed in the following paragraphs), the maximum length for a path is MAX_PATH, which is defined as 260 characters. A local path is structured in the following order: drive letter, colon, backslash, name components separated by backslashes, and a terminating null character. For example, the maximum path on drive D is "D:\some 256-character path string<NUL>" where "<NUL>" represents the invisible terminating null character for the current system codepage. (The characters < > are used here for visual clarity and cannot be part of a valid path string.)
Now we see that it is 1+2+256+1 or [drive][:\][path][null] = 260. One could assume that 256 is a reasonable fixed string length from the DOS days. And going back to the DOS APIs we realize that the system tracked the current path per drive, and we have 26 (32 with symbols) maximum drives (and current directories).
The INT 0x21 AH=0x47 says “This function returns the path description without the drive letter and the initial backslash.” So we see that the system stores the CWD as a pair (drive, path) and you ask for the path by specifying the drive (1=A, 2=B, …), if you specify a 0 then it assumes the path for the drive returned by INT 0x21 AH=0x15 AL=0x19. So now we know why it is 260 and not 256, because those 4 bytes are not stored in the path string.
Why a 256 byte path string, because 640K is enough RAM.
This is not strictly true as the NTFS filesystem supports paths up to 32k characters. You can use the win32 api and "\\?\" prefix the path to use greater than 260 characters.
A detailed explanation of long path from the .Net BCL team blog.
A small excerpt highlights the issue with long paths
Another concern is inconsistent behavior that would result by exposing long path support. Long paths with the \\?\ prefix can be used in most of the file-related Windows APIs, but not all Windows APIs. For example, LoadLibrary, which maps a module into the address of the calling process, fails if the file name is longer than MAX_PATH. So this means MoveFile will let you move a DLL to a location such that its path is longer than 260 characters, but when you try to load the DLL, it would fail. There are similar examples throughout the Windows APIs; some workarounds exist, but they are on a case-by-case basis.
The question is why does the limitation still exist. Surely modern Windows can increase the side of MAX_PATH to allow longer paths. Why has the limitation not been removed?
The reason it cannot be removed is that Windows promised it would never change.
Through API contract, Windows has guaranteed all applications that the standard file APIs will never return a path longer than 260 characters.
Consider the following correct code:
WIN32_FIND_DATA findData;
FindFirstFile("C:\Contoso\*", ref findData);
Windows guaranteed my program that it would populate my WIN32_FIND_DATA structure:
WIN32_FIND_DATA {
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
//...
TCHAR cFileName[MAX_PATH];
//..
}
My application didn't declare the value of the constant MAX_PATH, the Windows API did. My application used that defined value.
My structure is correctly defined, and only allocates 592 bytes total. That means that i am only able to receive a filename that is less than 260 characters. Windows promised me that if i wrote my application correctly, my application would continue to work in the future.
If Windows were to allow filenames longer than 260 characters then my existing application (which used the correct API correctly) would fail.
For anyone calling for Microsoft to change the MAX_PATH constant, they first need to ensure that no existing application fails. For example, i still own and use a Windows application that was written to run on Windows 3.11. It still runs on 64-bit Windows 10. That is what backwards compatibility gets you.
Microsoft did create a way to use the full 32,768 path names; but they had to create a new API contract to do it. For one, you should use the Shell API to enumerate files (as not all files exist on a hard drive or network share).
But they also have to not break existing user applications. The vast majority of applications do not use the shell api for file work. Everyone just calls FindFirstFile/FindNextFile and calls it a day.
From Windows 10. you can remove the limitation by modifying a registry key.
Tip Starting in Windows 10, version 1607, MAX_PATH limitations have been removed from common Win32 file and directory functions. However, you must opt-in to the new behavior.
A registry key allows you to enable or disable the new long path behavior. To enable long path behavior set the registry key at HKLM\SYSTEM\CurrentControlSet\Control\FileSystem LongPathsEnabled (Type: REG_DWORD). The key's value will be cached by the system (per process) after the first call to an affected Win32 file or directory function (list follows). The registry key will not be reloaded during the lifetime of the process. In order for all apps on the system to recognize the value of the key, a reboot might be required because some processes may have started before the key was set.
The registry key can also be controlled via Group Policy at Computer Configuration > Administrative Templates > System > Filesystem > Enable NTFS long paths.
You can also enable the new long path behavior per app via the manifest:
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
<ws2:longPathAware>true</ws2:longPathAware>
</windowsSettings>
</application>
You can mount a folder as a drive. From the command line, if you have a path C:\path\to\long\folder you can map it to drive letter X: using:
subst x: \path\to\long\folder
One way to cope with the path limit is to shorten path entries with symbolic links.
For example:
create a C:\p directory to keep short links to long paths
mklink /J C:\p\foo C:\Some\Crazy\Long\Path\foo
add C:\p\foo to your path instead of the long path
You can enable long path names using PowerShell:
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name LongPathsEnabled -Type DWord -Value 1
Another version is to use a Group Policy in Computer Configuration/Administrative Templates/System/Filesystem:
As to why this still exists - MS doesn't consider it a priority, and values backwards compatibility over advancing their OS (at least in this instance).
A workaround I use is to use the "short names" for the directories in the path, instead of their standard, human-readable versions. So e.g. for C:\Program Files\ I would use C:\PROGRA~1\ You can find the short name equivalents using dir /x.
As to how to cope with the path size limitation on Windows - using 7zip to pack (and unpack) your path-length sensitive files seems like a viable workaround. I've used it to transport several IDE installations (those Eclipse plugin paths, yikes!) and piles of autogenerated documentation and haven't had a single problem so far.
Not really sure how it evades the 260 char limit set by Windows (from a technical PoV), but hey, it works!
More details on their SourceForge page here:
"NTFS can actually support pathnames up to 32,000 characters in
length."
7-zip also support such long names.
But it's disabled in SFX code. Some users don't like long paths, since
they don't understand how to work with them. That is why I have
disabled it in SFX code.
and release notes:
9.32 alpha 2013-12-01
Improved support for file pathnames longer than 260 characters.
4.44 beta 2007-01-20
7-Zip now supports file pathnames longer than 260 characters.
IMPORTANT NOTE: For this to work properly, you'll need to specify the destination path in the 7zip "Extract" dialog directly, rather than dragging & dropping the files into the intended folder. Otherwise the "Temp" folder will be used as an interim cache and you'll bounce into the same 260 char limitation once Windows Explorer starts moving the files to their "final resting place". See the replies to this question for more information.
It does, and it is a default for some reason, but you could easily override it with this registry key:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem]
"LongPathsEnabled"=dword:00000001
See: https://blogs.msdn.microsoft.com/jeremykuhne/2016/07/30/net-4-6-2-and-long-paths-on-windows-10/
Another way to cope with it is to use Cygwin, depending on what do you want to do with the files (i.e. if Cygwin commands suit your needs)
For example it allows to copy, move or rename files that even Windows Explorer can't. Or of course deal with the contents of them like md5sum, grep, gzip, etc.
Also for programs that you are coding, you could link them to the Cygwin DLL and it would enable them to use long paths (I haven't tested this though)