• The Old New Thing

    Solving the problem rather than answering the question: How can a non-administrator modify a registry key that requires administrator permission?

    • 32 Comments

    A customer opened with a question, which the customer liaison forwarded to the product group with High Priority. (Because, apparently, their customer is more important than any other customer.)

    Our program needs to modify a registry key in HKEY_LOCAL_MACHINE even when not running as an administrator. We tried setting an entry in the registry key HKLM\Software\Microsoft\Windows NT\Current­Version\App­Compat­Flags\Layers to run our application elevated, but it didn't help. We also tried setting the entry in our application manifest to say that it requires elevation, but that didn't work either. Please provide us with a way to override UAC.

    The fact that they went in and tried to enable an application compatibility setting on their own application means that instead of fixing their program, they are just going to keep throwing garbage on the sidewalk and hope the street sweeper will still come and clean up behind them.

    Upon closer questioning, they explained that setting the manifest entry didn't work in the sense that when the user ran the program, the operating system prompted for elevation. But they wanted their program to elevate without prompting.

    Okay, first of all, if any program could could elevate without prompting, then there would be no point to elevation. Every program would simply ask for secret unprompted elevation, and there would be no point to elevation in the first place. So that angle is a non-starter.

    We asked them for details on the problem they are having, the problem where they think writing to HKLM is the solution. That way, we can solve the problem instead of answering the question.

    When our program is installed, it prompts the person doing the installation for the name of the server to connect to. The installer writes this information to HKLM. When a non-administrator runs the program, we want them to be able to switch to a different server. That's why we need to be able to write to HKLM.

    Okay, now that we understand the scenario, we can provide a solution.

    First of all, the reason why you can't write to HKLM is that it would allow a non-administrative user to change the server settings of another user. Suppose that I run the program and change the server to http://evil-hackers.example.com. Then I log off and wait. The next person to use the computer and run the program will connect to the hacker site instead of the real site, and now I can harvest credentials or launch a man-in-the-middle attack or otherwise do bad things.

    The solution, then, is to reduce the scope of any changes a non-administrative user makes to just that user. That way, if they choose to point the program at a rogue server, they are merely attacking themselves.

    • At install time, write the default server information to HKLM.
    • When a user changes the server, write the new server to HKCU.
    • When the program needs to decide which server to connect to:
      • Check if there is a local setting in HKCU. If so, then use it.
      • If there is no setting in HKCU, then use the setting in HKLM.
    • Optional: Add an administrative option to change the default server in HKLM.

  • The Old New Thing

    RegNotifyChangeKeyValue sucks less

    • 11 Comments

    One of the gotchas of the Reg­Notify­Change­Key­Value function is that the notification registration has thread affinity. This is a problem if you want the notification registration to outlive the thread that generated it. In particular, if you register the notification from a nonpersistent thread pool thread, you get into an infinite loop:

    1. Thread pool task calls Reg­Notify­Change­Key­Value, and waits for the associated event via Register­Wait­For­Single­Object.
    2. Thread pool thread goes idle.
    3. Thread pool destroys the idle thread.
    4. Due to thread affinity, this signals the handle.
    5. The thread pool queues a task to process the handle that was signaled.
    6. The task checks the registry key (observes that nothing changed) and calls Reg­Notify­Change­Key­Value again.
    7. Repeat.

    Windows 8 added a new flag to the Reg­Notify­Change­Key­Value function: REG_NOTIFY_THREAD_AGNOSTIC. If you pass this flag, then the notification registration does not have thread affinity. If the thread that called Reg­Notify­Change­Key­Value exits, the notification registration remains active.

  • The Old New Thing

    Why does the mouse cursor jump a few pixels if you click on the very bottom row of pixels on the taskbar?

    • 31 Comments

    ABCDSchuetze discovered that if you click on the very bottom row of pixels of the taskbar, the mouse cursor jumps up a few pixels. Why is that?

    In order to take advantage of Fitts's Law, the bottom-most row of pixels on a bottom-docked taskbar are clickable. Even though they are technically on the dead border of the window, the taskbar redirects the click to the button immediately above the border. But then you have this problem:

    • User clicks on the border pixel between the button and the edge of the screen.
    • The taskbar remaps the click to the button, thereby activating the button.
    • The button takes capture because that's what buttons do when you click on them. This allows you to drag off the button to cancel the click.
    • But wait: Since the mouse is on the border, it is already outside the button.
    • Result: The button cancels immediately.

    The short version: Clicking on the Fitts's edge causes the button to be pressed and then immediately canceled.

    The fix is to nudge the mouse back inside the button when the click begins.

  • The Old New Thing

    Nice job, you got an A minus from Bill

    • 15 Comments

    Bill Gates does not praise lightly.

    Some time ago, a colleague of mine helped to prepared a keynote address for Bill Gates. Afterward, he was informed that Bill rated the presentation an "A minus".

    My colleague thought, "Wow, an A minus. It would be great to get some feedback from Bill about where I could have done better."

    Bill's assistant explained, "Don't worry. That's the highest grade he gives."

  • The Old New Thing

    Further adventures in trying to guess what encoding a file is in

    • 8 Comments

    The Is­Text­Unicode function tries to guess the encoding of a block of memory purporting to contain text, but it can only say "Looks like Unicode" or "Doesn't look like Unicode", and there some notorious examples of where it guesses wrong.

    A more flexible alternative is IMulti­Language2::Detect­Code­page­In­IStream and its buffer-based equivalent IMulti­Language2::Detect­Input­Code­page. Not only can these methods detect a much larger range of code pages, they also can report multiple code pages, each with a corresponding confidence level.

    Here's a Little Program that takes the function out for a spin. (Remember, Little Programs do little to no error checking.)

    #define UNICODE
    #define _UNICODE
    #include <windows.h>
    #include <shlwapi.h>
    #include <ole2.h>
    #include <mlang.h>
    #include <shlwapi.h>
    #include <atlbase.h>
    #include <stdio.h>
    
    bool IsHtmlFile(PCWSTR pszFile)
    {
     PCWSTR pszExtension = PathFindExtensionW(pszFile);
     return
      CompareStringOrdinal(pszExtension, -1,
                           L".htm", -1, TRUE) == CSTR_EQUAL ||
      CompareStringOrdinal(pszExtension, -1,
                            L".html", -1, TRUE) == CSTR_EQUAL;
    }
    
    int __cdecl wmain(int argc, wchar_t **argv)
    {
     if (argc < 2) return 0;
     CCoInitialize init;
     CComPtr<IStream> spstm;
     SHCreateStreamOnFileEx(argv[1], STGM_READ, 0, FALSE, nullptr, &spstm);
    
     CComPtr<IMultiLanguage2> spml;
     CoCreateInstance(CLSID_CMultiLanguage, NULL,
         CLSCTX_ALL, IID_PPV_ARGS(&spml));
    
     DetectEncodingInfo info[10];
     INT cInfo = ARRAYSIZE(info);
    
     DWORD dwFlag = IsHtmlFile(argv[1]) ? MLDETECTCP_HTML
                                        : MLDETECTCP_NONE;
     HRESULT hr = spml->DetectCodepageInIStream(
         dwFlag, 0, spstm, info, &cInfo);
     if (hr == S_OK) {
      for (int i = 0; i < cInfo; i++) {
       wprintf(L"info[%d].nLangID = %d\n", i, info[i].nLangID);
       wprintf(L"info[%d].nCodePage = %d\n", i, info[i].nCodePage);
       wprintf(L"info[%d].nDocPercent = %d\n", i, info[i].nDocPercent);
       wprintf(L"info[%d].nConfidence = %d\n", i, info[i].nConfidence);
      }
     } else {
      wprintf(L"Cannot determine the encoding (error: 0x%08x)\n", hr);
     }
     return 0;
    }
    

    Run the program with a file name as the command line argument, and the program will report all the detected code pages.

    One thing that may not be obvious is that the program passes the MLDETECTCP_HTML flag if the file extension is .htm or .html. That is a hint to the detector that it shouldn't get faked out by text like <body> and think it found an English word.

    Here's the output of the program when run on its own source code:

    info[0].nLangID = 9
    info[0].nCodePage = 20127
    info[0].nDocPercent = 100
    info[0].nConfidence = 83
    info[1].nLangID = -1
    info[1].nCodePage = 65001
    info[1].nDocPercent = -1
    info[1].nConfidence = -1
    

    This says that its first guess is that the text is in language 9, which is LANG_ENGLISH, code page 20127, which is US-ASCII, That text occupies 100% of the file, and the confidence level is 83.

    The second guess is that the text is in code page 65001, which is UTF-8, but the confidence level for that is low.

    The language-guessing part of the function is not very sophisticated. For a higher-quality algorithm for guessing what language some text is in, use Extended Linguistic Services. I won't bother writing a sample application because MSDN already contains one.

  • The Old New Thing

    Non-capturing C++ lambdas can be converted to a pointer to function, but what about the calling convention?

    • 24 Comments

    First, let's look at how lambdas are implemented in C++.

    It is similar in flavor to the way lambdas are implemented in C#, but the details are all different.

    When the C++ compiler encounters a lambda expression, it generates a new anonymous class. Each captured variable becomes a member of that anonymous class, and the member is initialized from the variable in the outer scope. Finally, the anonymous class is given an operator() implementation whose parameter list is the parameter list of the lambda, whose body is the lambda body, and whose return value is the lambda return value.

    I am simplifying here. You can read the C++ language specification for gory details. The purpose of this discussion is just to give a conceptual model for how lambdas work so we can get to answering the question. The language also provides for syntactic sugar to infer the lambda return type and capture variables implicitly. Let's assume all the sugar has been applied so that everything is explicit.

    Here's a basic example:

    void ContainingClass::SomeMethod()
    {
     int i = 0, j = 1;
     auto f = [this, i, &j](int k) -> int
        { return this->calc(i + j + k); };
     ...
    }
    

    The compiler internally converts this to something like this:

    void ContainingClass::SomeMethod()
    {
     int i = 0, j = 1;
    
     // Autogenerated by the compiler
     class AnonymousClass$0
     {
     public:
      AnonymousClass$0(ContainingClass* this$, int i$, int& j$) :
       this$0(this$), i$0(i$), j$0(j$) { }
      int operator(int k) const
         { return this$0->calc(i$0 + j$0 + k); }
     private:
      ContainingClass* this$0; // this captured by value
      int i$0;                 // i captured by value
      int& j$0;                // j captured by reference
     };
    
     auto f = AnonymousClass$0(this, i, j);
     ...
    }
    

    We are closer to answering the original question. but we're not there yet.

    As a special bonus: If there are no captured variables, then there is an additional conversion operator that can convert the lambda to a pointer to a nonmember function. This is possible only in the case of no captured variables because captured variables would require an AnonymousClass$0 instance parameter, but there is nowhere to pass it.

    Here's a lambda with no captured variables.

    void ContainingClass::SomeMethod()
    {
     auto f = [](int k) -> int { return calc(k + 42); };
     ...
    }
    

    The above code gets transformed to

    void ContainingClass::SomeMethod()
    {
     class AnonymousClass$0
     {
     public:
      AnonymousClass$0()  { }
      operator int (*)(int k) { return static_function; }
      int operator(int k) const { return calc(k + 42); }
     private:
      static int static_function(int k) { return calc(k + 42); }
     };
    
     auto f = AnonymousClass$0();
     ...
    }
    

    Okay, now we can get to the actual question: How can I specify the calling convention for this implicit conversion to a pointer to nonmember function?

    (Note that calling conventions are not part of the C++ standard, so this question is necessarily a platform-specific question.)

    The Visual C++ compiler automatically provides conversions for every calling convention. So with Visual C++, the transformed code actually looks like this:

    void ContainingClass::SomeMethod()
    {
     class AnonymousClass$0
     {
     public:
      AnonymousClass$0()  { }
      operator int (__cdecl *)(int k) { return cdecl_static_function; }
      operator int (__stdcall *)(int k) { return stdcall_static_function; }
      operator int (__fastcall *)(int k) { return fastcall_static_function; }
      int operator(int k) { return cdecl_static_function(k); }
     private:
      static int __cdecl cdecl_static_function(int k) { return calc(k + 42); }
      static int __stdcall stdcall_static_function(int k) { return calc(k + 42); }
      static int __fastcall fastcall_static_function(int k) { return calc(k + 42); }
     };
    
     auto f = AnonymousClass$0();
     ...
    }
    

    In other words, the compiler creates all the conversions, just in case. (The versions you don't use will be removed by the linker.)

    But only for noncapturing lambdas.

  • The Old New Thing

    What's the point of using a custom timer queue if there is a default one already?

    • 4 Comments

    A customer observed that when you create a timer via Create­Timer­Queue­Timer, you have the option of passing either NULL to get the default timer queue or a handle to a custom timer queue created by the Create­Timer­Queue function. Why would you want to create a custom timer queue?

    If you create a custom timer queue, then you know that all the timers in the queue are yours. For example, there might be another component in the process that creates a lot of timers in the default timer queue. If you had put your timers in the default timer queue, then your timers will risk starvation.

    It's the same sort of logic that might lead you to create a custom heap instead of using the default heap: You create a custom heap if you want to isolate your allocations from other components. Another component that creates a lot of allocations in the default heap may create fragmentation pressure in the default heap, but your custom heap is unaffected.

    Note, however, that in both cases (timer starvation and heap fragmentation), this is not something you typically worry about because the cost of the insurance often doesn't outweigh the benefit. For example, if you create your own timer queue, then the threads associated with your timer queue cannot be used to service timers from the default timer queue and vice versa, resulting in more active threads in the process than necessary, which increases scheduler overhead and memory usage. Since the threads from the two timer queues are not coordinating their efforts (since that's the point of creating a private timer queue), you can end up with CPU thrashing if both timer queues have collectively created more threads than there are CPU cores, and they are all running.

    After all, the whole point of a timer queue in the first place is to consolidate a lot of little pieces of work into a small number of threads. Creating a private timer queue is moving in the opposite direction.

    But if you want to do it, then the facility is there.

    For example, if you create a private heap, then you can free all the allocations in that heap by destroying the heap. Similarly, having a private timer queue means that you can cancel and delete all the timers by deleting the timer queue. Though at least in the timer case, you can get the best of both worlds (shared timer queue plus bulk cancellation) by associating all the timers with a cleanup group.

  • The Old New Thing

    When asking about the capacity of a program, you also need to consider what happens when you decide to stop using the program

    • 27 Comments

    An internal customer had a question about a tool, let's call it Program Q.

    As part of our gated checkin system, the system creates a new record in a Program Q table to record details of the checkin. (What tests were run, who did the code review, that sort of thing.) We are considering incorporating the Program Q record number as part of our version number: major.minor.service­pack.hot­fix.record­number. What is the maximum number of records per table supported by Program Q?

    Now, the easy way out is to just answer the question: The theoretical maximum number of records per table is 2³²−1. Even if your gated checkin system's throughput is one checkin per second, that gives you over a century of record numbers.

    But answering the question misses the big picture: The limiting factor is not the capacity of Program Q. The limiting factor is how long you plan to keep using Program Q! Before the century is up, you probably won't be using Program Q. What is your transition plan?

    In this case, it's probably not that complicated. Suppose that at the time Program Q is retired and replaced with Program R, the highest record number is 314159. You could just say that the version number in the binary is the Program R record number plus 400000.

    If you're clever, you can time the switch from Program Q to Program R to coincide with a change to the major.minor.service­pack.hot­fix, at which point you can reset the record­number to 1.

  • The Old New Thing

    Microspeak: Light up

    • 16 Comments

    In Microspeak, a feature lights up if it becomes available in an application when run on an operating system that supports it.

    The idea is that you write your application to run on, say, Windows versions N and N + 1. There is a new feature in Windows version N + 1, and new functionality in the application when the code detects that the underlying Windows feature is availble.

    Here are a few citations:

    I have had some requests lately for details on the path to Windows 7 compatibility and how to light up key features.
    Top 7 Ways to light Up Your Apps on Windows Server 2008.

    The idea is that the program takes advantage of new Windows features when running on new versions of Windows. if run on older versions of Windows without those features, nothing happens.

    Inside the product group, discussion about "lighting up" often takes the form of deciding how much new hotness will be automatically applied to old applications and how much needs to be explicitly opted in. Applying new features to old applications makes the old applications and the new feature more valuable because the user sees the feature everywhere, as opposed to working only in new applications designed to take advantage of it. On the other hand, applying them automatically to old applications creates a compatibility risk, because the application may observe a behavior that hadn't occurred before, and it may begin behaving erratically as a result.

  • The Old New Thing

    The 2015/2016 Seattle Symphony subscription season at a glance

    • 6 Comments

    For many years, I've put together a little pocket guide to the Seattle Symphony subscription season for my symphony friends to help them decide which ticket package they want. For the past several years now, we haven't ordered any tickets at all because we all have young children, but I still make this guide out of some sense of obligation.

    So here's the at-a-glance season guide for the 2015/2016 season anyway, again with no comments from me because nobody I know is going to use them to decide which tickets to order. Besides, you can probably preview nearly all of the pieces nowadays (minus the premieres) by searching on YouTube.

    Here is the official brochure for those who want to read the details, and you can see what The Seattle Times thinks of it.

    Week Program 21 13 7A
    7B
    7C
    7D
    7E
    7F
    7G 4A SU
    09/24
    2015
    Mendelssohn: String Quartet #6
    Beethoven: Symphony #4
    Mahler: Symphony #1

     
     

     
     
       
     
     
       
     
     

    10/01
    2015
    R. Strauss: Don Quixote
    Brahms: Symphony #3
                   
    10/08
    2015
    Dvořák: A Hero's Song
    Britten: Violin Concerto
    R. Strauss: Also Sprach Zarathustra
                   
    10/22
    2015
    Stravinsky: Symphony in C
    Beethoven: Piano Concerto #1
    Mozart: Symphony #41, "Jupiter"
                   
    11/05
    2015
    Giya Kancheli: World Premiere
    Brahms: Violin Concerto
    Martinů: Symphony #4
                   
    11/12
    2015
    R. Strauss: Till Eulenspiegel's Merry Pranks
    Bruch: Violin Concerto #1
    Nielsen: Symphony #4, "The Inextinguishable"
                 
     
     
    11/19 Mahler: Symphony #10 (Cooke)                
    12/03
    2015
    Debussy: Danses sacrée et profane
    Messiaen: Poèmes pour Mi
    Fauré: Requiem
                   
    01/07
    2016
    Rimsky-Korsakov: Overture to The Tsar's Bride
    Rachmaninov: Piano Concerto #2
    Tchaikovsky: Suite #3 in G
                   
    01/21
    2016
    Mozart: Selections from Idomeneo Ballet Music
    Mozart: Violin Concerto #3
    Haydn: Symphony #104, "London"
                   
    02/04
    2016
    R. Strauss: Don Juan
    Beethoven: Piano Concerto #3
    Berio: Sinfonia (for 8 voices and orchestra)
                   
    02/11
    2016
    Ives: Three Places in New England
    Bartók: Piano Concerto #3
    Beethoven: Symphony #3, "Eroica"
                   
    03/10
    2016
    Haydn: Symphony #88
    Mozart: Piano Concerto #23
    Schoenberg: Transfigured Night
                   
    03/17
    2016
    John Adams: Scheherezade.2, Violin Concerto
    Elgar: Pomp and Circumstance March #3
    Respighi: Pines of Rome
                 
     
     

    03/24
    2016
    Glinka: Summer Night in Madrid
    Glazunov: Violin Concerto
    Rimsky-Korsakov: Scheherezade
                   
    04/07
    2016
    Mussorgsky: Introduction to Khovanshchina
    Prokofiev: Violin Concerto #2
    Brahms: Symphony #4
                   
    04/14
    2016
    Glinka: Overture to Ruslan and Ludmilla
    Dvořák: Cello Concerto
    Silvestrov: Symphony #5
                 
     
     

    04/21
    2016
    Mendelssohn: Overture to A Midsummer Night's Dream
    Britten: Nocturne
    Szymanowski: Symphony #3
    Tchaikovsky: Romeo & Juliet Fantasy Overture
                   
    04/28
    2016
    Dutilleux: Timbres, espace, mouvement
    Beethoven: Piano Concerto #4
    Ewald: Symphony for Brass Quintet #3
    Prokofiev: Symphony #7
     
     

     
     
     

     
     
     
     

     
         

     
     
    06/02
    2016
    Stravinsky: Symphony of Psalms
    Shostakovich: Symphony #4
                   
    06/05
    2016
    Fauré: Masques et bergamasques
    Ravel: Piano Concerto in G
    Dvořák: Symphone #9, "New World"
                   
    06/09
    2016
    Anna Clyne: U.S. Premiere
    Gershwin: Concerto in F
    Beethoven: Symphony #7
                   
    Week Program 21 13 7A
    7B
    7C
    7D
    7E
    7F
    7G 4A SU

    Insider tip: Click a column header to focus on a specific series. (This feature has been around for several years, actually.)

    Legend:

    21Masterworks 21-concert series (Choice of Thursdays or Saturdays)
    13Masterworks 13-concert series (Choice of Thursdays or Saturdays)
    7AMasterworks 7-concert series A (Thursdays)
    7BMasterworks 7-concert series B (Saturdays)
    7CMasterworks 7-concert series C (Thursdays)
    7DMasterworks 7-concert series D (Saturdays)
    7EMasterworks 7-concert series E (Thursdays)
    7FMasterworks 7-concert series F (Saturdays)
    7GMasterworks 7-concert series G (Sunday afternoons)
    4AMasterworks 4-concert series A (Friday afternoons)
    SUSymphony Untuxed (Fridays, reduced program)

    For those not familiar with the Seattle Symphony ticket package line-ups: Most of the ticket packages are named Masterworks nX where n is the number is the number of concerts in the package, and the letter indicates the variation. Ticket packages have been combined if they are identical save for the day of the week. For example, 7C and 7D are the same concerts; the only difference is that 7C is for Thursday nights, while 7D is for Saturday nights.

    This chart doesn't include concert series such as the Distinguished Artists series which share no concerts with any of the Masterworks concerts.

    Notes and changes:

    • The 7[AB], 7[CD], and 7[EF] concert series do not overlap, so you can create your own 14-concert series by taking any two of them, or recreate the 21-concert series by taking all three.
    • The 13-concert series is the same as the 7[CD] and 7[EF] series combined, minus the June 9 concert.
    • The non-Masterworks series line-up continues to be tweaked: Gone are the Mozart series and the The Sunday Untuxed short concerts for families. Two children's series were renamed but otherwise unchanged: Discover Music became Family Concerts, and Soundbridge Presents became Symphony Kids.
    • The long-time Wolfgang club, which targeted adults under age 40, and its accompanying series appear to be gone.
    • A Shakespeare-themed concert in April commemorates the 400th anniversary of his death.

    This is the first season of a two-season cycle of Beethoven symphonies and piano concerti. Although there are no ticket packages specifically for the Beethoven concerts, tickets are available individually so you can make your own festival.

Page 3 of 446 (4,451 items) 12345»