You start with an image of your icon in some image format, and convert it into a special .ico file using Visual Studio's built in icon editor.
The .ico file may contain your app's icon image in several different image resolutions (eg. 16x16, 32x32, etc), each image optimized for that size by the artist that created the image. This way the window manager can easily choose which is the best image size for the situation it needs; sometimes the window manager needs a small icon, sometimes a large one.
The .ico file is then linked into the executable as part of compiling the app. First you create a small one-line .rc file that indicates the path to the icon. This small file is then 'compiled' with the resource compiler (rc.exe, part of the Visual Studio suite of command line tools, and should already be in your PATH along with the other command line tools like cl.exe and link.exe). The resource compiler converts the .rc file into a "resource file" (.res file) which can then be added to the link line of the app, just like an .obj file.
The icon will then be shown by the window manager desktop shortcuts and file browsers whenever the .exe is referenced.
1) Do a 'Search -> For Files Or Folders' for all *.ico files
2) Copy one that's 32x32 to your local icons directory
3) Double click on the file, and open it with Visual Studio
Try to use an image that has a small color map. (16 colors)
4) Fill the icon with the clear see-through background color
(The blue/green icon of the 'Monitor' in the color swatch area)
5) Save your mods to the .ico file.
6) Compile the execuable with the following in your Makefile,
assuming a program called 'foo', and an icons directory
located in "../icons.windows":
echo 0 ICON "../icons.windows/foo.ico" > foo.rc
rc -r foo.rc
$(CC) foo.obj foo.res $(LIBS) /subsystem:console [..]
7) That's it!
If you ever change the icon of your .exe, you may need to restart
Explorer (or just reboot) in order to see the change, as sometimes
the window manager will cache the old icon.