MCI_OPEN fails for mp3 files in a C++ console application - c++

This is what I did:
DWORD dwReturn;
MCI_OPEN_PARMS mciOpenParms;
mciOpenParms.lpstrDeviceType = _T("MPEGvideo");
mciOpenParms.lpstrElementName = m_tmpFileName;
dwReturn = mciSendCommand(NULL, MCI_OPEN,
MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,
(DWORD)(LPVOID) &mciOpenParms);
if (dwReturn)
{
wchar_t chError[100];
mciGetErrorString(dwReturn,chError,sizeof(chError));
//report the error here
}
When I run the code, I see that dwReturn is 266 and chError is set to "Unknown problem while loading the specified device driver". What could be wrong?
Note: I also tried "mpegvideo" instead of "MPEGvideo"; it didn't help. Where are these things documented anyway?

It works for me. Maybe (likely) you have the MCI register all screwed up. Or maybe the file you are opening is corrupted somehow.
As far as I know these device names are not documented anywhere. But you can find the ones configured in your system in the registry: HKLM\Software\Microsoft\Windows NT\CurrentVersion\MCI32. My system has:
AVIVideo
CDAudio
MPEGVideo
Sequencer
WaveAudio
And given that the MCI is not used much nowadays, I'd say that they are pretty standard.

If you're specifying MCI_OPEN_ELEMENT then mciOpenParms.lpstrDeviceType must be null.
See the Remarks section.
*To use automatic type selection (via the entries in the registry), assign the filename and file extension to the lpstrElementName member of the structure identified by lpOpen, set the lpstrDeviceType member to NULL, and set the MCI_OPEN_ELEMENT flag.*

Related

Is it good to use ntdll.dll in a win32 console application?

