Create multiple ramdisk KMDF - windows

I have a question about the KMDF Ramdisk sample of Microsoft.
How do create more than one ramdisk device? How will the PnP manager know to call EvtDeviceAdd and can I control how many times it is called?
WdfDeviceCreate() is used to create ramdisk device in RamDiskEvtDeviceAdd(), but I can not install more than one instance of this ramdisk driver.
NTSTATUS
RamDiskEvtDeviceAdd(
IN WDFDRIVER Driver,
IN PWDFDEVICE_INIT DeviceInit
) {
WDF_OBJECT_ATTRIBUTES deviceAttributes;
NTSTATUS status;
WDFDEVICE device;
WDF_OBJECT_ATTRIBUTES queueAttributes;
WDF_IO_QUEUE_CONFIG ioQueueConfig;
PDEVICE_EXTENSION pDeviceExtension;
PQUEUE_EXTENSION pQueueContext = NULL;
WDFQUEUE queue;
DECLARE_CONST_UNICODE_STRING(ntDeviceName, NT_DEVICE_NAME);
DECLARE_CONST_UNICODE_STRING(MY_SDDL_STRING, L"D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;WD)(A;;GA;;;RC)");
PAGED_CODE();
UNREFERENCED_PARAMETER(Driver);
// Set name
status = WdfDeviceInitAssignName(DeviceInit, &ntDeviceName);
if (!NT_SUCCESS(status)) {
return status;
}
// Set permission
status = WdfDeviceInitAssignSDDLString(DeviceInit, &MY_SDDL_STRING);
if (!NT_SUCCESS(status)) {
return status;
}
WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_DISK);
WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);
WdfDeviceInitSetExclusive(DeviceInit, FALSE);
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_EXTENSION);
deviceAttributes.EvtCleanupCallback = RamDiskEvtDeviceContextCleanup;
status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);
if (!NT_SUCCESS(status)) {
return status;
}
pDeviceExtension = DeviceGetExtension(device);
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE (
&ioQueueConfig,
WdfIoQueueDispatchSequential
);
ioQueueConfig.EvtIoDeviceControl = RamDiskEvtIoDeviceControl;
ioQueueConfig.EvtIoRead = RamDiskEvtIoRead;
ioQueueConfig.EvtIoWrite = RamDiskEvtIoWrite;
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&queueAttributes, QUEUE_EXTENSION);
__analysis_assume(ioQueueConfig.EvtIoStop != 0);
status = WdfIoQueueCreate( device,
&ioQueueConfig,
&queueAttributes,
&queue );
__analysis_assume(ioQueueConfig.EvtIoStop == 0);
if (!NT_SUCCESS(status)) {
return status;
}
// Context is the Queue handle
pQueueContext = QueueGetExtension(queue);
// Set the context for our default queue as our device extension.
pQueueContext->DeviceExtension = pDeviceExtension;
// Now do any RAM-Disk specific initialization
pDeviceExtension->DiskRegInfo.DriveLetter.Buffer =
(PWSTR) &pDeviceExtension->DriveLetterBuffer;
pDeviceExtension->DiskRegInfo.DriveLetter.MaximumLength =
sizeof(pDeviceExtension->DriveLetterBuffer);
// Get the disk parameters from the registry
RamDiskQueryDiskRegParameters(
WdfDriverGetRegistryPath(WdfDeviceGetDriver(device)),
&pDeviceExtension->DiskRegInfo
);
// Allocate memory for the disk image.
pDeviceExtension->DiskImage = ExAllocatePoolWithTag(
NonPagedPool,
pDeviceExtension->DiskRegInfo.DiskSize,
RAMDISK_TAG
);
if (pDeviceExtension->DiskImage) {
UNICODE_STRING deviceName;
UNICODE_STRING win32Name;
RamDiskFormatDisk(pDeviceExtension);
status = STATUS_SUCCESS;
// Now try to create a symbolic link for the drive letter.
RtlInitUnicodeString(&win32Name, DOS_DEVICE_NAME);
RtlInitUnicodeString(&deviceName, NT_DEVICE_NAME);
pDeviceExtension->SymbolicLink.Buffer = (PWSTR)
&pDeviceExtension->DosDeviceNameBuffer;
pDeviceExtension->SymbolicLink.MaximumLength =
sizeof(pDeviceExtension->DosDeviceNameBuffer);
pDeviceExtension->SymbolicLink.Length = win32Name.Length;
RtlCopyUnicodeString(&pDeviceExtension->SymbolicLink, &win32Name);
RtlAppendUnicodeStringToString(&pDeviceExtension->SymbolicLink,
&pDeviceExtension->DiskRegInfo.DriveLetter);
status = WdfDeviceCreateSymbolicLink(device,
&pDeviceExtension->SymbolicLink);
}
return status;
Please help me! Thanks

