Quantcast
Channel: The Old New Thing
Viewing all 3085 articles
Browse latest View live

Why are custom properties created on Windows 2000 lost when I view the file from newer versions of Windows?

$
0
0

In Windows 2000, Explorer let you add properties like Summary and Author to nearly any file type. But when you view the files from a machine running Windows XP or later, those properties are lost. Where did they go?

Most file types do not have extensibility points for adding metadata. For example, every byte of a plain text files is devoted to text data; there is nowhere to put metadata like Author or Summary. In Windows 2000, the shell chose to store this extra information in NTFS alternate data streams (or more accurately, the shell chose to use the STGFMT_FILE storage format, which is implemented in terms of NTFS alternate data streams.) Storing the information in alternate data streams attaches the data to the file without affecting the file contents.

This was a clever idea, taking advantage of NTFS's ability to attach arbitrary data to a file, but it also had a serious problem: Alternate streams are not preserved by simple and common operations like sending the file by email, copying the file to a (FAT-formatted) USB thumb drive, uploading or downloading the file from a Web site, or burning the file to a CD. Basically, once the file leaves the comfortable confines of your local hard drive, there's a good chance that the metadata will be destroyed.

To avoid this problem, Windows XP switched to storing the metadata in the file contents itself. Doing this, however, requires support from the file format. Each file type can have registered for it a property handler which describes how to read and write properties for a file. (Windows itself comes with a few such handlers, such as for JPEG images and MP3 files, with more recent versions of Windows supporting more properties.) If no such property handler is registered, the shell will use structured storage, provided the file format is compatible with structured storage.

The data you added in Windows 2000 are still there. It's just that newer versions of Windows don't bother looking for them. (If you were sufficiently resourceful, you could write a program which opens the file in STGFMT_FILE mode, reads the properties, then reopens the file via the shell namespace and writes the properties back out.)

For lots of programming goodness about the shell property system, check out Ben Karas's blog, which I have been liberally linking to.


Just for fun: Sample user names in Windows 7

$
0
0

There are a few places in Windows where you are asked to enter your name in order to set up an account. Just for fun, I went through all the localized versions I could find and extracted the sample names. Some locales did not get around to translating all the strings. If the string was left untranslated (which can happen for LIPs), then I left the box blank. (Locales which did not translate either string have been omitted from the table.)

My reactions after the table.

