Thought i would chime in here as have been using this stm recently.
Yes the best method is to unplug then hold boot0 and replug, Windows has to see the enumeration signal which only happens on plug in or you have to send a USB signal to do it but it wont happen if you just reset+boot0.
For IDE i find that Visual studio+platform io works great for me, here is my normal work flow.
if am basing on stm codebase:-
First i start STM CubeMX and select my MCU, i then enable my various systems like USB, RCC etc and enable my gpio's , here you can specify the names of gpios and they are added as constants/defines to the final source.
once you have set your clocks and enabled all your peripheral's goto the project manager page.
On the project manager page I normally select Makefile as Toolchain IDE as i often am in linux or WSL and typing "make clean && make " is quick for my brain , it also makes for a handy reference needed later (no pun intended)
here also you can select heap size and more.
next I select my export location/folder and click Generate code
This gives us a "Generic codebase" to start from and should compile and upload to the device without issue but note it wont do anything other than setup a few gpios and clocks and not much else but sit in a while loop.
Next i create another need file for platformio and thats the platformio.ini file which is placed in the same folder as the Makefile,
[platformio]
src_dir = ./
[env:stm32f407_nand]
platform = ststm32
board = vccgnd_f407zg_mini
framework = stm32cube
src_filter = +<Core/Src/*>
+<USB_DEVICE/App/*>
+<USB_DEVICE/Target>
monitor_port = com4
build_flags =
;-D__STATIC_INLINE=
-DVECT_TAB_OFFSET=0
-Wunused-variable
-DDEBUG
-ffunction-sections
-fdata-sections
-funroll-loops
-Wl,--gc-sections
-Wno-implicit-function-declaration
-ICore/Inc
-IUSB_DEVICE/App
-IUSB_DEVICE/Target
-IMiddlewares/ST/STM32_USB_Device_Library/Core/Inc/
-IMiddlewares/ST/STM32_USB_Device_Library/Class/Inc
Next I load platformio (visual studio+platformio) and select open folder, browse to the folder with Makefile and platformio and let the platformio backend load up.
In the above example of platformio.ini I have included examples of including the USB drivers folders in both the make side and Include side (src_filter for make & build_flags for the includes )
please note that your USB_DEVICE code folder may have a different name if you dont select Makefile as output format in CubeMX
The 'board = board_name' part of the platformio.ini is where you set your actual board type, there are 100's built into platformio and the platformio wiki has a list of what you write here for your specific board , if your specific board/xtal combo does not exist in the list then it's real easy to choose a close match and just alter those small changes in the platformio.ini file,
a example would be under build_flags you add
-DHSE_VALUE=8000000
On my github i have many examples
https://github.com/darkspr1teThe reasons i have this workflow is platformio supports more than just STM mcu's so it allows me to load up code for two different devices and port code from one to the other. It also supports Arduino/CMSIS/Standard Peripheral Lib/STMCube/libopencm3, The arduino support is really handy if you dont want to sit there and build backend but create some quick code and not worry about USB clocks etc just bash some gpoi and be done with it.
platformio also supports many programmers like stlinkv2, DFU mode, serial tll upload , jtag and more.
the backend is also really patchable so if you need certain things to happen before compile (eg a bitmap font into C array ) it can easily be done either in the platformio.ini file or in the many python scripts it runs on. this also goes for after compile etc
Another handy feature is for the stm32 libs you can specify the version you want , this is handy for using code you found but wont compile under the latest cubemx backend , eg '
framework = stm32cube@8.9' would load the old codebase where gpio was written as GPIO_Pin_0 where in the later (past v9) it's written as GPIO_PIN_0