Published by Roman on 22 Jun 2009

RegSetKeySecurity, CRegKey::SetKeySecurity and CSecurityDesc

One thing is worth special mentioning in connection with previous post on DirectShow Filter Graph Spy on Microsoft Vista system: ATL’s CSecurityDesc class caused to waste some time.

CRegKey Key;
ATLENSURE_SUCCEEDED(HRESULT_FROM_WIN32(Key.Open(HKEY_CLASSES_ROOT, pszKeyName, READ_CONTROL | WRITE_OWNER)));
CSecurityDesc AdministratorsOwnerSecurityDescriptor;
AdministratorsOwnerSecurityDescriptor.SetOwner(Sids::Admins());
ATLENSURE_SUCCEEDED(HRESULT_FROM_WIN32(Key.SetKeySecurity(OWNER_SECURITY_INFORMATION, &AdministratorsOwnerSecurityDescriptor)));

The code compiles fine, but on runtime it gives error 87 (ERROR_INVALID_PARAMETER, E_INVALIDARG) in the last line, returned from RegSetKeySecurity API call. My first guess was that ATL’s CSecurityDesc class for some reason prepared wrong descriptor which resulted in rejecting it as an argument. From the first glance it looks (not sure) that this class deals, to some extent, with structures itself rather than using API functions, so it could be that it results in something looking differently from expected by API calls.

Still the problem is in class itself and its cast from CSecurityDesc& to required SECURITY_DESCRIPTOR* type. The class only implements operator to automatically cast to const SECURITY_DESCRIPTOR* type, so the following line would not be passed by compiler:

Key.SetKeySecurity(OWNER_SECURITY_INFORMATION, AdministratorsOwnerSecurityDescriptor)

However &AdministratorsOwnerSecurityDescriptor is another level of indirection and hence SECURITY_DESCRIPTOR** type, which is passed by compiler, but results in indeed invalid argument.

So in order to correctly convert CSecurityDesc& to SECURITY_DESCRIPTOR* it can be done this way:

CRegKey Key;
ATLENSURE_SUCCEEDED(HRESULT_FROM_WIN32(Key.Open(HKEY_CLASSES_ROOT, pszKeyName, READ_CONTROL | WRITE_OWNER)));
CSecurityDesc AdministratorsOwnerSecurityDescriptor;
AdministratorsOwnerSecurityDescriptor.SetOwner(Sids::Admins());
ATLENSURE_SUCCEEDED(HRESULT_FROM_WIN32(Key.SetKeySecurity(OWNER_SECURITY_INFORMATION, const_cast<SECURITY_DESCRIPTOR*>((const SECURITY_DESCRIPTOR*) AdministratorsOwnerSecurityDescriptor))));

Published by Roman on 22 Jun 2009

DirectShow Filter Graph Spy on Vista

I have been receiving comments that Filter Graph Spy tool does not work with Microsoft Vista operating system. I never had a moment to check until recently, and this time I realized that it really does not work. I am definitely aware of dramatic changes introduced with this operating system, and in particular UAC feature, virtualization and changes in security. No wonder this was the first guess that security was the cause, however the investigation showed there was a trail of issues underneath…

Investigation details deserve a separate post, while this one briefly outlines the issues and also accompany the repository update with a version compatible with Vista OS.

First of all, COM registration of the DLL (which definitely requires privilege elevation) succeeded on Vista. This means the registration procedure did not encounter any errors on the way, or poorly written code ignored the problem. It appeared that the source of the problem was CoTreatAsClass API, which failed to do the requested action, however returned status code indicating successful operation. This definitely looks like a bug and further comments on this particular behavior are expected to appear on Windows Applications Security MSDN forum, where I opened a topic on the matter.

With a COM TreatAs feature activated, the class’s behavior to instantiate instead of DirectShow’s CLSID_FilterGraph is restored, and in particular the DLL generates FilterGraphSpy.log log file on filter graph activity. Note that log file location is OS dependent (due to Vista’s permissions and file system virtualization):

  • pre-Vista OS: root of syste drive, typically C:\
  • starting Vista, administrator with elevated privileges: CSIDL_COMMON_APPDATA, typically C:\ProgramData (note this directory is hidden by deafult)
  • starting Vista, without elevated administrator privileges: CSIDL_LOCAL_APPDATA, typically C:\Users\$(UserName)\AppData\Local (note that AppData directory is hidden by deafult)

Still even with the log file generated and indicating activation of the spy, it was unable to connect to remote graph through the running object table (ROT). It appeared that the ROT entires are there where expected, it was OK to get an object from ROT and the problem came from QueryInterface code:

CComPtr<IUnknown> pFilterGraphUnknown;
ATLENSURE_SUCCEEDED(pRunningObjectTable->GetObject(pMoniker, &pFilterGraphUnknown));
CComQIPtr<IMyFilterGraph> pFilterGraph = pFilterGraphUnknown; // E_NOINTERFACE

