[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

update progress bar while copying

Posted on 2004-12-01
14
Medium Priority
?
1,174 Views
Last Modified: 2007-12-19
Hi all,

I am using the copyFile function to copy some files. the location is decided upon by the user via a form. However becuase the file to copy can be large then it looks like the form has frozen up when it is still copying. I have worked out how to use the progress bar and timer and want to update the progress bar during the copy. However the copy seems to have priority and the progress bar doesnt update. Can anyone help? Do I have to set up a separate thread for the progress bar? Can i do what I want? I ahve looked at FileCopyEx but cant get this working either so I thought this way would be a good workaroudn

Thanks in advance
Richard
0
Comment
Question by:richjo100
  • 7
  • 5
12 Comments
 
LVL 48

Expert Comment

by:AlexFM
ID: 12716270
Use SHFileOperation Function. It shows progress dialog like Windows Explorer. It is used internally by Windows Explorer to copy files.
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 12716294
CopyFileEx should work also, but it requires more code for progress indication. If you have problems using CopyFileEx or SHFileOperation, post your code here.
0
 

Author Comment

by:richjo100
ID: 12717156
Hi AlexFM,
Thanks for the quick reply. I would rather use copyfileEx if possible so here is my code. At the moment it copies but doesnt fall out of the loop. The code is

function.............

 BOOL b = false;
 return  CopyFileEx(source, fileNameToWrite, (LPPROGRESS_ROUTINE) CopyProgressRoutine, 0,  &b, COPY_FILE_FAIL_IF_EXISTS);      
}
      
public: static DWORD CALLBACK CopyProgressRoutine(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred,  LARGE_INTEGER StreamSize, LARGE_INTEGER StreamBytesTransferred, DWORD dwStreamNumber,        DWORD dwCallbackReason, HANDLE hSourceFile, HANDLE hDestinationFile, LPVOID lpData){
      int str = 999;
      switch (dwCallbackReason){
             case (CALLBACK_STREAM_SWITCH):
                  str  = PROGRESS_CONTINUE;
                  break;    
            case (CALLBACK_CHUNK_FINISHED):
                  updateProgressBar(updateVal += 2)
                  str=  PROGRESS_CONTINUE;
                  break;
            default:
                  str = PROGRESS_CONTINUE;
            break;
      }    
            return str;
    }


=====================================


Ideally I want the updateProgressBar function to be called. However because CopyProgressRoutine has to be static then so does this function. However when I construct the form I do this in form1.cpp and the code above is in form1.h therefore I cannot work out how to call the updateProgressBar function as the class is constructed in form1.cpp and then all the processing happens in form.h

However even if I dont include the updateProgressBar function then the file copies and then never jumps out the loop. I have tried looking for examples but cant find anything.

Any help would be appreciated
Richard

0
Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
LVL 48

Expert Comment

by:AlexFM
ID: 12717309
LPVOID lpData member may be used to pass class pointer. Using this pointer you have access to the class instance.

return  CopyFileEx(source, fileNameToWrite, (LPPROGRESS_ROUTINE) CopyProgressRoutine, this,  &b, COPY_FILE_FAIL_IF_EXISTS);  

static DWORD CALLBACK CopyProgressRoutine(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred,  LARGE_INTEGER StreamSize, LARGE_INTEGER StreamBytesTransferred, DWORD dwStreamNumber,       DWORD dwCallbackReason, HANDLE hSourceFile, HANDLE hDestinationFile, LPVOID lpData)
{  
    CMyClass* pClass = (CMyClass*)lpData;

   pClass->...;
}

To stop copying return PROGRESS_CANCEL.
0
 

Author Comment

by:richjo100
ID: 12717721
Thanks for your reply. I have added the following code to the CopyProgress...

Form1* pClass = (Form1*)lpData;

and I get the following error: (where XSend is the name of the project)
error C2440: 'type cast' : cannot convert from 'LPVOID' to 'XSend::Form1 __gc *'

I think the problem may stem from the fact that I created a form in visual c++ and then just added buttons and double cliked on them to write the code. Therefore I presume the only class I have produced is the class to do with the form whch is called form1. Is my understanding correct?

Thanks again
Richard
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 12718913
I didn't know that you are using managed extensions. Managed pointer cannot be casted to unmanaged pointer. However, you can use some trick: create unmanaged structure which contains Form1* reference and pass this pointer to this structure to CopyFileEx.
Or use SHFileOperation, it is simple for use.
0
 

Author Comment

by:richjo100
ID: 12719073
Hi AlexFm
I think I will use SHFileOperation then if it is easier. Thanks for your help so far. i'll let you know how I get on with SHFileOperation
Richard
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 12719259
Don't miss the following lines from SHFILEOPSTRUCT Structure MSDN topic:

pFrom
Although this member is declared as a null-terminated string, it is used as a buffer to hold multiple file names. Each file name must be terminated by a single NULL character. An additional NULL character must be appended to the end of the final name to indicate the end of pFrom.

The same is about pTo.
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 12719509
BTW, possibly there is pure managed way to make such operation. Ask this in .NET or C# area. Any C# or VB.NET code may be easily translated to managed C++.
0
 

Author Comment

by:richjo100
ID: 12840802
Thanks AlexFM. Ideally I want to increase the value of the progress bar during the copy. I was thinking of have a separate thread to do this. i will look in to it
Richard
0
 

