What’s the difference between CopyIcon and DuplicateIcon?

There are two functions that can be used to create one icon that is identical to another. One of them is Copy­Icon. The other is Duplicate­Icon. What's the difference?

There isn't any difference. Both functions clone an icon. In fact, their implementations are basically line-for-line identical.

Originally, there was just one function to clone an icon: Copy­Icon.

Windows 3.0 introduced Program Manager, and the developers of Program Manager wrote their own function called Duplicate­Icon. Why? I have no idea. My guess is that they didn't realize that such a function already existed, so they inadvertently reinvented the wheel.

Windows NT 3.1 came along, and the team that ported Program Manager to 32-bit Windows also ported the Duplicate­Icon function, and they figured, "This function is so useful, we'll export it for anybody to use!"

Meanwhile, the original Copy­Icon function is sitting there saying, "What am I, chopped liver?"

Anyway, it's a sad story, but that's how we ended up with two functions that do exactly the same thing. Personally, I would recommend using the Copy­Icon function. It's in user32.dll, which you are almost certainly already linked to if you're doing anything with icons in the first place, so the incremental cost is much lower.

Update: Joshua points out that the two functions are not identical. Duplicate­Icon takes an extra instance handle parameter. Now it makes sense. The shell version is an enhancement to the user version in that it can also transfer icon ownership to another module. (Hence the new first parameter.) This was important in 16-bit Windows because icons were resources which were associated with modules. If you wanted to use an icon after the module was unloaded, you needed to copy it and transfer ownership. But this ownership transfer step is not needed in Win32 because, as we saw yesterday, icons are no longer tied to the underlying resources. So the functions started out different but now they're the same.

Comments (9)
  1. Medinoc says:

    If they're identical, shouldn't one function simply be an export redirect to the other? After all, Shell32.DLL already references User32.DLL…

  2. Marc K says:

    Developer: "I tried creating a function named CopyIcon", but the compiler is telling me there is a name collision in user32.dll."

    Manager: "Just name it 'DuplicateIcon' instead."

    Developer: "OK. Thanks, boss."

  3. Joshua says:

    It can't be a redirect because DuplicateIcon takes an extra first argument. I checked the Wine sources. The code is identical. hInstance is listed as not used in the MSDN docs.

  4. Joshua Ganes says:

    This is hardly the first time someone has reinvented the wheel because they didn't know something already existed. It's a whole lot better to do it out of ignorance instead of due to not-invented-here syndrome.

    It would be interesting if both functions had the same results, but achieved them via very different approaches.

    Now that the damage is done, I'd probably re-implement DuplicateIcon() by calling CreateIcon() and deprecate DuplicateIcon() while maintaining for compatibility.

  5. Brian_EE says:

    "My guess is that they didn't realize that such a function already existed, so they inadvertently reinvented the wheel."

    Or, perhaps they thought they would need some additional functionality that CreateIcon() didn't provide, but by the end didn't need it, and then it was too late in the schedule to go back and change all the source code and re-test.

    [Actually, now it makes sense. The shell version takes an extra instance handle parameter because it copied the icon and transferred ownership to another module. This became meaningless in Win32 because icons are no longer owned by modules. So aha, it made sense at one point, but now it's pointless. -Raymond]
  6. gdalsnes says:

    It's a bad design that shell32 export any functionality at all, because ideally, the shell should replaceable without any apps knowing. I guess it's because of a war between user and shell team, where user team refused to add functionality required by shell team, and as revenge, shell team implemented and exported those functions. Too bad I wasn't there to prevent it.

    [What if shell32 were called "explorerhelper.dll"? Would that clear up the confusion? -Raymond]
  7. "Re-invented the wheel" is one of if not _the_ most over and inappropriately used idiom imho.  As much as "Not Invented Here" is an excuse for doing [potentially] unnecessary work, "Not re-inventing the wheel" is all too often simply an excuse for not doing proper design.

    Nobody *ever* re-invents a wheel (although they may end up duplicating an existing design of one).

    What we do do – all the time – is design a wheel best suited to the particular wheel-demanding job at hand.  You can't even simply take a wheel from a family sedan and just bolt it to an F1 car even though both are just "wheels on a car".

  8. Scarlet Manuka says:

    No, but if you're trapped in a post-apocalyptic wasteland, struggling to put together a crude cart from scraps of wreckage, you're not going to care if one of your wheels comes from a sedan and another from an F1 car, as long as they're roughly similar in size.

    That may be a bit of a stretch as an analogy, but here's one that's closer. You know you have to have a wheel of a certain minimum size and strength. You could build your own out of available materials, or you could buy one. There are a bunch of wheel salesmen around, most of whom advertise highly adaptable wheels that can magically grow or shrink to fit anything from a child's tricycle to an 18-wheel truck and can each support the weight of an entire building. You're a bit dubious about some of these claims, especially when all the salesmen gloss over the actual process of getting the wheel to be the way you want it, but you know it'll probably take you quite a while to build one yourself. Now what's your best course of action? What do you do if your manager gets all excited about the chrome finish advertised by one supplier and wants you to use their product, even if on closer reading the wheel they're selling doesn't look like it'll fit on your car very well?

  9. Silly says:

    > What if shell32 were called "explorerhelper.dll"? Would that clear up the confusion

    Wouldn't it have to have been called something like "exphel32.dll" for 8.3 compatibility and naming consistency?

Comments are closed.

Skip to main content