Short:
In my c++ project i need to read/write extended file properties. I managed it with using alternate data streams (ADS). My problem is, for opening the ADS i need to use the CreateFile API. But it is not fulfilling my needs. NtCreateFile will fullfill all my needs. (Or alternatively NtSetEaFile and NtQueryEaFile) But NtCreateFile is not directly accessible from a win32 console application.
I know i can use this function easily via GetProcAdress. But i like to know the opinion of you all, if i did miss something? Some other libs are using this pattern already, for example Chromium (https://github.com/chromium-googlesource-mirror/chromium/blob/1c1996b75d3611f56d14e2b30e7ae4eabc101486/src/sandbox/src/win_utils.cc function: ResolveNTFunctionPtr)
But im uncertain, because the c++ project is not a hobby project and i ask myself if it is dangerous or not.
I guess NtCreateFile is maybe the securest way to do, because it is well documented and supported by winternl.h header. Especially because this method is unchanged since windows 2000. But what is with NtSetEaFile, NtQueryEaFile which are fitting my needs perfectly. They are only half documented. A documentation for ZwSetEaFile and ZwQueryEaFile exist (unchanged since windows 2000).
Reason why i want to do that:
I want to write and read extended properties from files via ADS. But in case of writing the extended property of a given file the first time, i need to open the file with OPEN_ALWAYS. In case of file is not existing it will create a new file, even if i only access not the content stream of the file. To avoid this i get first the handle of the original file and check with this HANDLE if the file still exist.
But i dont want to blog any file with reduced access rights, because from my point of view that is a very bad pattern. The user needs to have full access to any file any time. Because of that we open all HANDLES with the flag FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE. And now i have the race.
auto hFile = CreateFileW(originalPath, …, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, …).
// this is the little race: if somebody at least rename originalPath the
// second CreateFileW call will cause the creation of a empty file with the
// path originalPath (the old path).
auto hADS = CreateFileW(originalPath + adsName, …, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_ALWAYS, …).
This is a main issue, especially because this happens from time to time in our tests. NtCreateFile will fix it, because i can create the second HANDLE with the help of the first HANDLE. Because of that no race. Or NtSetEaFile and NtQueryEaFile will help, because i only need one HANDLE.
The thing is, that the application needs not to be save for the future, because ADS works only on NTFS anyway. And who knows when NTFS will be exchanged. But i dont want a flaky behaviour. I want to trust this Methods. I I am fine if the API will change in the future and the software needs to adapt to it. But i want to be sure, that all Windows higher or equal then 7 can deal with it. Somebody some experience to share? I would like to hear them very much.
This question is wrong. Your proposed solution for your problem, is not using NtCreateFile, but use CreateFile with dwCreationDisposition set to the OPEN_EXISTING.
From documentation:
OPEN_EXISTING
Opens a file or device, only if it exists. If the specified file or
device does not exist, the function fails and the last-error code is
set to ERROR_FILE_NOT_FOUND.
Simply open file if exists and set whatever you want. If file is renamed, CreateFile returns ERROR_FILE_NOT_FOUND.
THE PROBLEM
Now, to your proposed solution, what is better method or why is not possible use ntdll.dll in win32 console application (???).
Again, your "better" method - GetProcAddress is "wrong" same as using linking against ntdll.dll. In Windows 11, or Windows 12 or Windows 3030 the function may be removed and both solutions (statical vs. dynamical import) will be fail.
It is not really unsecure to use this kind of APIs if their is a documentation. In case of NtSetEaFile, NtQueryEaFile and NtCreateFile you can find a description inside of Microsoft's Doc. (keep in mind NtXxx == ZwXxx)
But this API can change in the future and Microsoft does not guarantee that it will provides the same methods in the next Windows version. If you can, use the public API, because then you are safe. If not it is a case by case decision. In this case the three methods from the API are unchanged since Windows2000. Plus for example NtSetEaFile and NtQueryEaFile is used by Microsoft for WSL (Windows Subsystem for Linux). And especially NtCreateFile is used by a wide range of OpenSource Projects. So it is very unlikely that this API will change.
In my use case another aspect is important. Because I wanted to use ADS, but ADS is only supported by NTFS. So using ADS does not ensure future compatibility as well. So it was very clear for me using NtSetEaFile and NtQueryEaFile.
But how you can use this kind of APIs? Dynamic or static linking is possible. It depends on your needs what is better. In case of static linking you need to download the last WDK (Windows Driver Kit) and link against the ntdll.lib. In case of dynamic linking you can access the dll directly via GetModuleHandle and finding out the address of the method with GetProcAddress. Under Windows ntdll.dll is accessible from any application. In both cases you don't have directly a header file. You have to define the header file by yourself or use WDK to get them.
In my project dynamic linking was the best choice. The reason was, that on every windows the right implementation will be choosen and in case the method is not available i have the chance to deactivate the feature in my software instead of crash. Microsoft is recommending the dynamic way, because of the last reason.
Simple PseudoCode (dynamic case):
typedef struct _FILE_FULL_EA_INFORMATION {
ULONG NextEntryOffset;
UCHAR Flags;
UCHAR EaNameLength;
USHORT EaValueLength;
CHAR EaName[1];
} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;
typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
};
ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
typedef NTSTATUS(WINAPI *NtSetEaFileFunction)(IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK
IoStatusBlock,
IN PVOID Buffer,
IN ULONG Length);
HMODULE ntdll = GetModuleHandle(L"ntdll.dll");
NtSetEaFileFunction function = nullptr;
FARPROC *function_ptr = reinterpret_cast<FARPROC *>(&function);
*function_ptr = GetProcAddress(ntdll, "NtQueryEaFile");
// function could be used normally.
The other answer is incorrect. The reason is that the reason of my problem is, that I need to use OPEN_ALWAYS. Of course, if you don't need this flag, everything is fine. But in my case there is a point where I needed to create the ADS. And it will not be created without the OPEN_ALWAYS flag.

Trying to understand process mitigation policies that can be set by SetProcessMitigationPolicy function