ID English name for example, John For example: John Smith
af-za Afrikaans byvoorbeeld, John Voorbeeld: Jan Smit
am-et Amharic ለምሳሌ: አበበ ከበደ
ar-sa Arabic على سبيل المثال، أمجد على سبيل المثال: أشرف ماهر
as-in Assamese উদাহৰণৰ কাৰণে, প্ৰবিন উদাহৰণ স্বৰূপে: জন স্মিথ
az-latn-az Azerbaijani məsələn, Fərhad Məsələn: Vüsal Tahirov
bg-bg Bulgarian например Kiril Например: Пламен Христов
bn-bd Bengali (Bangladesh) উদাহরণস্বরূপ, জন উদাহরণস্বরূপ: জন স্মিথ
bn-in Bengali (India) উদাহরণস্বরূপ, রাম উদাহরণস্বরূপ: জন স্মিথ
bs-cyrl-ba Bosnian (Cyrillic) напримјер John Напримјер: Алмир Алмировић
bs-latn-ba Bosnian (Latin) naprimjer John Naprimjer: Almir Almirović
ca-es Catalan per exemple, Jordi Per exemple: Pau Solà
cs-cz Czech například Tereza Příklad: Jan Novák
cy-gb Welsh Siôn, er enghraifft Er enghraifft: Siân Jones
da-dk Danish f.eks. Claus Eksempel: Jens Jensen
de-de German N/A Beispiel: Jens Mander
el-gr Greek για παράδειγμα, Γιάννης Για παράδειγμα: Γεώργιος Βασιλείου
en-us English for example, John For example: John Smith
es-es Spanish por ejemplo, Juan Por ejemplo: Jorge López
et-ee Estonian näiteks Jaan Näiteks: Mati Kask
eu-es Basque esaterako, Rafa Adibidez: Ane Lizarralde
fa-ir Persian برای مثال، John
fi-fi Finnish esimerkiksi Juha Esimerkki: Henri Rautiainen
fil-ph Filipino halimbawa, Juan Halimbawa: Juan dela Cruz
fr-fr French par exemple Rosalie Par exemple : Marie Dubois
ga-ie Irish mar shampla, Seán Mar shampla: Seán Ó Murchú
gl-es Galician por exemplo: Xiana Por exemplo: Duarte Vidal
gu-in Gujarati ઉદાહરણ તરીકે, કમલેશ ઉદાહરણ તરીકે: કમલેશ દવે
ha-latn-ng Hausa A misali:John Smith
he-il Hebrew לדוגמה, John לדוגמה: משה כהן
hi-in Hindi उदाहरण के लिए, अमित उदाहरण के लिए: जनमेजय सिंह सिकरवार
hr-hr Croatian na primjer, Zdenko Primjerice: Ivan Kovač
hu-hu Hungarian például Lilian Például: Tót Béla
hy-am Armenian օրինակ՝ Արամ Օրինակ. Արմեն Արմենյան
id-id Indonesian misalnya, John Misalnya: John Smith
ig-ng Igbo iji maatụ, Chukwubike-ụgbaja Ọmụmatụ̀: Ụgbaja Chukwubuike Greg
is-is Icelandic til dæmis Jón Dæmi: Jón Jónsson
it-it Italian ad esempio, Luca Ad esempio: Valeria Dal Monte
iu-latn-ca Inuktitut Suurlu: John Smith
ja-jp Japanese 例: John 例: Taro Chofu
ka-ge Georgian მაგ. Nino მაგალითად: დიმიტრი გოგელია
kk-kz Kazakh мысалы, Джон Мысалы: Аманбайқызы Айнұр
km-kh Khmer ឧទាហរណ៍ John ឧទាហរណ៍: John Smith
kn-in Kannada ಉದಾಹರಣೆಗೆ, ಜಾನ್ ಉದಾಹರಣೆಗೆ: ಜಾನ್ ಸ್ಮಿತ್
ko-kr Korean 예: John 예: 홍길동
kok-in Konkani देखीक, जॉन देखीक: जॉन स्मिथ
ky-kg Kirghiz Мисалы: Тилек Чубаков
lb-lu Luxembourgish z. Bsp., John Zum Beispill: Marc Majerus
lt-lt Lithuanian pvz., Jonas Pvz., Jonas Jonaitis
lv-lv Latvian piemēram, Jānis Piemēram: Jānis Zariņš
mi-nz Māori Hei tauira: Hone Mete
mk-mk Macedonian на пример, Зоран На пример: Бранко Стојановски
ml-in Malayalam ഉദാ: ജോണ് ഉദാഹരണമായി: John Smith
mr-in Marathi उदाहरणासाठी, जॉन उदाहरणार्थ: जॉन स्मिथ
ms-bn Malay (Brunei) sebagai contoh, John Sebagai contoh: John Smith
ms-my Malay (Malaysia) sebagai contoh, John Sebagai contoh: John Smith
mt-mt Maltese pereżempju, John Eżempju: John Pace
nb-no Norwegian (Bokmål) for eksempel Kim Eksempel: Jens Jensen
ne-np Nepali उदाहरणार्थ, जोन उदाहरणको निमित्त: राम बहादुर
nl-nl Dutch bijvoorbeeld: Emma Bijvoorbeeld: Jan Smit
nn-no Norwegian (Nynorsk) for eksempel Kim Eksempel: Jens Jensen
nso-za Northern Sotho go fa mohlala, John Mohlala: John Smith
or-in Oriya ଉଦାହରଣ ସ୍ଵରୂପ, ଜୋନ୍ ଉଦାହରଣ ସ୍ଵରୂପ: ଦିପ୍ତି ରଞ୍ଜନ
pa-in Panjabi ਉਦਾਹਰਣ ਦੇ ਲਈ, ਜੌਨ ਉਦਾਹਰਣ ਦੇ ਲਈ: John Smith
pl-pl Polish na przykład: Tomek Na przykład: Jan Kowalski
pt-br Portuguese (Brazil) por exemplo, Marcio Por exemplo: João Silva
pt-pt Portuguese (Portugal) por exemplo: Rui Por exemplo: Jorge Santos
qps-ploc Pseudo ƒŏг єжåмþľę, Јσĥň [sqymS][₣óя εхдmþĺĕ: Јǿћη Šмīťђ !!! !!]
qps-mirr Pseudo (Mirrored) [For example: John Smith]
quz-pe Quechua qatina, Juan Kay hina: Jorge Lopez
ro-ro Romanian Ion, de exemplu De exemplu: Ion Popescu
ru-ru Russian например, Андрей Например: Иван Петров
si-lk Sinhala නිදසුන් ලෙස, නිමල් නිදසුනක් ලෙස: Don Lasith
sk-sk Slovak napríklad Ján Príklad: Peter Kováč
sl-si Slovene na primer Janez Na primer: Janez Kranjski
sq-al Albanian për shembull, Vehbi Për shembull: Vehbi Neziri
sr-cyrl-cs Serbian (Cyrillic) на пример, Јован На пример: Петар Петровић
sr-latn-cs Serbian (Latin) na primer, Jovan Na primer: Petar Petrović
sv-se Swedish t.ex. Rebecca Exempel: John Smith
sw-ke Swahili kwa mfano, Yohana Kwa mfano: Mussa Joseph
ta-in Tamil எடுத்துக்காட்டாக, ஜான் உதாரணத்திற்கு: குமார்
te-in Telugu ఉదాహరణకు, వేణు ఉదాహరణకు: రామ్ లక్ష్మణ్
th-th Thai ตัวอย่างเช่น John ตัวอย่างเช่น: John Smith
tn-za Tswana sekai, Tidimalo Sekao jaaka: P‌ule Molefe
tr-tr Turkish örneğin, Can Örneğin: Kemal Etikan
tt-ru Tatar мәсәлән, Фәрит Мәсәлән: Гали Вәлиев
uk-ua Ukrainian наприклад, Тарас Наприклад: Тарас Руденко
ur-pk Urdu مثال کے طور پر, امجد مثال کے طور پر: صفدر رشيد
uz-latn-uz Uzbek masalan, Akmal Masalan: Adham Soliyev
vi-vn Vietnamese ví dụ, John Ví dụ: John Smith
yo-ng Yoruba bí àpẹẹrẹ, Jòhánù Bí àpẹẹrẹ: John Smith
zh-cn Chinese (PRC) 例如: John 例如: 李建国
zh-hk Chinese (Hong Kong) 例如,John
zh-tw Chinese (Taiwan) 例如,John 範例: 祝英台
zu-za Zulu isibonelo, John Isibonelo: John Smith