Author Comment

by:richjo100
ID: 12866717
Hi AlexFM,

Am having some problems with using SHFileOperation. I have included shell32.lib but everytime I try and run any code with #include <shellapi.h> and I get loads of syntax errors. What is going on? Do I have to over-ride some function to get it to work?

Thanks
Richard
0
 
LVL 48

Accepted Solution

by:
AlexFM earned 920 total points
ID: 12875704
Create Windows Forms application with ShellTest name and paste this code to Form1.h file:

#pragma once

#include <windows.h>
#include <shellapi.h>

namespace ShellTest
{
    using namespace System;
    using namespace System::ComponentModel;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::Drawing;
    using namespace System::Runtime::InteropServices;

    public __gc class Form1 : public System::Windows::Forms::Form
    {  
        public:
            Form1(void)
            {
                InitializeComponent();
            }

        protected:
            void Dispose(Boolean disposing)
            {
                if (disposing && components)
                    {
                    components->Dispose();
                    }
                __super::Dispose(disposing);
            }
        private: System::Windows::Forms::Button *  button1;

        private:
            /// <summary>
            /// Required designer variable.
            /// </summary>
            System::ComponentModel::Container * components;

            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            void InitializeComponent(void)
                {
                this->button1 = new System::Windows::Forms::Button();
                this->SuspendLayout();
                //
                // button1
                //
                this->button1->Location = System::Drawing::Point(80, 96);
                this->button1->Name = S"button1";
                this->button1->Size = System::Drawing::Size(112, 24);
                this->button1->TabIndex = 0;
                this->button1->Text = S"button1";
                this->button1->Click += new System::EventHandler(this, button1_Click);
                //
                // Form1
                //
                this->AutoScaleBaseSize = System::Drawing::Size(5, 13);
                this->ClientSize = System::Drawing::Size(292, 266);
                this->Controls->Add(this->button1);
                this->Name = S"Form1";
                this->Text = S"Form1";
                this->ResumeLayout(false);

                }  
        private: System::Void button1_Click(System::Object *  sender, System::EventArgs *  e)
                 {
                     ArrayList* list = new ArrayList();

                     list->Add(new String(L"C:\\tmp\\file1.txt"));
                     list->Add(new String(L"C:\\tmp\\file2.txt"));

                     CopyFiles(list, L"C:\\Tmp1");
                 }

        void CopyFiles(ArrayList* list, String* dest)
        {
            int i, len, bufferLen;
            SHFILEOPSTRUCTW s;
            IntPtr pFrom, pTo;

            s.hwnd = (HWND)this->Handle.ToInt32();
            s.wFunc = FO_COPY;

            len = list->Count;
            bufferLen = 2;

            for ( i = 0; i < len; i++ )
            {
                String* str = dynamic_cast<String*>(list->Item[i]);

                if ( str )
                    bufferLen += (str->Length + 1);
            }

            bufferLen *= 2;
               
            pFrom = Marshal::AllocCoTaskMem(bufferLen);

            char* pCurrent = (char*) pFrom.ToInt32();

            for ( i = 0; i < len; i++ )
            {
                String* str = dynamic_cast<String*>(list->Item[i]);

                if ( str )
                {
                    IntPtr tmp = Marshal::StringToCoTaskMemUni(str);
                    int l = (str->Length + 1)*2;
                    memcpy(pCurrent, (void*)tmp.ToInt32(), l);
                    Marshal::FreeCoTaskMem(tmp);
                    pCurrent += l;

                }
            }

            *pCurrent++ = 0;
            *pCurrent = 0;

            s.pFrom = (LPCWSTR)pFrom.ToInt32();


            {
                int l = (dest->Length + 2)*2;
                pTo = Marshal::AllocCoTaskMem(l);

                char* pCurrent = (char*) pTo.ToInt32();

                l -= 2;
                IntPtr tmp = Marshal::StringToCoTaskMemUni(dest);
                memcpy(pCurrent, (void*)tmp.ToInt32(), l);
                Marshal::FreeCoTaskMem(tmp);
                pCurrent += l;

                *pCurrent++ = 0;
                *pCurrent = 0;

                s.pTo = (LPCWSTR)pTo.ToInt32();
            }

            s.fFlags = 0;
            s.hNameMappings = NULL;
            s.lpszProgressTitle = NULL;

            SHFileOperationW(&s);


            Marshal::FreeCoTaskMem(pFrom);
            Marshal::FreeCoTaskMem(pTo);
        }

    };
}

You can use CopyFiles function in your program. button1_Click shows how to use this function. This program copies files C:\tmp\file1.txt and C:\tmp\file2.txt to directory C:\Tmp1.

0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The following diagram presents a diamond class hierarchy: As depicted, diamond inheritance denotes when two classes (e.g., CDerived1 and CDerived2), separately extending a common base class (e.g., CBase), are sub classed simultaneously by a fourt…
In Easy String Encryption Using CryptoAPI in C++ (http://www.experts-exchange.com/viewArticle.jsp?aid=1193) I described how to encrypt text and recommended that the encrypted text be stored as a series of hexadecimal digits -- because cyphertext may…
Integration Management Part 2
Despite its rising prevalence in the business world, "the cloud" is still misunderstood. Some companies still believe common misconceptions about lack of security in cloud solutions and many misuses of cloud storage options still occur every day. …
Suggested Courses

834 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question