Sorry, if it's too broad of a question. I'm trying to see what exactly SetProcessMitigationPolicy function does in Windows 10, but I can't find much about it online (besides my previous forays into this subject.) I'm testing its PROCESS_MITIGATION_POLICY options one-by-one, and I have some questions about these:
ProcessSystemCallDisablePolicy states that it "Disables the ability to use NTUser/GDI functions at the lowest layer.". So I'm testing it as such:
PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY pmscdp = {0};
pmscdp.DisallowWin32kSystemCalls = 1;
BOOL bR = ::SetProcessMitigationPolicy(ProcessSystemCallDisablePolicy, &pmscdp, sizeof(pmscdp));
int err = ::GetLastError();
::GdiFlush(); //Try to trip it here
But it always fails with error code 19, or ERROR_WRITE_PROTECT.
So what exactly is it supposed to do and how do I set it?
ProcessExtensionPointDisablePolicy states that it "... prevents legacy extension point DLLs from being loaded into the process."
PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY pmepdp = {0};
pmepdp.DisableExtensionPoints = 1;
BOOL bR = ::SetProcessMitigationPolicy(ProcessExtensionPointDisablePolicy, &pmepdp, sizeof(pmepdp));
int err = ::GetLastError();
Sorry for my naivete, but what is the extension point DLL? And how can I test one?
ProcessSignaturePolicy states that it can "restrict image loading to those images that are either signed by Microsoft, by the Windows Store, or by Microsoft, the Windows Store and the Windows Hardware Quality Labs (WHQL)".
First off, it seems to have no effect on CreateProcess and only works with LoadLibrary-type functions. So if I do this:
PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY pmbsp = {0};
pmbsp.MicrosoftSignedOnly = 1;
//pmbsp.StoreSignedOnly = 1; //always seems to fail with this flag
//pmbsp.MitigationOptIn = 1; //Doesn't seem to have any effect
BOOL bR = ::SetProcessMitigationPolicy(ProcessSignaturePolicy, &pmbsp, sizeof(pmbsp));
BOOL err = ::GetLastError();
And then try to load some of my test DLLs:
HMODULE hModDll = ::LoadLibrary(L".\\Dll1.dll");
The LoadLibrary function fails with the MessageBox that reads:
Bad Image
Dll-Name is either not designed to run on Windows or it
contains an error. Try installing the program again using the original
installation media or contact your system administrator or the
software vendor for support. Error status 0xc0000428.
Interestingly, if I call it on some System32 DLL that is not signed:
HMODULE hModDll = ::LoadLibrary(L"iologmsg.dll");
it seems to work fine. But if I place a copy of my test Dll1.dll into System32 folder and load it this way:
HMODULE hModDll = ::LoadLibrary(L"Dll1_.dll");
it still fails with the same message box:
This is interesting. How can it tell the difference between iologmsg.dll and Dll1_.dll? Both files aren't signed.
PS. And that modal message box can throw in a really nasty wrench into the mix if the app (or the service) does not expect any UI to be shown there.
ProcessFontDisablePolicy lastly, I'm totally lost about this one. It states that it "turns off the ability of the process to load non-system fonts."
So after I enable it in my MFC GUI app:
PROCESS_MITIGATION_FONT_DISABLE_POLICY pmfdp = {0};
pmfdp.DisableNonSystemFonts = 1;
BOOL bR = ::SetProcessMitigationPolicy(ProcessFontDisablePolicy, &pmfdp, sizeof(pmfdp));
int err = ::GetLastError();
the app has a Richedit control that I can load a custom font in. So I went online and downloaded a totally random font. Then installed it in Windows Explorer and tried to use it from the app after that policy has been enabled:
//Set format for the text window
CHARFORMAT cf = { 0 };
cf.cbSize = sizeof(cf);
cf.dwMask = CFM_FACE | CFM_SIZE;
cf.yHeight = 18 * 20;
VERIFY(SUCCEEDED(::StringCchCopy(cf.szFaceName, _countof(cf.szFaceName), L"Action Man")));
VERIFY(SetDefaultCharFormat(cf));
The app was able to display and use that (clearly non-system) font without any issues:
So what am I missing here in that policy?
This is guessing, but since many links in the function's documentation are 404s, I believe that the following would be valid:
1.Probably not implemented, yet.
2.Only a guess (since the link is also 404), but it might refer to DLLs used in obsolete situtations (like the XP and below login DLL, replaced in Vista with Credential Providers).
3.Windows DLLs are treated as signed (without actually having a digital signature attached), not only because they reside in System32, but because Windows keeps internally a map for them. For your DLLs, it won't work. Also, this has no point in CreateProcess() because the new process cannot interact with yours (without your knowledge) and, therefore, cannot hijack it, where a DLL loaded with LoadLibrary can do anything to ruin your process.
4.It probably refers to fonts not installed by Explorer, but fonts added with AddFontResource.

GetDiskFreeSpaceEx with NULL Directory Name failing