Some observations:

  • Many languages translated the words "for example" but left the name as John or John Smith. I'm looking at you, Sweden. "John Smith"? Really? You couldn't have changed it to Sven Svensson?
  • Some languages chose generic names (like Jan Novák), keeping to the spirit of the English sample name. Others chose to substitute a real name (like Marie Dubois). [Update: See correction from Hardt.]
  • German doesn't provide a sample first name. My guess is that they ran out of room! The string Geben Sie einen Benutzernamen ein: probably took up all the space in the dialog, leaving no room for an example. [Update: See explanation of name Jens Mander from Roland.]
  • This information (and plenty of other translation goodness) is publically available for non-commercial use.

Related: The Locales of Windows 7, all divvied up.

My evil essence revealed

$
0
0

I found it amusing that somebody considered the fact that Microsoft employees can read my queued-up blog entries before the articles are published to be further evidence of Microsoft's evil essence as a monopoly.

Just for the record, this is not evidence of Microsoft's evil essence as a monopoly. Rather, it's evidence of Raymond's evil essence as a monopoly, because the monopoly on blog articles written by Raymond Chen that haven't yet been published belongs to me.

How do I prevent users from pinning my program to the taskbar?

$
0
0

A customer wanted to prevent users from pinning their application to the taskbar.

I have an application that is launched as a helper by a main application. Users shouldn't be launching it directly, but rather should be launching the main application. But since the helper shows up in the taskbar, users may be tempted to right-click on the taskbar icon and select "Pin to taskbar." Unfortunately, this pins the helper program to the taskbar instead of the main application, and launching the helper program directly doesn't work. Is there a way I can prevent users from pinning the helper program?

It so happens that there are a number of ways of marking your helper program as Don't pin me. Given the description above, the most direct way is probably to set the System.App­User­Model.Prevent­Pinning property on the window created by the helper program.

Take our scratch program and make the following changes:

#include <shellapi.h>
#include <propsys.h>
#include <propkey.h>

HRESULT MarkWindowAsUnpinnable(HWND hwnd)
{
 IPropertyStore *pps;
 HRESULT hr = SHGetPropertyStoreForWindow(hwnd, IID_PPV_ARGS(&pps));
 if (SUCCEEDED(hr)) {
  PROPVARIANT var;
  var.vt = VT_BOOL;
  var.boolVal = VARIANT_TRUE;
  hr = pps->SetValue(PKEY_AppUserModel_PreventPinning, var);
  pps->Release();
 }
 return hr;
}


BOOL
OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
{
 MarkWindowAsUnpinnable(hwnd);
 return TRUE;
}

I set the PROP­VARIANT manually instead of using Init­Prop­Variant­From­Boolean just to emphasize that the boolVal must be VARIANT_TRUE and not TRUE. In real life, I probably would have used Init­Prop­Variant­From­Boolean.

Run this program and observe that "Pin this program to taskbar" does not appear on the menu when you right-click on the taskbar button.

Even better would be to permit pinning, but set the System.App­User­Model.Relaunch­Command, .Relaunch­Display­Name­Resource and optionally .Relaunch­Icon­Resource properties so that if the user tries to pin the helper, it actually pins the main application.

Start with a new scratch program and make these changes:

#include <shellapi.h>
#include <propsys.h>
#include <propkey.h>
#include <propvarutil.h>

HRESULT IPropertyStore_SetValue(IPropertyStore *pps,
    REFPROPERTYKEY pkey, PCWSTR pszValue)
{
 PROPVARIANT var;
 HRESULT hr = InitPropVariantFromString(pszValue, &var);
 if (SUCCEEDED(hr))
 {
  hr = pps->SetValue(pkey, var);
  PropVariantClear(&var);
 }
 return hr;
}

BOOL
OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
{
 IPropertyStore *pps;
 HRESULT hr = SHGetPropertyStoreForWindow(hwnd, IID_PPV_ARGS(&pps));
 if (SUCCEEDED(hr)) {
  IPropertyStore_SetValue(pps,
    PKEY_AppUserModel_ID, L"Contoso.Scratch");
  IPropertyStore_SetValue(pps,
    PKEY_AppUserModel_RelaunchCommand,
    L"notepad.exe %windir%\\system.ini");
  IPropertyStore_SetValue(pps,
    PKEY_AppUserModel_RelaunchDisplayNameResource,
    L"C:\\full\\path\\to\\scratch.exe,-1");
  // optionally also set PKEY_AppUserModel_RelaunchIconResource
  pps->Release();
 }
 return TRUE;
}

// resource file
STRINGTABLE BEGIN
 1 "Open system.ini"
END