The call reached the original object but COM subsystem was unable to marshal the interface through apartments to enable interprocess communication on it. The reason for this is absence of PSFactoryBuffer class (CLSID {92A3A302-DA7C-4A1F-BA7E-1802BB5D2D02}), which provides proxy/stub pairs for marshaling well known DirectShow interfaces in the Vista’s version of quartz.dll. As mentioned by Microsoft’s Mike Wasson, this class was moved from quartz.dll into Vista SDK’s proppage.dll, so in order to obtain connectivity to remote DirectShow graphs starting Vista, one needs to install this DLL with Windows SDK, or otherwise have it registered with the operating system.

Also note that DirectShow-enabled applications that have their filter graphs published on ROT will need an utility application such as GraphEdit started with the same permissions (elevated or not) in order to be able to access ROT entires.

To sum everything up, to install Alax.Info DirectShow Filter Graph Spy on Vista:

  • get the latest FilterGraphSpy.dll
  • regsvr32 FilterGraphSpy.dll on target system from administrative command prompt, with elevated privileges (note you should have a log file FilterGraphSpy.log generated in CSIDL_COMMON_APPDATA directory, with a few lines indicating registration success)
  • get Windows SDK and make $(WindowsSDK)\Bin\proppage.dll file registered on target system (also administrative regsvr32), note that it is necessary to restart DirectShow-enabled applications and GraphEdit after DLL registration to get graphs visible through ROT
  • mind the log file directories with FilterGraphSpy.log file

A partial Visual C++ .NET 2008 source code is available from SVN, release binary included.

Published by Roman on 11 Jun 2009

Hint on how to easily find your filter graph on running object table (ROT)

With a lot of DirectShow Filter Graphs published on Running Object Table, especially those automatically published by Filter Graph Spy utility, it might be a bit tricky to locate your graph of interest in the list.

Filter graphs are published with a textual moniker item name of predefined format, which is recognized by GraphEdit or GraphStudio, or similar utilities as an item corresponding to a filter graph. A template for such a string is “FilterGraph %08x pid %08x“, which obviously only contains raw pointer address and process identifier, which only help a bit in looking up for proper graph interactively. However, it is important how exactly applications are recognizing filter graph related names. For example, GraphStudio does it the following way:

rot->EnumRunning(&emon);
emon->Reset();
while (emon->Next(1, &moniker, &f) == NOERROR) {

    // is this a graph object ?
    LPOLESTR    displayname;
    moniker->GetDisplayName(bindctx, NULL, &displayname);

    CString        name(displayname);
    if (name.Find(_T("!FilterGraph")) == 0) {

The items that match are then listed in GUI with an original string, which means that it is possible to provide an informational suffix to be able to locate the graph in a more convenient way, e.g. with a process image name, not only identifier (”; process: …” was appended to the item name):

GraphStudio's ROT Items

GraphEdit is using another method and is more strict in selecting among available items. AFAIR earlier versions did not allow custom suffixes in item names, however the latest version still picks the items up from the global list. However, GraphEdit does not show graph’s original item name, so suffixes are merely useless with GraphEdit.

GraphEdit ROT Items

Filter Graph Spy utility was updated to automatically append process name suffix, which should be OK for both GrapEdit and GraphStudio. Still, the feature can be disabled through registry DWORD value named “Enable ROT Moniker Item Name Suffix” under HKEY_LOCAL_MACHINE\SOFTWARE\Alax.Info\Utilities. The value of zero, or missing, is the default behavior to enable suffixes. The value of 1 disables the feature, the value of 2 makes sure it is enabled.

static CConstIntegerRegistryValue g_nEnableRotMonikerItemNameSuffix(_T("Enable ROT Moniker Item Name Suffix")); // 0 Default, 1 Disable, 2 Enable
if(g_nEnableRotMonikerItemNameSuffix != 1)
{
    TCHAR pszPath[MAX_PATH] = { 0 };
    _W(GetModuleFileName(NULL, pszPath, DIM(pszPath)));
    CString sItemName = AtlFormatString(_T("%s; process: %s"), m_RunningFilterGraph.GetDefaultMonikerItemName(GetControllingUnknown()), FindFileName(pszPath));
    m_RunningFilterGraph.SetFilterGraph(GetControllingUnknown(), CStringW(sItemName));
} else
    m_RunningFilterGraph.SetFilterGraph(GetControllingUnknown())

A partial Visual C++ .NET 2008 source code is available from SVN, release binary included.

Published by Roman on 01 Apr 2009

YV12, Extended Video Renderer Strides, Private DMO and more

Recently it was the time to sort out an issue with a video DMO, which outputs YV12 video and in the same time is capable of supporting extended video strides in order to efficiently make a direct connection to Video Mixing Renderer Filters.

From past experience, I already knew that some bugs are definitely involved but their effect was yet unexplored. For a testbed application, I took good old FrameRateSample02 application, which generates multiple video feeds and routes it to video renderers:

FrameRateSample02 Application with New Choices

With new source video choices the application is capable of constructing filter graphs that use a private DMO (that is hosted inside the executable) wrapped with DMO Wrapper Filter, with a graph topology shown below:

Filter Graph with a Private DMO

Continue Reading »

Published by Roman on 28 Feb 2009

MediaTools: Tone Source Filter to generate reference audio feed, dual Audio Source Filter and Virtual Audio Capture Device

In order to obtain a reference audio source and especially useful for debugging purposes, including:

  • audio input device unrelated to physical device, to avoid conditions when device is already in use by someone else
  • non-zero audio signal which is independent of certain speaker or broadcasting service, including one that makes capture, transmission or rendering issues easily perceptible by human
  • configurable to provide different audio media types, including through well known DirectShow interfaces, such as IAMStreamConfig
  • configurable to present in system as both regular DirectShow Filter, and as an Audio Capture Source which can be enumerated by applications
  • to be able to check how exactly other applications are accessing and configuring audio capture source

I added a new filter to the Media Tools library, a Tone Source Filter. The filter generates PCM Audio data, either infinite sine waveform, or interrupted signal  of requested parameters:

Tone Source Filter General Property Page

The filter accepts connection on PCM media types with flexible sampling rates in range 8 KHz through 200 KHz, 8-bit audio and 1 channel. Media type is also configurable through or, if not configured this way, the first enumerated media type off the Output pin is also configurable through property page and/or persistent setting accessible via private IDispatch derived interface property.

Tone Source Filter Prefered Format Property Page

Additionally, the filter may configured as a system-wide available audio input device, such as for example available to VLC Media Player or Media Player Classic:

VLC Media Player's Option to use Tone Source Filter based device

In order to configure the filter as such device, the library exports function DoToneSourceFilterDevicePropertySheetModal, which can be called using rundll32 utility (“rundll32 Acquisition.dll,DoToneSourceFilterDevicePropertySheetModal” from command line):

Devices Property Page

A partial Visual C++ .NET 2008 source code is available from SVN, release binary included.

File and Class Summary

Acqusition.dll

Acqusition.dll (download) hosts the following classes:

  • DirectShow Filters
    • Tone Source Filter, to generate reference/debug audio data

Class Overview

Tone Source Filter

The filter generates uninterrupted or interrupted reference sine waveform in form of PCM audio data.

Remarks

The hosting library (DLL) exposes DoToneSourceFilterDevicePropertySheetModal function which provides GUI to configure the filter as one or more audio capture source device, which can be enumerated by System Device Enumerator.

Published by Roman on 14 Feb 2009

MediaTools: HTTP Stream File Renderer Filter and more

In order to better troubleshoot network cameras and other devices, I added a new DirectShow filter to write HTTP response headers and body into a single file, one file (actually a pairs of files, the second file contains UTF-8 formatted HTTP response headers) per HTTP response.

While troubleshootting JPEG artefact issue with I used the following graph:

HTTP Stream File Renderer Filter in Filter Graph

which started M-JPEG streaming from a camera and had entire stream written into Response-01586228-0001-0001-Headers.txt (Headers) and Response-01586228-0001-0001.dat (Data) files, while parsed JPEG frames were also written into individual files and were available for comparison.

Other changes include:

  • new HTTP Stream File Renderer Filter (details are below)
  • attachable media types on internally used memory allocators, which enable filters to effectively reagree media types in running state
  • workaround for Panasonic BL-C140 camera (may be also helpful for other models), details here

There also seems to be a bug in Intel IPP 6.0 JPEG decoder that leaves bottom right image block incorrectly decoded, only when a sequence of images is decoded and the frame is not the first in the sequence.

A partial Visual C++ .NET 2008 source code is available from SVN, release binary included.

Continue Reading »

Published by Roman on 07 Feb 2009

Developer Goodies: ListResources to create an XML file from binary resources

At some point you might need to start paying special care for resources. Why? Perhaps there might be a number of reasons, I had to when I was dealing with first OEM versions of software and then internationalization. The whole idea is to let development team keep on working on regular version of software, in English language, while build OEM versions and localized versions of software by only manipulation with resources. It is an extremely important aspect of development because engineers always have full hands of work to do and there is no justification for getting extra work for them to deal with.

The first stage is development of regular English version of software and then other people replace resources to achieve desired branding (strings, titles, messages, icons, logos, version information, digital signatures; localized version whether they are resource duplicates for other languages or satellite DLLs), synchronize translations, prepare setup and distribution files.

One of the really simple and useful utilities on this way is the one that converts linked resources into a human readable file, so that it is possible to search for specific string through all resources of a binary (and actually all resources of the package if a batch makes such text files out of all binaries and then Find in Files Visual Studio .NET IDE feature is used).

ListResources writes an XML formatted file and prints infomration about:

  • resource types, identifiers and languages
  • extended information about:
    • menus RT_MENU
    • dialog templates RT_DIALOG
    • string tables RT_STRING
    • message tables RT_MESSAGETABLE
    • version information RT_VERSION
C:\ListResources "%WINDIR%\system32\winhttp.dll" >winhttp.xml

Continue Reading »

Next »