I'm trying to use GetDiskFreeSpaceEx in my C++ win32 application to get the total available bytes on the 'current' drive. I'm on Windows 7.
I'm using this sample code: http://support.microsoft.com/kb/231497
And it works! Well, almost. It works if I provide a drive, such as:
...
szDrive[0] = 'C'; // <-- specifying drive
szDrive[1] = ':';
szDrive[2] = '\\';
szDrive[3] = '\0';
pszDrive = szDrive;
...
fResult = pGetDiskFreeSpaceEx ((LPCTSTR)pszDrive,
    (PULARGE_INTEGER)&i64FreeBytesToCaller,
    (PULARGE_INTEGER)&i64TotalBytes,
(PULARGE_INTEGER)&i64FreeBytes);
fResult becomes true and i can go on to accurately calculate the number of free bytes available.
The problem, however, is that I was hoping to not have to specify the drive, but instead just use the 'current' one. The docs I found online (Here) state:
lpDirectoryName [in, optional]
A directory on the disk. If this parameter is NULL, the function uses the root of the current disk.
But if I pass in NULL for the Directory Name then GetDiskFreeSpaceEx ends up returning false and the data remains as garbage.
fResult = pGetDiskFreeSpaceEx (NULL,
    (PULARGE_INTEGER)&i64FreeBytesToCaller,
    (PULARGE_INTEGER)&i64TotalBytes,
(PULARGE_INTEGER)&i64FreeBytes);
//fResult == false
Is this odd? Surely I'm missing something? Any help is appreciated!
EDIT
As per JosephH's comment, I did a GetLastError() call. It returned the DWORD for:
ERROR_INVALID_NAME 123 (0x7B)
The filename, directory name, or volume label syntax is incorrect.
2nd EDIT
Buried down in the comments I mentioned:
I tried GetCurrentDirectory and it returns the correct absolute path, except it prefixes it with \\?\
it returns the correct absolute path, except it prefixes it with \\?\
That's the key to this mystery. What you got back is the name of the directory with the native api path name. Windows is an operating system that internally looks very different from what you are familiar with winapi programming. The Windows kernel has a completely different api, it resembles the DEC VMS operating system a lot. No coincidence, David Cutler used to work for DEC. On top of that native OS were originally three api layers, Win32, POSIX and OS/2. They made it easy to port programs from other operating systems to Windows NT. Nobody cared much for the POSIX and OS/2 layers, they were dropped at XP time.
One infamous restriction in Win32 is the value of MAX_PATH, 260. It sets the largest permitted size of a C string that stores a file path name. The native api permits much larger names, 32000 characters. You can bypass the Win32 restriction by using the path name using the native api format. Which is simply the same path name as you are familiar with, but prefixed with \\?\.
So surely the reason that you got such a string back from GetCurrentDirectory() is because your current directory name is longer than 259 characters. Extrapolating further, GetDiskFreeSpaceEx() failed because it has a bug, it rejects the long name it sees when you pass NULL. Somewhat understandable, it isn't normally asked to deal with long names. Everybody just passes the drive name.
This is fairly typical for what happens when you create directories with such long names. Stuff just starts falling over randomly. In general there is a lot of C code around that uses MAX_PATH and that code will fail miserably when it has to deal with path names that are longer than that. This is a pretty exploitable problem too for its ability to create stack buffer overflow in a C program, technically a carefully crafted file name could be used to manipulate programs and inject malware.
There is no real cure for this problem, that bug in GetDiskFreeSpaceEx() isn't going to be fixed any time soon. Delete that directory, it can cause lots more trouble, and write this off as a learning experience.
I am pretty sure you will have to retrieve the current drive and directory and pass that to the function. I remember attempting to use GetDiskFreeSpaceEx() with the directory name as ".", but that did not work.

Is a Program Running in Compatibility Mode

