private void ModelToJpegsThread(object objparam)
        {
            ModelToJpegsParameters param = objparam as ModelToJpegsParameters;

            try
            {
                while (true)
                {
                    if (param.model.version == -1) // someone told us to stop.
                    {
                        return;
                    }

                    int nWhichToProcess = -1;
                    lock (param.locker)
                    {
                        nWhichToProcess = param.iItemLatest;
                        param.iItemLatest++;
                        if (nWhichToProcess < param.model.list.Count)
                        {
                            Form1.g_status = "Downloading " + (nWhichToProcess + 1) + " of " + param.model.list.Count + "...";
                        }
                        else
                        {
                            return;
                        }
                    }

                    ModelItemToJpeg(param.model.list[nWhichToProcess], param.sDir);
                }
            }
            catch (Exception e)
            {
                param.model.version = -1; // tell everyone else to stop.
                string s = e.ToString().Replace("Exception", "").Replace("exception", "");
                System.Diagnostics.Debug.Assert(false);
                MessageBox.Show(s);
            }
        }
        private void ModelToJpegs(BookmarkBucketObjectModel obj, string sDir)
        {
            if (obj == null || obj.list.Count == 0) return;
            sDir += "\\out";
            if (Directory.Exists(sDir)) throw new BookmarkBucketException("'out' directory already exists.");
            Directory.CreateDirectory(sDir);

            // first, make sure we won't overwrite files.
            foreach (BookmarkBucketItem item in obj.list)
            {
                if (item.sFile.Length == 0 || item.sUrl.Length == 0)
                    throw new BookmarkBucketException("Missing url or title.");
                if (!BookmarkBucketCore.looksLikeAUrl(item.sUrl))
                    throw new BookmarkBucketException("invalid url");
                if (File.Exists(sDir + "\\" + item.GetNameWithoutExtension() + ".jpeg"))
                    throw new BookmarkBucketException("Jpeg for '" + item.GetNameWithoutExtension() + "' already exists.");
                if (File.Exists(sDir + "\\" + item.GetNameWithoutExtension() + ".png"))
                    throw new BookmarkBucketException("Png for '" + item.GetNameWithoutExtension() + "' already exists.");
                if (File.Exists(sDir + "\\" + item.GetNameWithoutExtension() + ".html"))
                    throw new BookmarkBucketException("Html for '" + item.GetNameWithoutExtension() + "' already exists.");
            }
            // test write access.
            try { File.WriteAllText(sDir + "\\!!temp!!.test", "test"); }
            catch (IOException) { throw new BookmarkBucketException("Apparently no write access here..."); }
            finally { if (File.Exists(sDir + "\\!!temp!!.test")) File.Delete(sDir + "\\!!temp!!.test"); }

            // use my own threadpool instead of c#'s because I want to limit number of threads running.
            int nThreads = 4;
            ModelToJpegsParameters param = new ModelToJpegsParameters { iItemLatest = 0, locker = new object(), model = obj, sDir = sDir };
            Thread[] threads = new Thread[nThreads];
            for (int i = 0; i < nThreads; i++)
            {
                threads[i] = new Thread(new ParameterizedThreadStart(this.ModelToJpegsThread));
                threads[i].Start(param);
            }
            // wait for all threads to complete. note that obj.version will be negative if an error occurred.
            for (int i = 0; i < nThreads; i++)
                threads[i].Join();
        }
        private void ModelToJpegs(BookmarkBucketObjectModel obj, string sDir)
        {
            if (obj == null || obj.list.Count == 0)
            {
                return;
            }
            sDir += "\\out";
            if (Directory.Exists(sDir))
            {
                throw new BookmarkBucketException("'out' directory already exists.");
            }
            Directory.CreateDirectory(sDir);

            // first, make sure we won't overwrite files.
            foreach (BookmarkBucketItem item in obj.list)
            {
                if (item.sFile.Length == 0 || item.sUrl.Length == 0)
                {
                    throw new BookmarkBucketException("Missing url or title.");
                }
                if (!BookmarkBucketCore.looksLikeAUrl(item.sUrl))
                {
                    throw new BookmarkBucketException("invalid url");
                }
                if (File.Exists(sDir + "\\" + item.GetNameWithoutExtension() + ".jpeg"))
                {
                    throw new BookmarkBucketException("Jpeg for '" + item.GetNameWithoutExtension() + "' already exists.");
                }
                if (File.Exists(sDir + "\\" + item.GetNameWithoutExtension() + ".png"))
                {
                    throw new BookmarkBucketException("Png for '" + item.GetNameWithoutExtension() + "' already exists.");
                }
                if (File.Exists(sDir + "\\" + item.GetNameWithoutExtension() + ".html"))
                {
                    throw new BookmarkBucketException("Html for '" + item.GetNameWithoutExtension() + "' already exists.");
                }
            }
            // test write access.
            try { File.WriteAllText(sDir + "\\!!temp!!.test", "test"); }
            catch (IOException) { throw new BookmarkBucketException("Apparently no write access here..."); }
            finally { if (File.Exists(sDir + "\\!!temp!!.test"))
                      {
                          File.Delete(sDir + "\\!!temp!!.test");
                      }
            }

            // use my own threadpool instead of c#'s because I want to limit number of threads running.
            int nThreads = 4;
            ModelToJpegsParameters param = new ModelToJpegsParameters {
                iItemLatest = 0, locker = new object(), model = obj, sDir = sDir
            };

            Thread[] threads = new Thread[nThreads];
            for (int i = 0; i < nThreads; i++)
            {
                threads[i] = new Thread(new ParameterizedThreadStart(this.ModelToJpegsThread));
                threads[i].Start(param);
            }
            // wait for all threads to complete. note that obj.version will be negative if an error occurred.
            for (int i = 0; i < nThreads; i++)
            {
                threads[i].Join();
            }
        }