So I have tried looking at a couple of different answers for this. One that I thought may have promise was this one:
How to check network interface type is Ethernet or Wireless on Windows using Qt?
However, I don't really know too much about Networking or even about Windows. Personally, I cannot understand most of the Microsoft documentation on their websites. I have tried things like INetworkConnection, NativeWiFi, etc. But either they do not do what I want, or I just cannot figure out how to do it from the available documentation.
With that being said, I would like to use C++ to check if the device this program is being run on is connected to the internet via Ethernet cable. Basically, I want to do the following:
If the computer is connected to Wireless only, run the program
If the computer is connected to Wired only, don't run the program
If the computer is connected to both Wired AND Wireless, don't run the program
However, the problem is that I don't know how to check if the device has Ethernet connected. Is there a way to do this? I am NOT using QT. Thank you!
EDIT: I should also include what I have tried so far.
I tried using GetAdaptersInfo and getting the Type trait from the PIP_ADAPTER_INFO variable type, but that always gives me Unknown type 71 whether I am on Ethernet or not.
The documentation for that GetAdaptersInfo is here:
https://msdn.microsoft.com/en-us/library/aa365917%28VS.85%29.aspx
Thanks
EDIT 2: Here is the code I was using for GetAdaptersInfo
bool is_on_ethernet{
PIP_ADAPTER_INFO pAdapterInfo;
PIP_ADAPTER_INFO pAdapter = NULL;
DWORD dwRetVal = 0;
UINT i;
struct tm newtime;
char buffer[32];
errno_t error;
ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
if(pAdapterInfo == NULL)
printf("Error allocating memory need to call GetAdaptersInfo");
if(GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW){
free(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
}
if((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR){
pAdapter = pAdapterInfo;
switch(pAdapter->Type){
case MIB_IF_TYPE_OTHER:
printf("Other\n");
return false;
break;
case MIB_IF_TYPE_ETHERNET:
printf("Ethernet\h");
return true;
break;
case MIB_IF_TYPE_TOKENRING:
printf("Token Ring\n");
return false;
break;
case MIB_IF_TYPE_FDDI
printf("FDDI\n");
return false;
break;
case MIB_IF_TYPE_PPP
printf("PPP\n");
return false;
break;
case MIB_IF_TYPE_LOOPBACK
printf("Lookback\n");
return false;
break;
case MIB_IF_TYPE_SLIP
printf("Slip\n");
return false;
break;
default
printf("Unknown type %ld\n\n", pAdapter->Type);
return false;
break;
}
}
if(pAdapterInfo)
free(pAdapterInfo);
return false;
}
Your problem is somewhat difficult as it can be really complicated to get the "current" network adapter --- windows routes packets depending on network adapter configuration and destination reachability so your "current" adapter may change at any time ... but since you already know how to retrieve IPs and MACs ("hardware address") of available adapters you could simply use your hack to retrieve a MAC for your current IP and filter/search inside of my second function for it! The field "PhysicalAddress" is what you're looking for, thats the MAC adress
I have made the experience that the only, somewhat reliable way of doing that is via GetIfTable and GetIfTable2, the former returns somewhat superficial adpater info and the latter provides great detail.
Heres a sample implementation, as it uses the detailed function you can also query for WLAN adapters :
vector<MIB_IF_ROW2>* getDevices(NDIS_PHYSICAL_MEDIUM type)
{
vector<MIB_IF_ROW2> *v = new vector<MIB_IF_ROW2>();
PMIB_IF_TABLE2 table = NULL;
if(GetIfTable2Ex(MibIfTableRaw, &table) == NOERROR && table)
{
UINT32 i = 0;
for(; i < table->NumEntries; i++)
{
MIB_IF_ROW2 row;
ZeroMemory(&row, sizeof(MIB_IF_ROW2));
row.InterfaceIndex = i;
if(GetIfEntry2(&row) == NOERROR)
{
if(row.PhysicalMediumType == type)
{
v->push_back(row);
}
}
}
FreeMibTable(table);
}
return v;
}
Now all you need to do is iterate over the list and filter out disabled adapters and whatnot :
vector<MIB_IF_ROW2>* wlan = getDevices(NdisPhysicalMediumNative802_11); //WLAN adapters
//see https://msdn.microsoft.com/en-us/library/windows/desktop/aa814491(v=vs.85).aspx, "PhysicalMediumType" for a full list
for(auto &row : *v)
{
//do some additional filtering, this needs to be changed for non-WLAN
if( row.TunnelType == TUNNEL_TYPE_NONE &&
row.AccessType != NET_IF_ACCESS_LOOPBACK &&
row.Type == IF_TYPE_IEEE80211 &&
row.InterfaceAndOperStatusFlags.HardwareInterface == TRUE)
{
//HERE BE DRAGONS!
}
}
Now its quite easy to generate lists of WLAN adapters and non-WLAN adapters (see comment in second function), search for your current MAC and conclude that it is wired or wireless - but be aware that these lists may overlap since 802.11 basically is an extended version of 802.3 but 802.3 does not include 802.11 (since its an extension) - so you will need a tiny bit of if/else logic going on in order to seperate WLAN from non-WLAN adapters.
You could also use WlanEnumInterfaces to get all of the WLAN adapters but thats basically the same as using the above function with NdisPhysicalMediumNative802_11 as parameter ...
So first, thank you very much to user #Nighthawk441 for pointing me in the right direction for this. Without this user, I would most certainly have not come up with a solution.
That being said, the solution I have right now is, at best, a hack. It seems to work, but I don't think it is even close to the best option. Thus, I will leave this as an answer but I will not accept it for a little while in the event that a better answer is found. I am also very open to any comments anyone may have as it pertains to this answer.
In short, what I did was I looped through all of the Adapters from GetAdaptersInfo. In order to see if the adapter was connected, I compared the IP address of the adapter to the string "0.0.0.0", as if it were something other than this I felt it was safe to say that the adapter was connected. So, without further ado, here is the code that I implemented.
bool is_on_ethernet(){
PIP_ADAPTER_INFO pAdapterInfo;
PIP_ADAPTER_INFO pAdapter = NULL;
DWORD dwRetVal = 0;
UINT i;
struct tm newtime;
char buffer[32];
errno_t error;
ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
if(pAdapterInfo == NULL)
printf("Error allocating memory needed to call GetAdaptersInfo");
if(GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW){
free(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
}
if((dwRetValue = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR){
do{
pAdapter = pAdapterInfo;
string ip_string = pAdapter->IpAddressList.IpAddress.String;
switch(pAdapter->Type){
case MIB_IF_TYPE_OTHER:
printf("Other\n");
break;
...
case MIB_IF_TYPE_ETHERNET:
printf("Ethernet\n");
//new code
if(ip_string.compare("0.0.0.0") != 0){
free(pAdapterInfo);
return true;
}
break;
default:
printf("Unknown type %ld\n", pAdapter->Type);
break;
}
}while(pAdapterInfo = pAdapterInfo->Next);
}
if(pAdapterInfo)
free(pAdapterInfo);
return false;
}
Looking at this reference really helped me:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa365819%28v=vs.85%29.aspx
So thank you to Nighthawk for supplying that information to me. Hopefully this will help someone else! If anyone has any comments or any other answers, feel free to post them! Thanks!
Based on #specializt's answer, and with some minor modification, I got it work for me as following:
BOOL getDevices(NDIS_PHYSICAL_MEDIUM type, vector<MIB_IF_ROW2>& vetIFRow)
{
PMIB_IF_TABLE2 table = NULL;
if (GetIfTable2Ex(MibIfTableRaw, &table) != NOERROR || !table)
{
return FALSE;
}
for (ULONG i = 0; i < table->NumEntries; i++)
{
MIB_IF_ROW2 row;
ZeroMemory(&row, sizeof(MIB_IF_ROW2));
row.InterfaceIndex = i;
if (GetIfEntry2(&row) == NOERROR && row.PhysicalMediumType == type)
{
vetIFRow.push_back(row);
}
}
FreeMibTable(table);
return TRUE;
}
BOOL isNetIFConnected(const MIB_IF_ROW2& row, IFTYPE Type)
{
return (row.TunnelType == TUNNEL_TYPE_NONE &&
row.AccessType != NET_IF_ACCESS_LOOPBACK &&
row.Type == Type &&
row.InterfaceAndOperStatusFlags.HardwareInterface == TRUE &&
row.MediaConnectState == MediaConnectStateConnected);
}
tstring getNetWorkType()
{
vector<MIB_IF_ROW2> vectRow;
BOOL bRet = getDevices(NdisPhysicalMedium802_3, vectRow); // ETHERNET adapters
if (bRet)
{
for (auto it = vectRow.begin(); it != vectRow.end(); it++)
{
if (isNetIFConnected(*it, IF_TYPE_ETHERNET_CSMACD))
{
return L"ETHERNET";
}
}
}
vectRow.clear();
bRet = getDevices(NdisPhysicalMediumNative802_11, vectRow); //WLAN adapters
if (bRet)
{
for (auto it = vectRow.begin(); it != vectRow.end(); it++)
{
if (isNetIFConnected(*it, IF_TYPE_IEEE80211))
{
return L"WIFI";
}
}
}
return L"Unknown";
}
Thanks to #specializt
Related
I've a big plain c++ project where I implemented a webbrowser control (the idea come from https://github.com/Tobbe).
Well I inject some external method with the AddCustomObject. The problem is when I need to dispose a big page (1.9KB) with many object (tinymce, jquery ecc) for local editing ... the memory increasing every time I open the page.
I've searched, googled, readed, contacted the original developer... nope.
In the close method the code is this:
if (ibrowser != 0) {
IConnectionPointContainer *cpc = 0;
ibrowser->QueryInterface(IID_IConnectionPointContainer, (void**)&cpc);
if (cpc != 0) {
IConnectionPoint *cp = 0;
cpc->FindConnectionPoint(DIID_DWebBrowserEvents2, &cp);
if (cp != 0) {
cp->Unadvise(cookie);
cp->Release();
}
cpc->Release();
}
IOleObject *iole = 0;
ibrowser->QueryInterface(IID_IOleObject, (void**)&iole);
/*ibrowser->Stop();
ibrowser->ExecWB(OLECMDID_CLOSE, OLECMDEXECOPT_DONTPROMPTUSER, 0, 0);
ibrowser->put_Visible(VARIANT_FALSE);*/
UINT refCount = ibrowser->Release();
ibrowser = 0;
if (iole != 0) {
iole->Close(OLECLOSE_NOSAVE);
iole->Release();
}
}
Debugging in Vs2008 I've saw many CustomObject::AddRef and Release maybe due to setTimeout
I've no idea how to resolve this... need help!
Thank's!
Andrea
This seems like it should be a simple question, but I'm not sure how best to solve it. I've seen a few posts on how to detect if a connected device is USB 2 or 3, but I need to know if USB 3 ports are available, even if no devices are connected.
One solution would be to traverse the 'SYSTEM\CurrentControlSet\Services' key in the registry and compare against a pre-set list of known USB3 services. I was hoping there was something more accurate like an IOCTL call.
I can implement C++ (preferred) or C#.
Thanks in advance for any help.
Here's how I implemented this. Not really the solution I'm looking for. This basically will tell me if USB 3.0 drivers are present on the system. It does not detect if the hardware on the system includes USB 3.0 ports. Would prefer something lower level in C++.
I would greatly appreciate it if someone could show me how to detect the hardware for this (rather than just slag and not contribute). Thanks!
private bool IsUsb3()
{
string val = (string)Microsoft.Win32.Registry.GetValue("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\USBXHCI", "ImagePath", 0);
if (val != null) return true; // Microsoft
val = (string)Microsoft.Win32.Registry.GetValue("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\USBHUB3", "ImagePath", 0);
if (val != null) return true; // Microsoft
val = (string)Microsoft.Win32.Registry.GetValue("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\usb3Hub", "ImagePath", 0);
if (val != null) return true; // Microsoft
val = (string)Microsoft.Win32.Registry.GetValue("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\UCX01000", "ImagePath", 0);
if (val != null) return true; // Microsoft
val = (string)Microsoft.Win32.Registry.GetValue("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\nusb3hub", "ImagePath", 0);
if (val != null) return true; // Renesas
val = (string)Microsoft.Win32.Registry.GetValue("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\nusb3xhc", "ImagePath", 0);
if (val != null) return true; // Renesas
val = (string)Microsoft.Win32.Registry.GetValue("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\iusb3xhc", "ImagePath", 0);
if (val != null) return true; // Intel
val = (string)Microsoft.Win32.Registry.GetValue("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\iusb3hub", "ImagePath", 0);
if (val != null) return true; // Intel
val = (string)Microsoft.Win32.Registry.GetValue("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\iusb3hcs", "ImagePath", 0);
if (val != null) return true;
return false;
}
Here's exactly what I was looking for:
http://read.pudn.com/downloads105/sourcecode/windows/vxd/432626/USBLib/USB.cs__.htm
I then added the following code:
// Get USB information
bool supportsUsb3 = false;
System.Collections.ObjectModel.ReadOnlyCollection<USB.USBController> hostlist = null;
hostlist = USB.GetHostControllers();
mControllerCount = hostlist.Count;
foreach (USB.USBController host in hostlist)
{
USB.USBController controller = new USB.USBController();
controller.ControllerDevicePath = host.ControllerDevicePath;
USB.USBHub roothub = controller.GetRootHub();
System.Collections.ObjectModel.ReadOnlyCollection<USB.USBPort> portlist = null;
portlist = roothub.GetPorts();
foreach (USB.USBPort port in portlist)
{
USB.USBHub hub = port.GetHub();
if (port.PortSpeed == USBLib.USB.USB_DEVICE_SPEED.UsbSuperSpeed.ToString())
{
supportsUsb3 = true;
break;
}
}
if (supportsUsb3)
break;
}
I can now determine if the user's PC has USB 3.0 ports. If they only have 2.0 ports, then I can use the previous code to determine if USB 3 drivers are installed.
I am trying to get at the 'UILevel' MSI property from within a C++ custom action in order to determine whether or not the user is running in 'no UI mode', but am not having much luck. The function I am calling is passed the MSIHANDLE from a function which I export in my DLL (which may be either a 'deferred' or 'firstsequence' action). What I'm seeing is that MsiGetPropertyW is always returning ERROR_MORE_DATA and the trueLength field is always 0. Here is my code:
bool runningInNoUIMode(MSIHANDLE hInstall)
{
unsigned long nBufLen = 64UL;
WCHAR *wszValue = new WCHAR[nBufLen];
DWORD trueLength = 0UL;
UINT result = ::MsiGetPropertyW(hInstall, L"UILevel", L"", &trueLength); // Get the size of the property value first to see if there is enough storage allocated.
if (ERROR_MORE_DATA == result || nBufLen <= trueLength)
{
if (NULL != wszValue)
{
delete [] wszValue;
}
// Allocate more memory for the property adding one for the null terminator.
nBufLen = trueLength + 1;
wszValue = new WCHAR[nBufLen];
}
if (NULL == wszValue)
{
WcaLog(LOGMSG_STANDARD, "Unable to determine the user interface level the MSI is being run with because we were unable to allocate storage for accessing the 'UILevel' property.");
return false;
}
memset(wszValue, L'\0', nBufLen * sizeof(WCHAR));
result = ::MsiGetPropertyW(hInstall, L"UILevel", wszValue, &trueLength);
if (ERROR_SUCCESS != result)
{
WcaLog(LOGMSG_STANDARD, "Unable to determine the user interface level the MSI is being run with, error code = '%lu'.", result);
delete [] wszValue;
return false;
}
if (0 == wcscmp(L"2", wszValue)) // INSTALLUILEVEL_NONE == 2
{
delete [] wszValue;
return true;
}
delete [] wszValue;
return false;
}
I believe I can work around this for now by passing the 'UILevel' property through WiX and checking for it that way in the C++, but I am curious what the problem here is as well.
I'm using Visual Studio/Visual C++ 2010 on Windows 7 with WiX 3.5.2519.
Thanks for any assistance you can provide!
Another way of making this simpler is to use the MsiEvaluateCondition function.
BOOL bUI = MsiEvaluateCondition(L"UILevel<3");
in C# using Microsoft.Deployment.WindowsIntaller (DTF) it's:
var uiLevel = session["UILevel"];
In C++ there's a sample at MsiGetProperty function:
UINT __stdcall MyCustomAction(MSIHANDLE hInstall)
{
TCHAR* szValueBuf = NULL;
DWORD cchValueBuf = 0;
UINT uiStat = MsiGetProperty(hInstall, TEXT("MyProperty"), TEXT(""), &cchValueBuf);
//cchValueBuf now contains the size of the property's string, without null termination
if (ERROR_MORE_DATA == uiStat)
{
++cchValueBuf; // add 1 for null termination
szValueBuf = new TCHAR[cchValueBuf];
if (szValueBuf)
{
uiStat = MsiGetProperty(hInstall, TEXT("MyProperty"), szValueBuf, &cchValueBuf);
}
}
if (ERROR_SUCCESS != uiStat)
{
if (szValueBuf != NULL)
delete[] szValueBuf;
return ERROR_INSTALL_FAILURE;
}
// custom action uses MyProperty
// ...
delete[] szValueBuf;
return ERROR_SUCCESS;
}
Thanks to #DanielGehriger, we figured out that the problem isn't with the code, but with the scheduling for the custom action. The UILevel MSI property is simply not available when running a deferred custom action (I found that the code worked correctly for a custom action scheduled for firstsequence). I have worked around this limitation by explicitly passing it on custom action data using WiX:
<CustomAction Id="CustomAction.SetProperty" Property="CustomActionCall"
Value="UILEVEL=[UILevel];" />
and then checking for this in the C++ with WcaIsPropertySet and WcaGetProperty. Note that the character case of the property name between square brackets matters here.
I have tried all the normal methods of faking keyboard actions (SendInput/SendKeys/etc) but none of them seemed to work for games that used DirectInput. After a lot of reading and searching I stumbled across Interception, which is a C++ Library that allows you to hook into your devices.
It has been a very long time since I worked with C++ (Nothing existed for C#) so I am having some trouble with this. I have pasted in the sample code below.
Does it look like there would be anyway to initiate key actions from the code using this? The samples all just hook into the devices and rewrite actions (x key prints y, inverts mouse axis, etc).
enum ScanCode
{
SCANCODE_X = 0x2D,
SCANCODE_Y = 0x15,
SCANCODE_ESC = 0x01
};
int main()
{
InterceptionContext context;
InterceptionDevice device;
InterceptionKeyStroke stroke;
raise_process_priority();
context = interception_create_context();
interception_set_filter(context, interception_is_keyboard, INTERCEPTION_FILTER_KEY_DOWN | INTERCEPTION_FILTER_KEY_UP);
/*
for (int i = 0; i < 10; i++)
{
Sleep(1000);
stroke.code = SCANCODE_Y;
interception_send(context, device, (const InterceptionStroke *)&stroke, 1);
}
*/
while(interception_receive(context, device = interception_wait(context), (InterceptionStroke *)&stroke, 1) > 0)
{
if(stroke.code == SCANCODE_X) stroke.code = SCANCODE_Y;
interception_send(context, device, (const InterceptionStroke *)&stroke, 1);
if(stroke.code == SCANCODE_ESC) break;
}
The code I commented out was something I tried that didn't work.
You need to tweak key states for UP and DOWN states to get key presses. Pay attention at the while loop that the variable device is returned by interception_wait, your commented out code would send events to what?? device is not initialized! Forget your code and try some more basic. Look at the line inside the loop with the interception_send call, make more two calls after it, but don't forget to change stroke.state before each call using INTERCEPTION_KEY_DOWN and INTERCEPTION_KEY_UP so that you fake down and up events. You'll get extra keys at each keyboard event.
Also, you may try use INTERCEPTION_FILTER_KEY_ALL instead of INTERCEPTION_FILTER_KEY_DOWN | INTERCEPTION_FILTER_KEY_UP. The arrow keys may be special ones as mentioned at the website.
void ThreadMethod()
{
while (true)
{
if (turn)
{
for (int i = 0; i < 10; i++)
{
Sleep(1000);
InterceptionKeyStroke stroke;
stroke.code = SCANCODE_Y;
stroke.state = 0;
interception_send(context, device, (const InterceptionStroke *)&stroke, 1);
Sleep(1);
stroke.state = 1;
interception_send(context, device, (const InterceptionStroke *)&stroke, 1);
turn = false;
}
}
else Sleep(1);
}
}
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ThreadMethod, NULL, NULL, NULL);
while (interception_receive(context, device = interception_wait(context), (InterceptionStroke*)&stroke, 1) > 0)
{
if (stroke.code == SCANCODE_F5) turn = true;
interception_send(context, device, (InterceptionStroke*)&stroke, 1);
if (stroke.code == SCANCODE_ESC) break;
}
I want to listen for the insert and remove event of a smart cart... The application is for windows and the smart card is using x.509 certificates. The reader I use is standard card readers that is inserted in most new laptops and you can also buy them for usb use..
One thing I have found is:
cryptware.it/apidoc/scapi/index.html
but it cant be the only way and I just wanted to know my options...
Does anyone know what's the best way to do this?
Thanks in advance!
The Windows API has this function:
LONG WINAPI SCardGetStatusChange(
__in SCARDCONTEXT hContext,
__in DWORD dwTimeout,
__inout LPSCARD_READERSTATE rgReaderStates,
__in DWORD cReaders
);
You can then check if the rgReaderStates contains SCARD_STATE_EMPTY or SCARD_STATE_PRESENT. Read the details here: MSDN description
It is strictly speaking not event-driven but it blocks execution until a change happened. So by creating a separate thread that calls this in a loop, you can easily generate an event yourself.
A example.
This should be incorporated in thread function which runs this function at a time interval (1 second). The thread function should use this and sends a notification to the application that the driver has changed.
WARNING: UGLY CODE. PLEASE USE THIS AS AN EXAMPLE AND IMPROVE IT AS YOU SEE FIT.
BOOL CheckDirProperties(const CString& path, BOOL& bReadOnly, BOOL& bRemovable)
{
DWORD FileAttributes;
DWORD DriveAttributes;
UINT uDriveType;
if( path.GetLength() < 2 ||path.GetAt( 1 ) != ':' )
{
// invalid path, abort
return FALSE;
}
//Ugly path handling
CString szFormattedDrivePath("C:\\"); // string of length 3 where drive letter will be replaced
// Replace the drive letter with the drive letter from the path
szFormattedDrivePath.SetAt( 0, path.GetAt( 0 ) );
DriveAttributes = GetFileAttributes( szFormattedDrivePath );
FileAttributes = GetFileAttributes( path);
uDriveType = GetDriveType( szFormattedDrivePath );
if( !(FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
!(DriveAttributes & FILE_ATTRIBUTE_DIRECTORY) )
{ // Not a directory
return FALSE;
}
if( (FileAttributes & FILE_ATTRIBUTE_ARCHIVE) ||
(DriveAttributes & FILE_ATTRIBUTE_ARCHIVE) ||
(FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) ||
(DriveAttributes & FILE_ATTRIBUTE_ENCRYPTED) ||
(FileAttributes & FILE_ATTRIBUTE_OFFLINE) ||
(DriveAttributes & FILE_ATTRIBUTE_OFFLINE) ||
(FileAttributes & FILE_ATTRIBUTE_OFFLINE) ||
(DriveAttributes & FILE_ATTRIBUTE_OFFLINE) )
{ // Not a directory
TRACE("The directory %s on drive %s has unexpected file attributes. Problems may occur.\n",path, szFormattedDrivePath );
}
// To set m_bReadOnly to true, we need to know that the entire subtree is readonly.
// Even if the drive or the directory has the FILE_ATTRIBUTE_READONLY set, the content may not be read-only.
// Therefore the default value of bReadOnly must be FALSE.
bReadOnly = FALSE;
switch( uDriveType )
{
case DRIVE_FIXED:
case DRIVE_REMOTE:
bRemovable = FALSE;
break;
case DRIVE_CDROM:
bRemovable = TRUE;
bReadOnly = TRUE; // We know that a CD-ROM drive is always read-only
break;
case DRIVE_REMOVABLE:
case DRIVE_RAMDISK:
bRemovable = TRUE;
break;
case DRIVE_NO_ROOT_DIR: // fall through
case DRIVE_UNKNOWN: // fall through
default:
bRemovable = TRUE; // assume it is removable if we don't know what value to set
break;
}
return TRUE;
}