• The Old New Thing

    Microspeak: Dialogue

    • 24 Comments

    Why have a conversation when you can dialogue?

    I think this is minimal work, but do others care? If they don't, then this is one for the ideas that failed bin. If they do, well let's dialogue...

    No need to talk when you can dialogue.

  • The Old New Thing

    Using the MNS_DRAGDROP style: Dragging out

    • 8 Comments

    Windows 2000 introduced the MNS_DRAG­DROP menu style, which permits drag/drop operations in a menu. Nobody uses this style, probably because it's totally undiscoverable by the end-user. But I'll write a sample program anyway.

    Mind you, I knew nothing about the MNS_DRAG­DROP menu style until I started writing this entry. But I simply read the documentation, which says that if you set this style, you will receive WM_MENU­DRAG and WM_MENU­GET­OBJECT messages. The WM_MENU­DRAG message is sent when the user drags a menu item, so let's go with that first. The documentation says that you get information about the item that was dragged, and then you return a code that specifies whether you want the menu to remain up or whether you want it torn down.

    Simple enough. Let's do it.

    Start with the scratch program, add the function Get­UI­Object­Of­File and the class CDrop­Source, and change the calls to Co­Initialize and Co­Uninitialize into Ole­Initialize and Ole­Uninitialize, respectively. Next, define the menu we're going to play with:

    // resource header file
    #define IDM_MAIN 1
    #define IDC_CLOCK 100
    
    // resource file
    IDM_MAIN MENU PRELOAD
    BEGIN
        POPUP "&Test"
        BEGIN
            MENUITEM "&Clock", IDC_CLOCK
        END
    END
    

    Now we can add some new code to our scratch program. First, we add a menu to our window and enable drag/drop on it:

    BOOL
    OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
    {
     MENUINFO mi = { sizeof(mi), MIM_STYLE, MNS_DRAGDROP };
     return SetMenuInfo(GetMenu(hwnd), &mi);
    }
    
    // InitApp
     // wc.lpszMenuName = NULL;
     wc.lpszMenuName = MAKEINTRESOURCE(IDM_MAIN);
    

    For both dragging and dropping, we need a way to obtain the COM object associated with a menu item, so I'll put them in this common helper function:

    HRESULT GetMenuObject(HWND hwnd, HMENU hmenu, UINT uPos,
                          REFIID riid, void **ppvOut)
    {
     HRESULT hr = E_NOTIMPL;
     *ppvOut = NULL;
     if (hmenu == GetSubMenu(GetMenu(hwnd), 0)) {
      switch (GetMenuItemID(hmenu, uPos)) {
      case IDC_CLOCK:
       hr = GetUIObjectOfFile(hwnd, L"C:\\Windows\\clock.avi",
                                                 riid, ppvOut);
       break;
      }
     }
     return hr;
    }
    

    If the menu is our "Test" popup menu, then we know how to map the menu items to COM objects. For now, we have only one item, namely Clock, which corresponds to the C:\Windows\clock.avi¹ file.

    Now we can hook up a handler to the WM_MENU­DRAG message:

    #define HANDLE_WM_MENUDRAG(hwnd, wParam, lParam, fn) \
     (fn)((hwnd), (UINT)(wParam), (HMENU)(lParam))
    
    LRESULT OnMenuDrag(HWND hwnd, UINT uPos, HMENU hmenu)
    {
     LRESULT lres = MND_CONTINUE;
     IDataObject *pdto;
     if (SUCCEEDED(GetMenuObject(hwnd, hmenu, uPos,
                                     IID_PPV_ARGS(&pdto)))) {
      IDropSource *pds = new(std::nothrow) CDropSource();
      if (pds) {
       DWORD dwEffect;
       if (DoDragDrop(pdto, pds, DROPEFFECT_COPY | DROPEFFECT_LINK,
                      &dwEffect) == DRAGDROP_S_DROP) {
        lres = MND_ENDMENU;
       }
       pds->Release();
      }
      pdto->Release();
     }
     return lres;
    }
    

    This function is where the magic happens, but it's really not all that magical. We get the data object for the menu item being dragged and tell OLE to do a drag/drop operation with it. Just to make things interesting, I'll say that the menu should be dismissed if the user dropped the object somewhere; otherwise, the menu remains on the screen.

    Finally, we hook up the message handler to our window procedure:

    HANDLE_MSG(hwnd, WM_MENUDRAG, OnMenuDrag);
    

    And there you have it. A program that calls up a menu with drag enabled. If you drag the item labeled Clock, then the drag/drop operation proceeds as if you were dragging the clock.avi file.

    Next time, we'll look at the drop half of drag and drop.

    Footnote

    ¹ I hard-coded the clock.avi file for old time's sake. Yes, I know the file is no longer included with Windows. That'll teach people to use hard-coded paths!

  • The Old New Thing

    2012 Q3 link clearance: Microsoft research edition

    • 14 Comments

    My Q1 and Q3 link clearances are traditionally for links to other Microsoft bloggers, but this time I'm going to link to a few Microsoft research papers I found interesting.

    Why do Nigerian scammers say they're from Nigeria?

    Short answer: Because it ensures that the replies come only from the most gullible people on earth.

    Bonus chatter: I received a scam email purportedly from Sir Humphrey Appleby, secretary to the Prime Minister. I could tell it was a fake because the message was comprehensible.

    Sketch2Cartoon: Composing Cartoon Images by Sketching

    Okay, I admit I haven't read the paper. But the video is fun to watch.

    Debugging in the (Very) Large: Ten Years of Implementation and Experience

    This is the paper on Windows Error Reporting that everybody cites. To me, it gets interesting starting in Section 6.

    An Empirical Analysis of Hardware Failures on a Million Consumer PCs

    I had the good fortune of seeing an early version of this paper. The thing that jumped out at me was the hard drive failure information:

    • The probability of a failure in the first 5 days of uptime is 1 in 470.
    • Once you've had one failure, the probability of a second failure is 1 in 3.4.
    • Once you've had two failures, the probability of a third failure is 1 in 1.9.

    Translation: That hard drive failure you experienced? It was no fluke. Once you experience your first hard drive failure, the odds of a second one increase by a factor of over 100.

    What's more, that second failure is highly likely (86%) to occur within the next ten days, and almost certainly (99%) within the next thirty.

    Conclusion: When you get a hard drive failure, replace the drive immediately.

  • The Old New Thing

    I am no longer impressed by your fancy new 10,000 BTU hot pot burner

    • 31 Comments

    Two years ago, we had a gathering at my house for some friends for hot pot, the traditional way of ringing in the lunar new year (which takes place today). It was actually a bit of a cross-cultural event, since the attendees came from different regions of Asia, where different traditions reign. (And the American guests just had to choose sides!)

    My house has but one portable stove for hot pot, so one of the guests brought her own unit, a unit as it turns out which was purchased specifically for the occasion, which gleamed in the light and proudly proclaimed 10,000 BTU of raw heating power. This was cause for much boasting, particularly since I didn't know the heating power of my own puny old unit, but I accepted my second-place position with grace.

    Some time later, we had a quiet family hot pot, and my old and horrifically unfashionable burner was brought out to do its tired but important job, and it was then that I found the sticker that specified its heating power.

    9,925 BTU.

    Now I am no longer impressed by my friend's 10,000 BTU burner.

  • The Old New Thing

    Yes, there's a new desktop window manager, but no, I don't know any more about it than you do

    • 7 Comments

    Sean W. requests, via the suggestion box, "an in-depth discussion of the use of the shell's new Desktop Window Manager (Dwm*) functions in Win32."

    The desktop window manager is not actually part of the shell. It operates at the window manager level. (Notice that DWM is active even when Explorer isn't running.) You probably should have posted your suggestion to Greg Schechter's request for DWM topics which was not too old at the time you posted your topic suggestion. But then again, "Best practices for applications under the DWM" was on his list of future topics, so it looks like what you wanted was already on his to-do list. I don't know whether he followed up on his own to-do list, though. If not, you can always consult the Performance Considerations and Best Practices (for using DWM) topic in MSDN.

  • The Old New Thing

    It helps if you write a cover letter and remember the name of your interviewer

    • 2 Comments

    It's not a big thing, but it shows that you have your act together and does a lot towards distinguishing you from everybody else. A story of the importance of writing a cover letter and remembering the name of your interviewer.

    (Then again, what do I know. JobsBlog probably is a better source for this type of info. Earlier this year, Angela McLaughlin shared her thoughts on cover letters.)

  • The Old New Thing

    Searching for Evil: Spot the scam

    • 8 Comments

    Security researcher Ross Anderson gives a talk on how a search engine can be used to shed light on the various evils that lurk on the Web. It starts off slow, but picks up when he gets to the "Can you spot the scam?" game that he plays with each Web site. (If you're in a hurry, skip ahead to a little past the 20 minute mark.)

  • The Old New Thing

    John Swansburg deftly declines the fine print disclaimer on his Heelys

    • 11 Comments

    Before field-testing his Heelys for a report in Slate, John Swansburg reads the legal disclaimer and declines it.

  • The Old New Thing

    Why can't I use PSGUID_STORAGE like a GUID?

    • 24 Comments

    The stgprop.h header file defines a GUID called PSGUID_STORAGE, but a customer was having trouble using it.

        GUID guid;
        ...
        // This generates a strange compiler error
        if (IsEqualGUID(guid, PSGUID_STORAGE)) { ... }
    

    The strange compiler error the customer referred to is the following:

    test.cpp(136) : error C2143: syntax error : missing ')' before '{'
    test.cpp(136) : error C2059: syntax error : ')'
    test.cpp(136) : error C2143: syntax error : missing ';' before '{'
    test.cpp(136) : error C2059: syntax error : '{'
    test.cpp(136) : error C2059: syntax error : ')'
    test.cpp(137) : error C2059: syntax error : '}'
    test.cpp(137) : error C2143: syntax error : missing ';' before '}'
    test.cpp(137) : error C2059: syntax error : '}'
    

    "I don't see what the compiler is complaining about. The parentheses appear to be properly matched before the left brace."

    Remember, what you see is not necessarily what the compiler sees. Let's take another look at this mysterious GUID:

    #define PSGUID_STORAGE  { 0xb725f130,           \
                              0x47ef, 0x101a,       \
                              { 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac } }
    

    Well there's your problem. After the preprocessor does its substitution, the line becomes

        if (IsEqualGUID(guid, { 0xb725f130,
                  0x47ef, 0x101a,
                  { 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac } })) { ... }
    

    and that's not legal C/C++. (Though with a little tweaking, you can get GCC to accept it.) The PSGUID_STORAGE symbols is intended to be used as an initializer:

    const GUID StorageGuid = PSGUID_STORAGE;
    

    "How did you know that?"

    I didn't, but I went to the effort of looking at the definition in the header file and figuring it out from inspection.

    Why is it defined this way instead of

    DEFINE_GUID(PSGUID_STORAGE, 0xb725f130, 0x47ef,
            0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac);
    

    ?

    Because this GUID is used as the FMTID of a PROPERTY­KEY. The PROPERTY­KEY structure looks like this:

    typedef struct {
      GUID  fmtid;
      DWORD pid;
    } PROPERTYKEY;
    

    The intended usage is evidently

    const PROPERTYKEY
    PKEY_STORAGE_DIRECTORY = { PSGUID_STORAGE, PID_STG_DIRECTORY };
    

    Since the C language does not permit global variables to be initialized from other global variables (or at least it didn't at the time PROPERTY­KEYs were defined; who knows what crazy features will show up in C1X), PSGUID_STORAGE needs to be a macro which expands to an initializer rather than being a global variable.

    Today's question was really just settling the prerequisites for tomorrow's topic. Stay tuned.

  • The Old New Thing

    The old DEBUG program can load COM files bigger than 64KB, but that doesn't mean they actually load as a program

    • 22 Comments

    Some times ago, I described why a corrupted binary sometimes results in the error "Program too big to fit in memory". Commenter Neil was under the impression that nonrelocatable programs files could be larger than 64KB and used the DEBUG command to verify this assertion.

    While it's true that DEBUG can load files bigger than 64KB, that doesn't mean that they will load as a program. If DEBUG decide that you didn't give it a program (the file extension is not EXE or COM),¹ then it treats the file on the command line as a data file and loads it into memory in its entirety, provided it fits in memory in its entirety. When it does this, the BX register contains the upper 16 bits of the file size, and CX contains the lower 16 bits. This is also the format that is used when writing files back out: Use the n command to set the name of the output file and set BX:CX to the file size.

    Even though DEBUG has been obsolete for over a decade, it is still useful for exactly this purpose: You can use it as a hex editor for files less than around 512KB.

    But don't deceive yourself into thinking that you created a COM file that is bigger than 64KB.

    ¹There is another extension which has special meaning to DEBUG, but it's not relevant to the discussion.

Page 372 of 419 (4,181 items) «370371372373374»