Is there a C++ .NET function that I can call that will detect if my program is running in compatibility mode? If there is not one, could someone show me the code for one? Thanks.
For example:
Program loads up
Compatibility Mode check
if true then exit
else run
From another forum
After a few google searches went in
vain, I decided to experiment myself.
I found that the compatibility
settings for each executable are
stored - as I thought it would be - in
the windows registry.
The key where the settings are stored
is
HKEY_CURRENT_USER\Software\Microsoft\Windows
NT\CurrentVersion\AppCompatFlags\Layers
For each application that has its
compatibility settings specified,
there exists a value under that key
whose name is the path to the
executable and the data is a string
consisting of the compatibility
settings.
The keywords in the string that
specify the compatibility settings
are: WIN95 WIN98 NT4SP5
WIN2000 256COLOR 640X480
DISABLETHEMES DISABLECICERO
If multiple settings are specified (or
are to be specified), the data
consists of the settings above
separated by a space each. The first
four settings are mutually exclusive,
i.e. only one of them is to be
specified (if at all). I haven't
tested the consequences of specifying
multiple operating systems.
So, back to addressing your problem.
To check if an executable (let's say,
"C:\path\executable.exe") is set to
run in 256 color mode, there would be
a value named "C:\path\executable.exe"
(without the quotes, even if the path
contains spaces) under the key
[HKEY_CURRENT_USER\Software\Microsoft\Windows
NT\CurrentVersion\AppCompatFlags\Layers],
and the data associated with the value
would contain the string "256COLOR".
If it is also set to run in
compatibility mode under Windows
98/ME, the data would be "WIN98
256COLOR".
So, the approach is simple. Test if
there is a value with the full path of
the executable under the key I
mentioned above. If there isn't, the
executable has not been specified any
compatibility settings. If the value
exists, retrieve its data and check
for the presence of "256COLOR" in the
data. Accordingly, the presence of
"WIN95" or "WIN98" or "NT4SP5" or
"WIN2000" would mean that the
executable is set to run in
compatibility mode for that particular
operating system.
Get the version of the operation system that is returned from GetVersionEx and compare it to the file version on kernel32.dll. When in application compatibility mode GetVersionEx will always return the version of the operating system that is being 'emulated'. If both versions are different then you are in application compatibility mode.
The answer above helped me to get a "solution" for the question at hand. It is probably not the most elegant, but seems to work. Obviously you can get a bit more creative on the return type. Booleon does not suffice here. I think a native API would be good.
typedef VOID (NTAPI* TRtlGetNtVersionNumbers)(LPDWORD pdwMajorVersion, LPDWORD pdwMinorVersion, LPDWORD pdwBuildNumber);
bool IsRunningCompatMode()
{
TRtlGetNtVersionNumbers RtlGetNtVersionNumbers = (TRtlGetNtVersionNumbers)GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlGetNtVersionNumbers");
assert(RtlGetNtVersionNumbers);
if(RtlGetNtVersionNumbers)
{
OSVERSIONINFO osInfo = {0};
osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osInfo);
DWORD dwMajorVersion;
DWORD dwMinorVersion;
DWORD dwBuildNumber;
RtlGetNtVersionNumbers(&dwMajorVersion, &dwMinorVersion, &dwBuildNumber);
dwBuildNumber &= 0x0000FFFF;
if(osInfo.dwBuildNumber != dwBuildNumber)
{
return true;
}
}
return false;
};

Edit Registry Values

I want to change the registry values on the pocketPC. I ran the following code:
if(enabled)
{
dwData = 120;
}
if(RegSetValueEx(HKEY_LOCAL_MACHINE, _T("System\\CurrentControlSet\\Control\\Power\\Timeouts\\BattSuspendTimeout"), 0, REG_DWORD, (LPBYTE)&dwData, sizeof(DWORD)))
{
return FALSE;
}
but it doesn't shange the registry entry. Does anyone know how to set registry key values with c++?
Thanks!
There are a two problems with what you are doing:
1: RegSetValueEx does not take a path, only a valuename. So you need to open the key path first.
e.g.
HKEY key;
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Control\\Power\\Timeouts", 0, 0, &key))
{
if(RegSetValueEx(key, _T("BattSuspendTimeout"), 0, REG_DWORD, (LPBYTE)&dwData, sizeof(DWORD)))
{
RegCloseKey(key);
return FALSE;
}
RegCloseKey(key);
}
2: That area of the registry requires Privileged code signing to work on all Windows Mobile devices. You can get away with it on most current touch-screen windows mobile devices if the user says "yes" to the unknown publisher question when the application is first run or installed. If you get a "Access Denied" error on the set, then you really need to be Privileged code signed for the set to work.
RegSetValueEx returns a descriptive error code. You can get a human-readable message out of this error code using FormatMessage and possibly via the Error Lookup tool, or the #ERR facility in VS. The code you have looks correct so see what the error message tells you.
How are you verifying the change? Keep in mind that making this change will not be reflected automatically in the device behavior and it probably won't show up in the Control Panel either (depends on if the CPL has already been loaded or not). The shell is unaware that you made the change and it doesn't poll the value - you have to tell it to go out and re-read. How to do it is documented in MSDN (basically you set a named system event).
Check out [VORegistry][1], it makes working with the registry so much easier.
[1]: http://www.voscorp.com/products/developer/winmobile/voregistry/index.htm VORegistry
Assuming that your looking with RegEdit, did you refresh (F5) the registry view?