I understand this is an old post, but since there are no useful answers, I thought I might add my thoughts.
EvtDeviceAdd is called by the KMDF framework when a device matches a hardware ID that your INF supports. (https://msdn.microsoft.com/en-us/library/windows/hardware/ff541693%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396).
According to the VirtualVolume documentation (https://code.msdn.microsoft.com/windowshardware/VirtualVolume-83334efd), the only way to create a device is to call devcon install virtvol.inf virtvol.
You can make multiple RAMDisks by calling devcon install multiple times.

Related

How to get Device Instance path from Bus Relations in Win32 API

Is there a good way to get the Device Instance path(e.g: USB\VID_021D&PID_0C51&MI_00\6&192CE49&4&0000) from Bus Relations (e.g:{0.0.1.00000000}.{4234a4c6-3535-49d6-971c-76ce1f22521e}) ?
I realize some terms in Windows have aliases, by "Device Instance path" and "Bus Relations", I mean the two properties found in the device manager:
I have tried to get the Device Instance path from the PropertyStore
int getProperty(std::string& sampleID)
{
HRESULT hr = S_OK;
IMMDeviceEnumerator* pEnumerator = NULL;
//CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IMMDeviceEnumerator),
(void**)&pEnumerator);
if (hr != S_OK)
{
// error cleanup
return hr;
}
IMMDevice* pEndpoint = NULL;
std::wstring wSampleID(sampleID.begin(), sampleID.end());
hr = pEnumerator->GetDevice(wSampleID.c_str(), &pEndpoint);
if (hr != S_OK || pEndpoint == NULL)
{
// error cleanup
return hr;
}
if (!pEndpoint)
{
// error cleanup
return hr;
}
IPropertyStore* pProps = NULL;
hr = pEndpoint->OpenPropertyStore(
STGM_READ, &pProps);
PROPVARIANT varName;
// Initialize container for property value.
PropVariantInit(&varName);
hr = pProps->GetValue(
PKEY_AudioEndpoint_GUID, &varName);
if (hr != S_OK)
{
//error cleanup
return hr;
}
std::cout << varName.pwszVal << std::endl;
PropVariantClear(&varName);
SAFE_RELEASE(pProps)
SAFE_RELEASE(pEndpoint)
SAFE_RELEASE(pEnumerator);
return hr;
}
but there does not seem to be a property key to retrieve this piece of information for Audio Endpoint IMMDevice. Any suggestion is appreciated.
An example would be a headphone + microphone device which yields two
Bus Relation strings, one for headphone and the other for microphone.
My goal is to group the Bus Relations belonging to the same physical
device.
Bus Relations belonging to the same physical device have already been grouped and you can get it through "Bus relations" property of the same physical audio device (parent). You can find that via Device Manager (View -> Devices by connection) like this:
Is there a good way to get the Device Instance path(e.g:
USB\VID_021D&PID_0C51&MI_00\6&192CE49&4&0000) from Bus Relations
(e.g:{0.0.1.00000000}.{4234a4c6-3535-49d6-971c-76ce1f22521e}) ?
Although it is not clear that what grouped Bus relations will you use for. But you will find that not all (USB) devices have Device Instance path in this format: USB\VID_xxxx&PID_xxxx*. Take Microphone showed in above snapshot as an example, its Device Instance path like below, same with one of bus relations of its parent.

Developing iTunes like application in c#

I need to develop an application in c# that could automatically detect an iPhone when it is connected to the system and read a particular file for the iPhone file system. I basically want this file to be downloaded automatically from device to the PC. I used USBpcap tool that suggests that iTunes connects to phone using some XML format. Any help or insight greatly appreciated. Is there any documentation of Third party APIs that can get me started? There are some applications that can replicate iTunes functionality e.g Copytrans
Is there any protocol or APIs provided by Apple?
I have been digging the internet and found this link Layered communication for iPhone.
Also I am using the LibUsbDotNet libraries for communicating to the usb device(Example). Can any one suggest which EndPoints should be used.
It seems to me that I have to implement usbmuxd in windows application. It is a multilayer protocol. There must be some libraries that implement usbmuxd(I dont think I have to implement the protocol all by my self)
I dont have much idea about iTunes communication as well as USB communication. I am adding as much information as I can(of course with the things I come up with in my R&D). Any help is highly appreciated.
public static DateTime LastDataEventDate = DateTime.Now;
public static UsbDevice MyUsbDevice;
#region SET YOUR USB Vendor and Product ID!
public static UsbDeviceFinder MyUsbFinder = new UsbDeviceFinder(1452, 4768);
#endregion
private void LibUSB()
{
ErrorCode ec = ErrorCode.None;
try
{
// Find and open the usb device.
MyUsbDevice = UsbDevice.OpenUsbDevice(MyUsbFinder);
// If the device is open and ready
if (MyUsbDevice == null)
throw new Exception("Device Not Found.");
// If this is a "whole" usb device (libusb-win32, linux libusb)
// it will have an IUsbDevice interface. If not (WinUSB) the
// variable will be null indicating this is an interface of a
// device.
IUsbDevice wholeUsbDevice = MyUsbDevice as IUsbDevice;
if (!ReferenceEquals(wholeUsbDevice, null))
{
// This is a "whole" USB device. Before it can be used,
// the desired configuration and interface must be selected.
// Select config #1
wholeUsbDevice.SetConfiguration(1);
// Claim interface #0.
wholeUsbDevice.ClaimInterface(0);
}
// open read endpoint 1.
UsbEndpointReader reader = MyUsbDevice.OpenEndpointReader(ReadEndpointID.Ep03);
// open write endpoint 1.
UsbEndpointWriter writer = MyUsbDevice.OpenEndpointWriter(WriteEndpointID.Ep02);
int bytesWritten;
ec = writer.Write(usbmux_header.GetBytes(), 2000, out bytesWritten);
if (ec != ErrorCode.None)
throw new Exception(UsbDevice.LastErrorString);
byte[] readBuffer = new byte[1024];
while (ec == ErrorCode.None)
{
int bytesRead;
// If the device hasn't sent data in the last 100 milliseconds,
// a timeout error (ec = IoTimedOut) will occur.
ec = reader.Read(readBuffer, 10000, out bytesRead);
if (ec == ErrorCode.Win32Error)
throw new Exception("port not open");
if (bytesRead == 0)
throw new Exception("No more bytes!");
// Write that output to the console.
Console.Write(Encoding.Default.GetString(readBuffer, 0, bytesRead));
}
}
catch (Exception ex)
{
Console.WriteLine();
Console.WriteLine((ec != ErrorCode.None ? ec + ":" : String.Empty) + ex.Message);
}
finally
{
if (MyUsbDevice != null)
{
if (MyUsbDevice.IsOpen)
{
// If this is a "whole" usb device (libusb-win32, linux libusb-1.0)
// it exposes an IUsbDevice interface. If not (WinUSB) the
// 'wholeUsbDevice' variable will be null indicating this is
// an interface of a device; it does not require or support
// configuration and interface selection.
IUsbDevice wholeUsbDevice = MyUsbDevice as IUsbDevice;
if (!ReferenceEquals(wholeUsbDevice, null))
{
// Release interface #0.
wholeUsbDevice.ReleaseInterface(0);
}
MyUsbDevice.Close();
}
MyUsbDevice = null;
// Free usb resources
UsbDevice.Exit();
}
}
}
class usbmux_header
{
public static UInt32 length = 10; // length of message, including header
public static UInt32 reserved = 0; // always zero
public static UInt32 type = 3; // message type
public static UInt32 tag = 2; // responses to this query will echo back this tag
public static byte[] GetBytes()
{
byte[] lgth = BitConverter.GetBytes(length);
byte[] res = BitConverter.GetBytes(reserved);
byte[] tpe = BitConverter.GetBytes(type);
byte[] tg = BitConverter.GetBytes(tag);
byte[] retArray = new byte[16];
lgth.CopyTo(retArray, 0);
res.CopyTo(retArray, 4);
tpe.CopyTo(retArray, 8);
tg.CopyTo(retArray, 12);
return retArray;
}
};
I have been trying to send hello packet bytes to iPhone but I am not able to read any response from phone.
To play with ipod you can use SharePodLib
As I understand it, only one client can use the USB connection to iOS at one time. On both macOS and Windows, that one client is usbmux. That library multiplexes TCP connections with higher-level clients, including iTunes, Photos, and (on macOS) the open-source peertalk library.
So on Windows, you wouldn't want to implement your own usbmux, but rather a client that sits on top of that, analogous to peertalk. I haven't seen anything open-source that does this, but a number of developers have accomplished it with their own proprietary software.
If anybody else has pointers about using usbmux on Windows, I'd love to hear about it.
—Dave
You can use imobiledevice-net. It provides a C# API to connect to iOS devices using your PC.
For example, to list all iOS devices connected to your PC, you would run something like this:
ReadOnlyCollection<string> udids;
int count = 0;
var idevice = LibiMobileDevice.Instance.iDevice;
var lockdown = LibiMobileDevice.Instance.Lockdown;
var ret = idevice.idevice_get_device_list(out udids, ref count);
if (ret == iDeviceError.NoDevice)
{
// Not actually an error in our case
return;
}
ret.ThrowOnError();
// Get the device name
foreach (var udid in udids)
{
iDeviceHandle deviceHandle;
idevice.idevice_new(out deviceHandle, udid).ThrowOnError();
LockdownClientHandle lockdownHandle;
lockdown.lockdownd_client_new_with_handshake(deviceHandle, out lockdownHandle, "Quamotion").ThrowOnError();
string deviceName;
lockdown.lockdownd_get_device_name(lockdownHandle, out deviceName).ThrowOnError();
deviceHandle.Dispose();
lockdownHandle.Dispose();
}

Looking for a reliable mapping of Forms.Screen.DeviceName to Monitor EDID info

I'm developing an application which will display information derived from the EDID blocks (monitor model, ID, S/N, etc.) on a dialog on the corresponding monitor.
This code works for finding the EDID information for displays. It extracts the EDID information by enumerating the DISPLAY keys under HKLM\SYSTEM\CurrentControlSet\Enum\DISPLAY\[Monitor]\[PnPID]\Device Parameters\EDID.
Update: The above code is relying on "side effects" of PnP use of the registry. I am now using the SetupAPI to enumerate monitors, which correctly handles monitors being attached/removed (unlike the code from the link above.)
I am trying to correlate each Screen in Windows.Forms.Screen.AllScreens[] (\\.\DISPLAY1, \\.\DISPLAY2, etc.) with the entries returned from the above registry inspection.
Note: In the code block below, DisplayDetails.GetMonitorDetails() has now been replaced with more robust registry enumeration code using the SetupAPI, but the data returned is the same.
e.g.
private void Form1_Load(object sender, EventArgs e)
{
Console.WriteLine("Polling displays on {0}:", System.Environment.MachineName);
int i = 0;
foreach ( DisplayDetails dd in DisplayDetails.GetMonitorDetails())
{
Console.WriteLine( "Info: Model: {0}, MonitorID: {1}, PnPID: {2}, Serial#:{3}", dd.Model, dd.MonitorID, dd.PnPID, dd.SerialNumber );
Console.WriteLine( "Does this correlate to Screen: {0}?", Screen.AllScreens[i++].DeviceName );
}
}
Output:
Info: Model: DELL P2411H, MonitorID: DELA06E, PnPID: 5&2e2fefea&0&UID1078018, Serial#:F8NDP0C...PU
Does this correlate to Screen: \\.\DISPLAY1?
Info: Model: DELL P2411H, MonitorID: DELA06E, PnPID: 5&2e2fefea&0&UID1078019, Serial#:F8NDP0C...AU
Does this correlate to Screen: \\.\DISPLAY2?
Answer: NO
In testing, I've found these don't reliably correlate (I have a system in which the first display enumerated is \\.\DISPLAY2).
My Question:
Is there a way to reliably get the EDID information for a given Forms.Screen? I can get the EDID block, but have found no path to correlate this up to the UI top-level Form. Prompting the user is undesirable, as in my use case the two (or more) monitors will likely be the same model and resolution, and only differ by a few digits in the S/N.
I've looked for paths following the Forms.Screen API, Win32 EnumDisplay, other registry GUIDs (PnP and driver-related), but haven't found any promising paths.
I have also investigated the WMI Win32_DesktopMonitor API (Windows 7), however it doesn't appear to have any more information that would help me correlate it to the Windows.Forms.Screen.AllScreens[] entries.
I suspect if there is a way to do this, it's through the SetupAPI, however I haven't found it yet.
A method to resolve the GDI to SetupAPI is available in the EnumDisplayDevices API. If you pass in the EDD_GET_DEVICE_INTERFACE_NAME in for dwFlags, the monitor enumeration will return DeviceID information of the form:
Monitor 0 info:
DeviceName: \\.\DISPLAY1
MonitorInfo: Dell P2411H(Digital)
DeviceID: \\?\DISPLAY#DELA06E#5&2e2fefea&0&UID1078018#{e6f07b5f-ee97-4a90-b076-3
3f57bf4eaa7}
Monitor 1 info:
DeviceName: \\.\DISPLAY2
MonitorInfo: Dell P2411H(Digital)
DeviceID: \\?\DISPLAY#DELA06E#5&2e2fefea&0&UID1078019#{e6f07b5f-ee97-4a90-b076-3
3f57bf4eaa7}
The DeviceID fields now match the results from the didd.DevicePath, as retrieved in the C# fragment below:
Guid MonitorGUID = new Guid(Win32.GUID_DEVINTERFACE_MONITOR);
// We start at the "root" of the device tree and look for all
// devices that match the interface GUID of a monitor
IntPtr h = Win32.SetupDiGetClassDevs(ref MonitorGUID, IntPtr.Zero, IntPtr.Zero, (uint)(Win32.DIGCF_PRESENT | Win32.DIGCF_DEVICEINTERFACE));
if (h.ToInt64() != Win32.INVALID_HANDLE_VALUE)
{
bool Success = true;
uint i = 0;
while (Success)
{
// create a Device Interface Data structure
Win32.SP_DEVICE_INTERFACE_DATA dia = new Win32.SP_DEVICE_INTERFACE_DATA();
dia.cbSize = (uint)Marshal.SizeOf(dia);
// start the enumeration
Success = Win32.SetupDiEnumDeviceInterfaces(h, IntPtr.Zero, ref MonitorGUID, i, ref dia);
if (Success)
{
// build a DevInfo Data structure
Win32.SP_DEVINFO_DATA da = new Win32.SP_DEVINFO_DATA();
da.cbSize = (uint)Marshal.SizeOf(da);
// build a Device Interface Detail Data structure
Win32.SP_DEVICE_INTERFACE_DETAIL_DATA didd = new Win32.SP_DEVICE_INTERFACE_DETAIL_DATA();
didd.cbSize = (uint)(4 + Marshal.SystemDefaultCharSize); // trust me :)
// now we can get some more detailed information
uint nRequiredSize = 0;
uint nBytes = Win32.BUFFER_SIZE;
if (Win32.SetupDiGetDeviceInterfaceDetail(h, ref dia, ref didd, nBytes, out nRequiredSize, ref da))
{
// Now we get the InstanceID
IntPtr ptrInstanceBuf = Marshal.AllocHGlobal((int)nBytes);
Win32.CM_Get_Device_ID(da.DevInst, ptrInstanceBuf, (int)nBytes, 0);
string InstanceID = Marshal.PtrToStringAuto(ptrInstanceBuf);
Console.WriteLine("InstanceID: {0}", InstanceID );
Marshal.FreeHGlobal(ptrInstanceBuf);
Console.WriteLine("DevicePath: {0}", didd.DevicePath );
}
i++;
}
}
}
Win32.SetupDiDestroyDeviceInfoList(h);
}
Sample Output:
InstanceID: DISPLAY\DELA06E\5&2E2FEFEA&0&UID1078018
DevicePath: \\?\display#dela06e#5&2e2fefea&0&uid1078018#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
The DeviceName from the original EnumDisplayDevices matches the Forms.Screen.DeviceName property.
With these two pieces of information, it is now possible to read the EDID block during the SetupDIEnumDeviceInterface traversal using a fragment like the below:
private static byte[] GetMonitorEDID(IntPtr pDevInfoSet, SP_DEVINFO_DATA deviceInfoData)
{
IntPtr hDeviceRegistryKey = SetupDiOpenDevRegKey(pDevInfoSet, ref deviceInfoData,
DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
if (hDeviceRegistryKey == IntPtr.Zero)
{
throw new Exception("Failed to open a registry key for device-specific configuration information");
}
IntPtr ptrBuff = Marshal.AllocHGlobal((int)256);
try
{
RegistryValueKind lpRegKeyType = RegistryValueKind.Binary;
int length = 256;
uint result = RegQueryValueEx(hDeviceRegistryKey, "EDID", 0, ref lpRegKeyType, ptrBuff, ref length);
if (result != 0)
{
throw new Exception("Can not read registry value EDID for device " + deviceInfoData.ClassGuid);
}
}
finally
{
RegCloseKey(hDeviceRegistryKey);
}
byte[] edidBlock = new byte[256];
Marshal.Copy(ptrBuff, edidBlock, 0, 256);
Marshal.FreeHGlobal(ptrBuff);
return edidBlock;
}
Which, finally, can be parsed for the VESA descriptor blocks, as shown in the DisplayDetails.GetMonitorDetails() method in this code.

Free VRam on OS X

does anyone know how to get the free(!) vram on os x?
I know that you can query for a registry entry:
typeCode = IORegistryEntrySearchCFProperty(dspPort,kIOServicePlane,CFSTR(kIOFBMemorySizeKey),
kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents);
but this will return ALL vram, not the free vram. Under windows you can query for free VRAM using directshow
mDDrawResult = DirectDrawCreate(NULL, &mDDraw, NULL);
mDDrawResult = mDDraw->QueryInterface(IID_IDirectDraw2, (LPVOID *)&mDDraw2);
DDSCAPS ddscaps;
DWORD totalmem, freemem;
ddscaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
mDDrawResult = mDDraw2->GetAvailableVidMem(&ddscaps, &totalmem, &freemem);
Ugly, but it works. Anyone knows the osx way?
Best
Wendy
answering myself so others may use this:
#include <IOKit/graphics/IOGraphicsLib.h>
size_t currentFreeVRAM()
{
kern_return_t krc;
mach_port_t masterPort;
krc = IOMasterPort(bootstrap_port, &masterPort);
if (krc == KERN_SUCCESS)
{
CFMutableDictionaryRef pattern = IOServiceMatching(kIOAcceleratorClassName);
//CFShow(pattern);
io_iterator_t deviceIterator;
krc = IOServiceGetMatchingServices(masterPort, pattern, &deviceIterator);
if (krc == KERN_SUCCESS)
{
io_object_t object;
while ((object = IOIteratorNext(deviceIterator)))
{
CFMutableDictionaryRef properties = NULL;
krc = IORegistryEntryCreateCFProperties(object, &properties, kCFAllocatorDefault, (IOOptionBits)0);
if (krc == KERN_SUCCESS)
{
CFMutableDictionaryRef perf_properties = (CFMutableDictionaryRef) CFDictionaryGetValue( properties, CFSTR("PerformanceStatistics") );
//CFShow(perf_properties);
// look for a number of keys (this is mostly reverse engineering and best-guess effort)
const void* free_vram_number = CFDictionaryGetValue(perf_properties, CFSTR("vramFreeBytes"));
if (free_vram_number)
{
ssize_t vramFreeBytes;
CFNumberGetValue( (CFNumberRef) free_vram_number, kCFNumberSInt64Type, &vramFreeBytes);
return vramFreeBytes;
}
}
if (properties) CFRelease(properties);
IOObjectRelease(object);
}
IOObjectRelease(deviceIterator);
}
}
return 0; // when we come here, this is a fail
}
i am somewhat surprised that this query takes almost 3 msec ..
be aware that there may be more than one accelerator on your system ( eg. macbook )
so be sure you select the proper one for the query

Finding the Recycle Bin on a local NTFS drive

I'm trying to write some simple code that will return the directory for the recycle bin on a local drive. Seems like it would be simple -- should be a thousand answers on Google. Haven't found one yet :(
I HAVE found that FAT and NTFS drives have different base names (RECYCLED and RECYCLER). I've found that 'the' recycle bin is a virtual folder that combines the recycle bins of all drives on the machine.
What I haven't found is a way to find C: drive's recycle bin directory -- even on a Vietnamese (or any other non-English) machine. (No posts I can find indicate whether "RECYCLER" gets internationalized or not)
Can anyone point me to a definitive answer?
Thanks
UPDATE: Aware of CSIDL_BITBUCKET and the functions that use it. From everything I've read though, it points to a virtual directory which is the union of all deleted files by that user on all drives. Looking for the physical recycle bin directory (on my Vista it appears to be C:\$Recycle.Bin as far as I can tell)
Using Raymond Chen's advice, and someone else's technique (can't remember where I found it) I present a function that will find the Recycle Bin directory on a drive. The function cycles through the directories in the root directory looking at hidden and/or system directories. When it finds one, it checks the child subdirectories looking for one that has CLSID_Recycle Bin.
Note that I've included two GetFolderCLSID functions below. Raymond Chen's is the simpler one, but it doesn't work on Windows 2000. The other implementation is longer, but appears to work everywhere.
Call like: CString recycleDir = FindRecycleBinOnDrive(L"C:\");
CString FindRecycleBinOnDrive(LPCWSTR path)
{
CString search;
search.Format(L"%c:\\*", path[0]);
WIN32_FIND_DATA fd = {0};
HANDLE fHandle = FindFirstFile(search, &fd);
while(INVALID_HANDLE_VALUE != fHandle)
{
if(FILE_ATTRIBUTE_DIRECTORY == (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) //only check directories
{
if(0 != (fd.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN))) //only check hidden and/or system directories
{
//the recycle bin directory itself won't be marked, but a SID-specific child directory will, so now look at them
CString childSearch;
childSearch.Format(L"%c:\\%s\\*", path[0], fd.cFileName);
WIN32_FIND_DATA childFD = {0};
HANDLE childHandle = FindFirstFile(childSearch, &childFD);
while(INVALID_HANDLE_VALUE != childHandle)
{
if((FILE_ATTRIBUTE_DIRECTORY == (childFD.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) && //only check directories
(childFD.cFileName[0] != L'.')) //don't check . and .. dirs
{
CString fullPath;
fullPath.Format(L"%c:\\%s\\%s", path[0], fd.cFileName, childFD.cFileName);
CLSID id = {0};
HRESULT hr = GetFolderCLSID(fullPath, id);
if(SUCCEEDED(hr))
{
if(IsEqualGUID(CLSID_RecycleBin, id))
{
FindClose(childHandle);
FindClose(fHandle);
//return the parent (recycle bin) directory
fullPath.Format(L"%c:\\%s", path[0], fd.cFileName);
return fullPath;
}
}
else
{
Log(logERROR, L"GetFolderCLSID returned %08X for %s", hr, fullPath);
}
}
if(FALSE == FindNextFile(childHandle, &childFD))
{
FindClose(childHandle);
childHandle = INVALID_HANDLE_VALUE;
}
}
}
}
if(FALSE == FindNextFile(fHandle, &fd))
{
FindClose(fHandle);
fHandle = INVALID_HANDLE_VALUE;
}
}
_ASSERT(0);
return L"";
}
//Works on Windows 2000, and even as Local System account
HRESULT GetFolderCLSID(LPCWSTR path, CLSID& pathCLSID)
{
LPMALLOC pMalloc = NULL;
HRESULT hr = 0;
if (SUCCEEDED(hr = SHGetMalloc(&pMalloc)))
{
LPSHELLFOLDER pshfDesktop = NULL;
if (SUCCEEDED(hr = SHGetDesktopFolder(&pshfDesktop)))
{
LPITEMIDLIST pidl = NULL;
DWORD dwAttributes = SFGAO_FOLDER;
if (SUCCEEDED(hr = pshfDesktop->ParseDisplayName(NULL, NULL, (LPWSTR)path, NULL, &pidl, &dwAttributes)))
{
LPPERSIST pPersist = NULL;
if (SUCCEEDED(hr = pshfDesktop->BindToObject(pidl, NULL, IID_IPersist, (LPVOID *) &pPersist)))
{
hr = pPersist->GetClassID(&pathCLSID);
pPersist->Release();
}
pMalloc->Free(pidl);
}
pshfDesktop->Release();
}
pMalloc->Release();
}
return hr;
}
//Not supported on Windows 2000 since SHParseDisplayName wasn't implemented then
//HRESULT GetFolderCLSID(LPCWSTR pszPath, CLSID& pathCLSID)
//{
// SHDESCRIPTIONID did = {0};
// HRESULT hr = 0;
// LPITEMIDLIST pidl = NULL;
// if (SUCCEEDED(hr = SHParseDisplayName(pszPath, NULL, &pidl, 0, NULL))) //not supported by Windows 2000
// {
// IShellFolder *psf = NULL;
// LPCITEMIDLIST pidlChild = NULL;
// if (SUCCEEDED(hr = SHBindToParent(pidl, IID_IShellFolder, (void**)&psf, &pidlChild)))
// {
// hr = SHGetDataFromIDList(psf, pidlChild, SHGDFIL_DESCRIPTIONID, &did, sizeof(did));
// psf->Release();
// pathCLSID = did.clsid;
// }
// CoTaskMemFree(pidl);
// }
// return hr;
//}
In Win32, use SHGetSpecialFolderLocation. Pass CSIDL_BITBUCKET as the CDIL parameter.
A little bit late, but perhaps better late than never...
After debugging shell32.dll, I have found that for each version of windows the recycle path is hardcoded and, also, depends on the filesystem of that drive. I have tested this on Windows XP, Vista and Windows7:
Let X: be the drive we want to get the path to the recycle bin and let SID be the SID of the current user, then:
switchif(OsType) {
case WindowsXP:
{
if(PartitionType("X:") == NTFS)
{
printf("Path is: X:\\Recycler\\SID\\");
}
else
{
printf("Path is X:\\RECYCLED\\");
}
}
case WindowsVista:
case Windows7:
{
if(PartitionType("X:") == NTFS)
{
printf("Path is: X:\\$Recycle.bin\\SID\\");
}
else
{
printf("Path is X:\\$RECYCLE.BIN\\");
}
}
}
A wiki article presents the same facts:
http://en.wikipedia.org/wiki/Recycle_Bin_%28Windows%29

Resources