First with that particular implementation you should ideally pass the Graphics object as a method argument, that way you only have to instantiate it once outside your drawing code which greatly reduces the native interop overhead taking place within the FromHwnd method. But despite this using FillRectangle definitely isn't a fast method of doing this but is pretty much the only option with the Graphics class, but there are alternatives.
The easiest one would be to create a Bitmap object, which includes Get/SetPixel methods, with the same dimensions as your picture box and set it to the box's Image property which it internally draws as the background within its OnPaint method before calling any attached OnPaint event handlers. When you want to draw a pixel just call Bitmap.SetPixel, more advanced drawing routines can be done by creating a Graphics object from the bitmap as well. When done drawing call PictureBox.Refresh/Invalidate to make it undergo a repaint, and like said the image will be automatically drawn.
Code:
// Only need to create once after your picture box has been created
Bitmap bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
Graphics bmpGraphics = Graphics.FromImage(bmp);
pictureBox.Image = bmp;
// Drawing routine, don't bother creating a Graphics object for the picture box since it's not needed
bmpGraphics.Clear(Color.Black);
bmp.SetPixel(256, 256, Color.White);
bmpGraphics.DrawLine(Pens.Red, 32, 32, 64, 64);
pictureBox.Refresh();
// Best to explicitly dispose of these (and any other unmanaged resources like brushes/pens too) when no longer needed.
// If you forget they won't be disposed until the GC kicks in and calls their finalizers, really shouldn't rely on this though.
bmpGraphics.Dispose();
bmp.Dispose();
You can achieve even better performance by using Bitmap.LockBits for your pixel manipulation, this returns a pointer to the pixel data buffer which you can access directly using an unsafe pointer or using the System.Runtime.InteropServices.Marshal class (unsafe pointer being fastest obviously). One drawback is that you cannot use the Bitmap within any of the Graphics methods whilst locked, you will need to unlock first. In my tests even the worst-case scenario of setting only a single pixel between the lock/unlock surprisingly achieves better performance than using Bitmap.SetPixel, and the performance gains will only continue to rise as you increase the number of pixels you are manipulating within the locked block. If you are interested in LockBits I suggest taking a look at
Jo3's sprite file structure thread which copies the pixel data into a local array with Marshal.Copy (cut his entire read time down to 3.5~ seconds from 35~ seconds with SetPixel, only slightly slower than using an unsafe pointer), and you could look at
my example attached here which includes doing it with an unsafe pointer or with the Marshal.Read/Write* classes (slowest method of the 3, still much faster than SetPixel though). I would suggest creating your own bitmap class that creates an internal Bitmap and Graphics object and expose only what is necessary, similar to what I had done in my program.