Congratulations on finishing this thing, and thanks for coming here to the forums and being excited about this stuff. I have a tendency (like many others, I suppose) to be all jaded and even bored about a lot of this, so it's nice to see someone who is enthusiastic and all fired up.
Anyway, my thoughts (somewhat random):
1) Source Releases
Your source-only release contains a lot of compiled binary .obj files, as well as DLLs and pre-compiled headers that greatly inflate the archive file size. For smaller downloads, source release packages should be stripped of any binary data like this. All of that stuff is generated in the compile process, so no need to ship it.
2) Resource Management
As you move on to more complicated projects, you are going to want to be smarter about how you handle resources such as images. In your program, the block, paddle and ball textures are loaded and used essentially as globals (not technically, but their usage patterns are global). That is, you create an essentially static object that exists for the lifetime of the program, and is handed to objects that need it.
In a more complicated program, though, that uses more assets, it is impractical to have all assets loaded for the lifetime of the program. You will instead want to implement a system for managing the lifetime of objects such as textures/images. An object can request a resource from the system, and it will load it (if needed) and return a reference or pointer to the asset. When the object no longer needs it, it is released. If no objects are referencing an asset, it can be unloaded. You can also implement a cache system that will keep some objects loaded if they are frequently used.
As an example of this, one of my earlier systems used an internal std::map of weak_ptrs keyed on a string (and later a hashed string). The string key can be filename, and the weak_ptr points to a texture resource. When a texture is requested, the system first checks to see if there is an entry in the map for the requested file. If so, then the weak_ptr is checked for validity. (If a resource is dropped, an entry will remain in the map, but the pointer itself will be invalid). If the pointer is invalid the resource is loaded. If the resource does not yet exist, it is loaded and a weak_ptr to it is placed in the map. Once the resource is located and loaded as needed, then a shared_ptr is cloned from the weak_ptr and returned.
As long as at least one shared_ptr exists, the resource will remain loaded. Once all objects holding a pointer to the resource are destroyed, though, and no shared_ptr exists, then the resource destructor is called and the resource is destroyed, the weak_ptr i the table invalidated. Requesting the resource, then, will cause it to be reloaded. You can implement a second map of shared_ptrs, keyed on name, as a cache to hold a copy of the resource and keep it from being dumped if all other shared_ptrs are dropped.
If you are anything like me, you will go through several iterations of your system until you get something you like, however you implement it. And if you are even more like me, this will be one of your first "reusable" systems that you drag with you from project to project, iterating and improving it as you go. Nailing this system down will vastly help you later, though, as you try to tackle more complicated projects.
3) Sneaky Side Effects
Take a look at your Block::Initialize method. The name suggests that the method will set some internal invariants and data in Block then exit. There is no reason to suspect it does anything else. Yet it has a side-effect, in that it takes references as parameters, and modifies the value of one of them. This sort of sneaky side effect is generally regarded as a Bad ThingTM
. Even if the side-effect is documented (it isn't) this is still something you should avoid. Either rename the method to reflect its actual behavior, or refactor to eliminate the side effect and find another way to accomplish what you need. Trust me, if you ever come back to this kind of code after a 6-month break during which you worked on something completely unrelated, these kinds of side-effects can cause you no end of headaches.
4) General Inconsistencies in Object Handling
Your Block class has an Initialize method, but neither your Paddle nor Ball class do. Ostensibly, they are all game objects, and ideally you would want at least some semblance of a common interface for dealing with them. In the past, people did this by implementing great, gawky, god-awful object inheritance hierarchies to abstract the handling of game objects. Current, modern thinking is to implement object composition, where the shared components have common interfaces. However you solve it, you should have some consistent, data-oriented means of creating, managing and destroying objects.
Implementing a sane object management policy means that you can, for example, destroy blocks that are hit, as opposed to just setting an internal flag to hide them. You can also spawn intermediate objects that perform assitance tasks, as well. For example, when a block is hit you can spawn an Explosion object whose sole purpose is to exist long enough to play an explosion animation and a sound effect, then self-destruct. The spawning of this object can be initiated by the block collision logic.
It's kind of... weird... that you implement your logic updates as functions. Really, object logic probably belongs inside the object itself, via some sort of Update method. An external function would iterate on objects and call their Update method. This way, you can implement different brands of logic merely by instancing different varieties of objects, and the main loop doesn't have to be modified to call another function. It can just keep calling Update as before.
Things such as collision detection are typically off-loaded into sub-systems of their own. For example, a physics sub-system. The sub-system will keep arrays of primitives and when a method is called, it will iterate the arrays in some fashion (this can get complex, for systems with lots of objects, but for small games it can be dead simple) and calculate collisions. It will determine which objects collide with each other, and it will somehow notify the interested parties of the collision so that they can update themselves accordingly. Then the main loop can just call UpdateCollisions after Update.
Again, as with anything, there are a thousand ways you can handle this stuff, but keeping essentially global references to all objects is not the optimal method.
Huh. Why would a method named SetVelocity (which you would expect to accept as parameters a 2D velocity vector) accept a string parameter instead? I mean, I get what you are doing, but it just doesn't seem like the best way to do it.
6) Main Loop
There are problem with how you implement your loop. Moving things have a fixed, specified velocity which is applied each turn through the loop, but the loop doesn't take timing into account. It will run as fast (or as slow) as the CPU will allow. This means that if there are background tasks, for example, that pull away CPU time the simulation will slow down. It will also run faster or slower depending on the CPU speed. In the old DOS days, many games were implemented like this because the hardware at the time was all fairly similar. But once faster processors came around, many of those games became flat out unplayable, due to extreme speeds. It is generally a bad idea to allow your loop to run "unrestrained" like that.
As with everything else, there are a number of ways you can implement a proper game loop. Some loops will fix the logic update rate to a clock, and allow it to render as fast as possible, interpolating logical positions to make the visual update smooth. Others will update each time through the loop using a calculated elapsed-time delta to scale velocities based on how much time has passed since the last update. Still others will do one or the other of these, and limit the visual framerate to some rate in order to keep from hammering the video card too hard. What you do is a matter of taste, but I highly recommend you do a bit of research into it.
These are just a few of my first impressions upon looking at your code. Don't be discouraged if it seems like a lot. You've got plenty of time to figure all this stuff out, so just keep plugging away and trying to improve and you will get there.