I'm pulling a fast one here and pretending that Notepad is my main application. Obviously you'd use your actual main application. (I'm also hard-coding the path to my scratch program.)

When you run this program, right-click on the taskbar button. Observe that the option to run a new copy of the program is called Open system.ini and if you pick it (or use the middle-mouse-button shortcut), Notepad runs. If you pin the program, the pinned icon runs Notepad.

Even if you don't need to redirect the pinned item to another program, you can use this second technique to pass a custom command line for the pinned icon.

How do I control X-Mouse settings (active window tracking)?

$
0
0

For quite some time, Windows has had a setting officially called active window tracking but which informally goes by the name X-Mouse, because that was the name of the PowerToy which first exposed the feature. (The PowerToy was in turn so-named because it made the mouse behave in a manner similar to many X window managers.) The setting is exposed to end users in Windows 7 on Make the mouse easier to use under Activate a window by hovering over it with the mouse.

If you want to write your own PowerToy to control this setting, you can do so by calling the SystemParametersInfo function. There are three settings which collectively control the X-Mouse feature:

  1. SPI_SETACTIVEWINDOWTRACKING: This is the master switch which enables the behavior.
  2. SPI_SETACTIVEWNDTRKZORDER: This controls whether the window is brought to the top when it is activated by active window tracking.
  3. SPI_SETACTIVEWNDTRKTIMEOUT: This controls how long the mouse has to be in a window before it is auto-activated.

Note that X-Mouse is a user preference. Applications should not change the setting without the user's permission.

Swamping the thread pool with work faster than it can drain

$
0
0

This scenarios is real, but details have been changed to protect the guilty.

Consider a window showing the top of a multi-page document. The developers found that when the user clicks the down-arrow button on the scroll bar, the program locks up for 45 seconds, over a dozen threads are created, and then suddenly everything clears up and the window displays the final paragraph of the document (i.e., it scrolled all the way to the bottom).

The problem was traced to queueing tasks to the thread pool faster than they can drain.

The document is an object which, unlike a window, has no thread affinity. (Naturally, there are critical sections around the various document methods so you don't have corruption if two threads try to modify the document at the same time.) The way to display a different portion of the document is to call a method which changes the viewport location.

When the user clicks the down-arrow button on the scroll bar, the main thread creates a periodic timer at four fifths of the double-click speed, and each time the timer elapses, it does the equivalent of document.ScrollDown(). The code cancels the timer once the user releases the mouse button.

The catch is that the document was so complicated that it takes a long time to change the view top and redraw the new view. (I don't remember exactly how long, but let's say it was 700ms. The important thing is that it takes longer than 400ms.)

Given that set-up, you can see what happens when the user clicks the scroll down-arrow. The initial scroll is initiated, and before it can complete, another scroll is queued to the thread pool. The document view keeps trying to update its position, but the periodic timer generates scroll requests faster than the document view can keep up.

If that description was too terse, here's a longer version.

The code for scrolling went something like this:

OnBeginScrollDown()
{
 // Start a timer to do the scrolling
 CreateTimerQueueTimer(&htimer, NULL, ScrollAgain, NULL,
     0, GetDoubleClickTime() * 4 / 5, WT_EXECUTEDEFAULT);
}

OnEndScrollDown()
{
 if (htimer != NULL) {
  DeleteTimerQueueTimer(NULL, htimer, INVALID_HANDLE_VALUE);
  htimer = NULL;
 }
}

ScrollAgain(...)
{
 document.ScrollDown();
}

(In reality, the program didn't use the CreateTimerQueueTimer function—it had a custom timer queue and a custom thread pool—but the effect is the same.)

At time T = 0, the user clicks on the scroll bar down-arrow. The UI thread starts the timer with an initial delay of zero and a period of 400ms. The timer fires immediately, and a thread pool thread is asked to run ScrollAgain. The ScrollAgain function calls ScrollDown, which begins the process of scrolling the document.

At time T = 400ms, the periodic timer fires, and a new thread pool thread is created to service it. Pool thread 2 calls ScrollDown() and blocks.

At time T = 700ms, the ScrollDown call on pool thread 1 completes, and now pool thread 2 can begin its call to ScrollDown().

At time T = 800ms, the periodic timer fires again, and pool thread 1 (now idle) is asked to handle it. Pool thread 1 calls ScrollDown() and blocks.

At time T = 1200ms, the periodic timer fires yet again. This time, there are no idle threads in the thread pool, so the thread pool manager creates yet another thread to service the timer. Pool thread 3 calls ScrollDown() and blocks.

At time T = 1400ms, the ScrollDown() call issued by pool thread 2 completes. Pool thread 2 now returns to idle. Now the call to ScrollDown() from pool thread 1 (issued at time T = 800ms) can start.

At time T = 1600ms, the periodic timer fires again, and pool thread 2 is chosen to service it. Pool thread 2 calls ScrollDown() and blocks.

At time T = 2000ms, the periodic timer fires again, and a new pool thread is created to service it. Pool thread 4 calls ScrollDown() and blocks.

You can see where this is going, I hope. Work is being generated by the periodic timer at a rate of one work item per 400ms, but it takes 700ms to carry out each work item, and the tasks are serialized on the document. It's like Lucy in the chocolate factory. The document is frantically trying to carry out all the work, and it never manages to catch up. Eventually, the document scrolls all the way to the bottom, and the mass of pent-up calls to ScrollDown() all return immediately since there is no more scrolling possible.

Now that the document is idle, it can paint, and that's where the user finally sees the document, scrolled all the way to the bottom.

There are a number of possible solutions here.

One way is not to queue up another scroll while an old one is still running. Instead, just wait for it to finish, and then issue a new scroll that accumulates all the scrolling that had taken place while you were waiting for the first to complete. This results in jerky scrolling, however, and it creates a lag of up to 700ms between the user releasing the mouse button and scrolling actually stopping.

Another approach is to disable repainting the entire document when you detect that you are in the document is too complex to scroll quickly case and just scroll the scrollbar thumb. When the user stops scrolling, re-enable painting and boom the document appears at the user's chosen location. This preserves responsiveness, but you lose the ability to see the document as you scroll it.

I don't know what solution the customer finally went with. I was just there to help with the debugging.

Bonus example: Larry Osterman describes another situation with the same underlying cause.

Hidden take-away: Observe that both of these examples illustrate one of the subtle consequences of a design which moves all processing off the UI thread.

Update: Note that Set­Timer wouldn't have helped here.

case WM_TIMER:
  if (wParam == SCROLLTIMER) {
    QueueUserWorkItem(ScrollAgain, NULL, WT_EXECUTEDEFAULT);
  }
  ...

Since the processing has been moved off the UI thread, the WM_TIMER messages are free to keep flowing in and queue up work faster than the background thread can keep up.

Why do Group Policy settings require me to have a degree in philosophy?

$
0
0

Josh points out that Group Policy settings often employ double-negatives (and what's the difference between turning something off and not configuring it)?

Group Policy settings are unusual in that they are there to modify behavior that would continue to exist without them. They aren't part of the behavior but rather a follow-on. Suppose that the default behavior is to do XYZ automatically, but due to requests from corporate customers, a Group Policy is added to alter this behavior. The Group Policy for this might look like this:

Don't do XYZ automatically




The template for boolean Group Policy settings is

Blah blah blah




Consequently, every boolean Group Policy setting is forced into the above format, even if the setting is reverse-sense, as our sample one is. In general, the three settings for a Group Policy mean

Enabled Change the behavior as described in the title of the group policy.
Disabled Do not change the behavior and continue with the default behavior.
Not configured Let somebody else decide.

The difference between Disabled and Not configured is that when you disable a Group Policy, then you're saying "Restore default behavior." On the other hand, if you don't configure a Group Policy setting, then you're saying "I have no opinion about whether this Group Policy should be enabled or disabled, so keep looking, because there might be another Group Policy Object that does express an opinion."

Recall that multiple Group Policy Objects can apply to a specific user. For example, a typical user may be subject to a Local Group Policy, a Non-Administrator Local Group Policy, a series of other Group Policies depending on what security groups the user belongs to, and then a User-Specified Group Policy. You can use the Resultant Set of Policy snap-in to see how all these different Group Policy Objects interact.

The upshot of this is that Group Policy settings often end up using double negatives if the policy is to disable a default behavior. You "Enable" the setting to disable the default behavior, you "Disable" the setting to enable the default behavior, and you leave the setting "Not configured" if you want to let some other Group Policy Object decide. Even when there is a more clever way of wording the options to avoid the double negative, the people who write Group Policy descriptions are so used to double-negatives that it doesn't even occur to them that a particular setting setting permits an optimization. (Either that, or they figure that system administrators are so used to seeing double-negatives, that when it's not there, they get confused!)

You'd think that with the name scratch, people wouldn't expect it to be around for a long time

$
0
0

There is a server run by the Windows team called scratch. Its purpose is to act as a file server for storing files temporarily. For example, if you want to send somebody a crash dump, you can copy it to the scratch server and send the person a link. The file server is never backed up and is not designed to be used as a permanent solution for anything.

The Windows team likes to use the server to test various file server features. For example, the scratch server uses hierarchical storage management and migrates files to tape relatively aggressively, so that the HSM development team can get real-world usage of their feature.

The file system team will occasionally wipe the hard drives on the server and reformat them with a new version of NTFS, so that they can put the new file system driver through its paces in a situation where it is under heavy load.

When these sort of "mass extinction events" takes place, you can count on somebody sending out email saying, "Hey, what happened to the sprocket degreaser? It was on \\scratch\temp\sprocket_degreaser, but now I can't find it. I have an automated test that relies on the sprocket degreaser as well as some data files on \\scratch\temp\foobar_test_data, and they're all gone!"

Um, that's a scratch machine. Why would you put important stuff on it?

"Um, well..." (scratches forehead)

Okay, well before we reformatted the hard drive, we copied the data to \\scratch2\save, so try looking there. But remember, the scratch server is for temporary file storage and comes with no service level agreement.

"Oh, phew, thanks."

You'd think that with the name scratch, people wouldn't expect it to be around for a long time. Maybe they could call it can_be_reformatted_at_any_time.

[Raymond is currently on his way to sunny Hawaii; this message was pre-recorded. Mahalo.]


Microspeak: The planned unplanned outage, and other operations jargon

$
0
0

The Operations group at Microsoft manage the servers which keep the company running. And they have their own jargon which is puzzling to those of us who don't spend all our days in a noisy server room.

  • Unplanned Unplanned Outage
  • Planned Unplanned Outage
  • Immediate Deployment Timeframe. This one even has its own TLA: IDT.

From what I can gather, an Unplanned Outage would be better termed an Unscheduled Outage: We did not have it marked off on our calendar that the server would be unavailable at this time, but it ended up that way. These unscheduled outages fall into two categories: An Unplanned Unplanned Outage is an unscheduled outage that took place of its own volition. In other words, the server crashed or somebody accidentally kicked the power cable. On the other hand, the paradoxically-named Planned Unplanned Outage is an unscheduled outage that took place because the operations team took the server down out of schedule. For example, the server may have started thrashing, and they think rebooting it will help.

But the one that sounds really Microspeaky is Immediate Deployment Timeframe. Here's a citation:

Date: June 7, 2011 4:52 PM

...
Due to the critical nature of this issue, the hotfix will be deployed in an Immediate Deployment Timeframe. All affected servers will be remediated on June 8.

Start: June 7, 2011 11:00PM
End: June 8, 2011 12:00AM

In other word, Immediate Deployment Timeframe means as soon as possible. Note, however that it doesn't mean now, which is what I originally thought immediate meant until I looked at the start/end times and compared them to the message time. There must be some other TLA that means now, but what is faster than immediate?

Bonus Microspeak: remediate.

[Raymond is currently away; this message was pre-recorded.]

PE resources must be 4-byte aligned, but that doesn't stop people from trying other alignments

$
0
0

Resources in PE-format files must be stored at offsets which are a multiple of four. This requirement is necessary for platforms which are sensitive to data alignment.

That doesn't stop people from breaking the rules anyway. After all, it sort of works anyway, as long as you're careful. I mean, sure maybe if somebody running a non-x86 version of Windows tries to read your resources, they will crash, but who uses non-x86 versions of Windows, right?

In Windows Vista SP1, additional hardening was added to the resource parsing code to address various security issues, but the one that's important today is that tests were made to verify that the data were properly aligned before accessing it. This prevents a file with a misaligned version resource from crashing any program that tried to read its resources. In particular, it is common for programs to read the version resources of arbitrary files—for example, Explorer does it when you view the file's properties or if you turn on the Description column in Details view—so enforcing alignment on resources closes that avenue of remote denial of service.

And then the bug reports came in. "Program XYZ fails to install" because the program tries to read its own version resources and cannot, because the tool they used to build the program cheated on the alignment requirement and stored the resources at offsets that aren't multiples of 4. "I mean, come on, that wastes like three bytes per resource. Everything still worked when we removed the alignment padding, so we went ahead and shipped it that way."

Another example of a program that stopped working when the alignment rules were enforced was a computer game expansion pack which could not install because the code that tried to verify that you had the base game found itself unable to read its version resources.

Multiple programs refused to run, preferring to display the error message "AppName is not a valid Win32 application." Presumably, as part of initialization, they tried to read their own version resources, which failed with ERROR_BAD_EXE_FORMAT, which they then showed to the user.

The fix was to relax the enforcement of the rules back to the previous level, and impose the stricter requirements only on architectures which raise exceptions on misaligned data. It does mean that you can have a program whose resources can be read on one machine but not on the other, but that was deemed a lesser evil than breaking all the programs which relied on being able to misalign their data without consequence.

[Raymond is currently away; this message was pre-recorded.]

Generally speaking, if your function fails, you should return a failure code

$
0
0

A customer requested assistance with their shell namespace extension, and the request worked its way to me for resolution.

Unhandled exception at 0x76fab89c (shell32.dll) in explorer.exe: 0xC0000005:
Access violation reading location 0x00000000.

shell32.dll!CShellItem::_GetPropertyStoreWorker()  + 0x44 bytes
shell32.dll!CShellItem::GetPropertyStoreForKeys()  + 0x38 bytes
thumbcache.dll!CThumbnailCache::_GetMonikerDataFromShellItem()  + 0x8b bytes
thumbcache.dll!CThumbnailCache::GetThumbnail()  + 0x11c bytes
shell32.dll!CSetOperationCallback::_LookupThumbnail()  + 0x8d bytes
shell32.dll!CSetOperationCallback::_PrefetchCachedThumbnails()  + 0xb6 bytes
shell32.dll!CSetOperationCallback::OnNextBatch()  + 0x4f bytes
shell32.dll!CEnumTask::_PushBatchToView()  + 0x68 bytes
shell32.dll!CEnumTask::_IncrFillEnumToView()  + 0x2ca5 bytes
shell32.dll!CEnumTask::_IncrEnumFolder()  + 0x8da5a bytes
shell32.dll!CEnumTask::InternalResumeRT()  + 0xa6 bytes
shell32.dll!CRunnableTask::Run()  + 0x92 bytes
browseui.dll!CShellTask::TT_Run()  + 0x2d bytes
browseui.dll!CShellTaskThread::ThreadProc()  + 0x87 bytes
browseui.dll!CShellTaskThread::s_ThreadProc()  + 0x21 bytes
shlwapi.dll!_ExecuteWorkItemThreadProc@4()  + 0xe bytes
ntdll.dll!_RtlpTpWorkCallback@8()  + 0xaa bytes
ntdll.dll!_TppWorkerThread@4()  + 0x274 bytes
kernel32.dll!@BaseThreadInitThunk@12()  + 0x12 bytes
ntdll.dll!__RtlUserThreadStart@8()  + 0x27 bytes

The customer was at a loss because the customer's code was nowhere on the stack. What is wrong?

The customer didn't provide a dump file or any other information beyond the stack trace. (Hint: When reporting a problem with a shell namespace extension, at least mention the last few method calls your namespace extension received before the crash.) I was forced to use my psychic powers to solve the problem. But you can, too. All the information you need is right there in front of you.

The shell faulted on a null pointer in the function CShellItem::_GetPropertyStoreWorker, which from its name is clearly a worker function which obtains the property store from a shell item.

At this point, you put on your thinking cap. Why is the shell taking a null pointer fault trying to retrieve the property store from a shell item? Remember that the problem is tied to a custom namespace extension.

My psychic powers tell me that the namespace extension returned S_OK from GetUIObjectOf(IPropertyStoreFactory) but set the output pointer to NULL.

(It turns out my psychic powers were weak without coffee, because the initial psychic diagnosis was GetUIObjecttOf(IPropertyStore) instead of IPropertyStoreFactory.)

As a general rule, if your function fails, then you should return a failure code, not a success code. There are exceptions to this rule, particular when OLE automation is involved, but it's a good rule to start with.

The customer reported that fixing their IShellFolder::BindToObject to return an error code when it failed fixed the problem. The customer then followed up with another crash, again providing startling little information.

Unhandled exception at 0x763cf7e7 (shell32.dll) in explorer.exe: 0xC0000005: 
Access violation reading location 0x000a0d70.

Call Stack:

shell32.dll!CInfotipTask::InternalResumeRT() + 0x2e bytes 
shell32.dll!CRunnableTask::Run() + 0x92 bytes 
browseui.dll!CShellTask::TT_Run() + 0x2d bytes 
browseui.dll!CShellTaskThread::ThreadProc() + 0x87 bytes 
browseui.dll!CShellTaskThread::s_ThreadProc() + 0x21 bytes 
shlwapi.dll!_ExecuteWorkItemThreadProc@4() + 0xe bytes 
ntdll.dll!_RtlpTpWorkCallback@8() + 0xaa bytes 
ntdll.dll!_TppWorkerThread@4() + 0x274 bytes 
kernel32.dll!@BaseThreadInitThunk@12() + 0x12 bytes 
ntdll.dll!__RtlUserThreadStart@8() + 0x27 bytes

The customer reported that IQueryInfo::SetInfoTip is getting called. The customer liaison added, "Raymond, I'm looking forward to your psychic powers again."

Apparently, some people don't understand that psychic powers are not something you ask for. It's my way of scolding you for not providing enough information to make a quality diagnosis possible. You don't come back saying, "Hey, thanks for answering my question even though I did a crappy job of asking it. Here's another crappy question!"

I reported back that my psychic powers were growing weary from overuse, and that the customer might want to expend a little more time investigating the problem themselves. Especially since it has the same root cause as their previous problem.

[Raymond is currently away; this message was pre-recorded.]

You don't need to steal focus if you can just arrange for someone to give it to you

$
0
0

Commenter doesn't matter proposes a scenario where focus-stealing is necessary: There are two applications A and B, Application B exposes an interface, and Application A connects to application B via that interface, When some sort of even occurs in application B, it notifies application A, which wants to steal focus in order to interact with the user as a result of the event.

Actually, this is still not a situation where focus-stealing is necessary. Application B just needs to call Allow­Set­Foreground­Window on application A before it fires the event, so that when application A receives the event, it can display its dialog box or whatever. If the communication channel is via a window message, you can use Get­Window­Thread­Process­Id to get the process ID of application A. If the communication channel is COM, you can use Co­Allow­Set­Foreground­Window. If the communication channel is something else, well, then you'll have to use whatever mechanism works for your communication channel. (Obviously there must be at some point a place in the communication channel where it can figure out the identity of application A, since it needs to talk to application A to deliver the event in the first place.)

If you don't have access to the source code of application B, then you get to work with whoever designed the interface to convince them to add the necessary call for you.

But outright stealing the focus is the wrong thing to do, because it presumes that the user was interacting with application B when the event was fired. What if the event fired while application B was not the focus? Even if the event is a user interface event, like a mouse click, it's possible that the event will fire even though application B doesn't have the focus: Application B may receive the mouse click, and while application B decides what to do with it, the user switches to application C. Eventually, application B fires the event, but at this point the user is no longer working with application B, and transfering focus to application A would count as one of those evil focus-stealing situations.

Just because there's no good way to do something doesn't mean that you are automatically permitted to do it in a bad way.

Bonus chatter: Sometimes I wonder about the people who use the principle If I can't do something legally, I should be allowed to do it illegally, and then get indignant when they are caught.

"You got a parking ticket because you were parked in a handicapped space without a permit."

But all the regular parking spaces were taken. I had to park in a handicapped space; I had no other choice. You can't give me a ticket for that!

[Raymond is currently away; this message was pre-recorded.]

Sufficiently advanced magic is indistinguishable from technology

$
0
0

An informal tradition in a former group was that whenever somebody bought a new car, we all went out to lunch to celebrate, but the person with the new car had to be one of the drivers.

During one of our new-car trips, the proud owner of the new car showed off its fancy features. "Check this out, this car has a voice-controlled radio: Radio, On."

The car radio turned on.

"Radio, Select KUOW."

The radio changed its station.

"Radio, louder."

The volume went up.

But this wasn't a demonstration of voice-recognition technology. It was a magic trick.

You see, the car has radio controls built into the back of the steering wheel.

[Raymond is currently away; this message was pre-recorded.]

How do I convert a UTF-8 string to UTF-16 while rejecting illegal sequences?

$
0
0

By default, when you ask Multi­Byte­To­Wide­Char to convert a UTF-8 string to UTF-16 that contains illegal sequences (such as overlong sequences), it will try to muddle through as best as it can. If you want it to treat illegal sequences as an error, pass the MB_ERR_INVALID_CHARS flag.

The MSDN documentation on this subject is, to be honest, kind of hard to follow and even includes a double-negative: "The function does not drop illegal code points if the application does not set this flag." Not only is this confusing, it doesn't even say what happens to illegal code points when you omit this flag; all it says is what it doesn't do, namely that it doesn't drop them. Does it set them on fire? (Presumably, if you omit the flag, then it retains illegal code points, but how do you retain an illegal UTF-8 code point in UTF-16 output? It's like saying about a function like atoi "If the value cannot be represented as an integer, it is left unchanged." Huh? The function still has to return an integer. How do you return an unchanged string as an integer?)

How do I create a right-aligned toolbar button?

$
0
0

I didn't think this was all that common a request, but it came in twice from two different customers, so I guess there are still people creating toolbars, and creating them with right-aligned buttons (even though it violates Windows user interface guidelines, though I can't find a citation right now).

You may have noticed that the toolbar common control doesn't provide a facility for creating right-aligned buttons. Partly because it's a violation of the guidelines anyway, but mostly because the default state of every feature is "not implemented." Adding a feature requires work, and since there is only a finite amount of work available to apply, you have to decide where to spend it. And generally speaking, you don't focus your efforts on helping people violate the guidelines.

If you want to create a right-aligned toolbar button, you can cobble one together by combining things you already have. I can think of two ways of doing this off the top of my head.

  • Create two toolbars, one for the left-aligned buttons and one for the right-aligned buttons, then size and position them appropriately.
  • Create a separator between the left-aligned buttons and the right-aligned buttons, and set the separator size appropriately.

Which comes to a third reason why there is no feature for right-aligned toolbar buttons: Because you can already do it yourself without too much effort.


How do I make a window remain visible even when the user selects Show Desktop?

$
0
0

A customer had this question:

I'd like to know how to get a window to remain visible, even when the user has selected Show Desktop. Right now, when the user picks Show Desktop, the desktop appears and covers my window.

Um, yeah, because that's the whole point of Show Desktop: To show the desktop and get rid of all those windows that are in the way. Windows like yours.

We're sorry that Windows was unprepared for a program as awesome as yours, because there's no way to mark your window as even if the user says to show the desktop instead of this window, override the user's command and show the window anyway. (They're probably angling for a nice bonus.)

