Give the window a non-sizing (e.g. dialog) border. This is the best option as well as the simplest, because the appearance of the window reflects what you can do with it.
Handle the WM_NCHITTEST message and return HT_NOWHERE whenever the user is in a sizing portion of the border.
Handle WM_GETMINMAXINFO and adjust the ptMinTrackSize and ptMaxTrackSize values of the MINMAXINFO structure to be the same as the windows current size. You can use the same trick to allow resizing but enforce a minimum resize value.