As a consolation prize, you can create a desktop gadget. Desktop gadgets are part of the desktop and raise with it. It so happens that upon further discussion, the customer was trying to write a clock-type program—this is something very well-suited to gadgetification.

A different customer had a related question, but disguised it behind another question:

I noticed that desktop gadgets remain on the desktop even if the user clicks Show Desktop. How does that work? How do gadget stay in front of the desktop when it is shown? What is the trick?

This was a rather odd question to come through the customer channel. And it probably wasn't just idle curiosity. You don't burn a support request for idle curiosity.

(While it's probably true that you don't burn a support request just for idle curiosity, I've seen support requests turn into idle curiosity. Once the customers got the answer to their question, they realized that since they had already burned a support request, they may as well pile on with follow-up questions that are just idle curiosity. That was not the case here, because the customer led with the question.)

The "trick" is that gadgets and the desktop know about each other, so when the user clicks Show Desktop, the desktop covers up all the windows on the screen and then takes the gadgets and places them on the desktop.

The customer's question is rather odd, because they ask "The system works like X. Are there any tricks for X?" The answer is the rather tautological "The trick for how the system works like X is that the system was designed to do X."

I suspect that the customer has a secret agenda they are unwilling to share. My guess is that their secret agenda is that they want to write a program that is exempt from being covered by the desktop when the user clicks Show Desktop, and they think they can do it by emulating whatever it is that gadgets do.

The customer liaison confirmed that that's what the customer is actually trying to do, but that the customer was being coy with the liaison as well and did not explain what the problem scenario was that made them think that they needed a program that is exempt from being covered by the desktop when the user clicks Show Desktop. The customer liaison went back to the customer with the explanation that the way to get the special gadget behavior is to be a gadget, and if they want to pursue it, then writing a gadget is what they need to do.

In Windows, the directory is the application bundle

$
0
0

Aaargh! wonders why Windows doesn't just steal the concept of bundles from Apple and package up each application with all its libraries and everything else it needs into a single directory.

This is such a great idea, it's been around since the early 1990's. It's just that Windows didn't give it a cute named like bundle. It just gave it the boring name directory. In other words, it's a victim of bad marketing. Maybe we should have given it a cute name like... elfgrass.

The first directory searched by the LoadLibrary function is the directory containing the application. If you put all your supporting libraries in the same directory as your EXE, and if you access non-library data via paths relative to your application directory, then then you have successfully packaged up your application with all its libraries and everything else it needs into a single directory. Congratulations, you pre-invented the bundle.

Indeed, Microsoft's guidance for over a decade has been to discourage copying files into the System32 directory.

If this facility has been around for nearly twenty years, why do people still copy files into the System32 directory?

Probably inertia. "We've always installed that way, and we're not changing it because we don't know what would stop working."

There may be some people concerned about disk space. "We have a bunch of applications which share some common libraries, and by putting the common libraries in a shared location (instead of in the application directory), we avoid wasting the user's disk space." Which raises the troublesome question: Is disk space still an issue nowadays?

Some people would say that no, disk space is no longer an issue. Hard drives are hundreds of gigabytes in size. Increasing the size of each application by a few dozen megabytes is just noise.

Other people would say that yes, disk space is still an issue. (Note how many people got excited when Snow Leopard took up less disk space.) Solid-state hard drives are still limited in size, and even for people with large hard drives, you see them freaking out about the disk space used by things like Windows Update, volume snapshot services, and System Restore. (Nevermind that at least for volume snapshots and System Restore, the disk space is automatically released when disk space starts to run low. It's like getting upset that the disk cache uses so much of your memory even though the computer is not under any memory pressure.)

Bonus reading: Disk space and Windows 7.

See you in Building 109, Conference Room A

$
0
0

We saw some time ago that if somebody invites you to a meeting in Building 7, they are inviting you off campus to take a break from work.

If somebody invites you to a meeting in Building 109, Conference Room A, they are inviting you to join them at the Azteca Mexican restaurant next door.

Update: One of the members of the "Building 109 Conference Room A" mailing list informed me that Building 109 Conference Room A is specifically the bar at the Azteca restaurant.

Update 2: Building 109 Conference Room A has its own mailing list!

How to get Windows Media Player to single-step a video

$
0
0

I always forget how to do this, so I'm going to write it down so I can look it up later.

When a video is playing, right-click the volume control slider and select Enhancements, then Play speed settings. (Actually, it also works if you right-click the speaker icon, the Stop button, the Replay button, or the Shuffle button, but the volume control slider is the biggest target.)

On the Play speed settings dialog, the single-step controls are at the bottom; they look like triangles.

How do I compress files (via NTFS compression) from the command line?

$
0
0

A customer wanted to know whether there was a way to compress files and directories (in the sense of NTFS compression) from a script or from the command line. They knew about the Properties dialog, but they wanted something scriptable.

The command-line tool for this is COMPACT.EXE. Type compact /? for usage information.

The customer liaison was grateful for this information.

Thanks for the prompt response, and yes, this will meet our customer's need to compress specific files such as *.docx under a particular directory and all its subdirectories.

Um, *.docx files are already compressed. Compressing them again gains you nothing.

Bonus reading: Functions for manipulating documents which follow the Open Package Conventions are available in both managed and unmanaged versions. Check out the Packaging Team Blog for more information, including a comparison of the managed and unmanaged versions.

Viewing all 3085 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>