Geeks With Blogs
Blog Moved to Blog Moved to
Update:  Put a comment in if you want the C# version of this code and I will get it to you
Sorry about the delay about getting back to this, but I have been rebuilding a clean build environment for this tool for both Visual Studio 2003 and Visual Studio 2005 which required a little bit of work.  I'm in the process of getting some sort of hosting so that I can share the source code, but if you need or want it in the mean time, please do not hesitate to contact me.
Anyhow, we left off with the total number of classes and structures that we need to create.  So, now that this is out of the way, let me start off with the header and implementation of the BackgroundCopyManager.  I created this class in a singleton pattern because we are connecting to a service.  Below is an abbreviated header file for the BackgroundCopyManager:
namespace Podwysocki
     namespace Services
          namespace BackgroundTransferServices
              public __gc class BackgroundCopyManager
                   // Member variables
                   static BackgroundCopyManager* managerInstance;
                   static Object* syncLock = new Object();
                   IBackgroundCopyManager __nogc* pCopyManager;
                   static const Int64 defaultRetryPeriod = 1209600;
                   static const Int64 defaultRetryDelay = 600;
                  // Default constructor
                   // Destructor
                   // Gets the singleton instance
                   __property static BackgroundCopyManager* get_Instance();
                  // CreateCopyJob methods
                  CreateCopyJob(String* displayName);
                  CreateCopyJob(String* displayName, String* description);
                  CreateCopyJob(String* displayName, String* description, BackgroundCopyJobType type);
                  CreateCopyJob(String* displayName, String* description, BackgroundCopyJobType type, Int64 retryPeriod, Int64 retryDelay);
                 // Get job by ID
                 BackgroundCopyJob* GetJob(System::Guid id);
                 // Get jobs
                 BackgroundCopyJobCollection* GetJobs();
                 BackgroundCopyJobCollection* GetJobs(JobUserFlag userFlag);
              }; // class - BackgroundCopyManager
Now let's hit a few portions of interest.  Like I said, you can get the whole thing by just requesting it.  First off, let's look at the Instance property implementation.
          // Enter synch lock
          // Check if already created
          if(managerInstance == NULL)
               managerInstance = new BackgroundCopyManager();
          return bgCopyManager;
     } // try
         // Exit synch lock
    } // finally
} // method - get_Instance()
Next, we will cover creating a connection to BITS in our constructor.  What we need to do is connect to the BITS service via the CoCreateInstance.  Here is the implementation:
// Default BackgroundCopyManager constructor
     // Set principal policy
     // Initialize locals
     HRESULT hr;
     // Create instance
     IBackgroundCopyManager __nogc* lpCopyManager = pCopyManager;
     hr = CoCreateInstance(__uuidof(BackgroundCopyManager2_0), NULL,
      (void**) &lpCopyManager);
     // Reset reference
     pCopyManager = lpCopyManager;
     // Throw exception if failed
         throw new COMException(ResourceMessageManager::UnknownExceptionMessage(String::Empty, S"CoCreateInstance", hr), hr);
} // constructor - BackgroundCopyManager
Next, we will look at how to create a job through the CreateJob method.  This is using all the items in the fully overloaded method:
Podwysocki::Services::BackgroundTransferServices::BackgroundCopyJob* Podwysocki::Services::BackgroundTransferServices::BackgroundCopyManager::CreateCopyJob(String* displayName, String* description, BackgroundCopyJobType jobType, System::Int64 retryPeriod, System::Int64 retryDelay)
     // Validate arguments
     ArgumentValidation::CheckForEmptyOrNullString(displayName, S"displayName");
     ArgumentValidation::CheckForStringMaxLength(256, displayName, S"displayName");
     ArgumentValidation::CheckForNullReference(description, S"description");
     // Initialize locals
     HRESULT hr;
     GUID pJobId;
     IBackgroundCopyJob* pJob = NULL;
     BackgroundCopyJob* pBgJob = NULL;
     IntPtr pDisplayName = Marshal::StringToCoTaskMemUni(displayName);
     LPCWSTR lpDisplayName = (LPCWSTR)pDisplayName.ToPointer();
         // Create job
         hr = pCopyManager->CreateJob(lpDisplayName, (BG_JOB_TYPE)jobType, &pJobId, &pJob);
              throw new COMException(ResourceMessageManager::UnknownExceptionMessage (S"IBackgroundCopyManager", S"CreateJob", hr), hr);
         // Create BackgroundCopyJob
         pBgJob = new BackgroundCopyJob(pJob);
         // Set properties
         pBgJob->Description = description;
         // Check if retry period not default
         if(retryPeriod != defaultRetryPeriod)
              pBgJob->NoProgressTimeout = retryPeriod;
         // Check if retry delay not default
         if(retryDelay != defaultRetryDelay)
              pBgJob->MinimumRetryDelay = retryDelay;
         return pBgJob;
    } // try
        // Release pDisplayName
   } // finally
} // BackgroundCopyManager::CreateCopyJob(String*, String*, BackgroundCopyJobType, Int64, Int64)
The next method is to get the jobs from the current manager.  The implementation is here:
Podwysocki::Services::BackgroundTransferServices::BackgroundCopyJobCollection* Podwysocki::Services::BackgroundTransferServices::BackgroundCopyManager::GetJobs(JobUserFlag jobUser)
     // Check if job flag set to all users
     if(JobUserFlag::AllUsers == jobUser)
          // Get the current principal and check if part of BUILTIN\Administrators
          WindowsPrincipal* principal = dynamic_cast<WindowsPrincipal*>(Thread::CurrentPrincipal);
               throw new SecurityException(ResourceMessageManager::GetJobAccessDeniedExceptionMessage);
     } // if - JobUserFlag
     // Initialize locals
     HRESULT hr;
     IEnumBackgroundCopyJobs* pJobs = NULL;
     IBackgroundCopyJob* pJob = NULL;
     ULONG cJobCount = 0;
     BackgroundCopyJobCollection* jobCollection = new BackgroundCopyJobCollection();
          hr = pCopyManager->EnumJobs((DWORD)jobUser, &pJobs);
               // Get count of jobs in queue
               // Iterate through jobs enum
               for(ULONG idx=0; idx<cJobCount; idx++)
                    // Get next item and break if error
                    hr = pJobs->Next(1, &pJob, NULL);
                         jobCollection->Add(new BackgroundCopyJob(pJob));
                         throw new COMException(ResourceMessageManager::UnknownExceptionMessage(S"IEnumBackgroundCopyJobs", S"Next", hr), hr);
               } // for - idx<cJobCount
               return jobCollection;
          } // if - SUCCEEDED
               throw new COMException(ResourceMessageManager::UnknownExceptionMessage(S"IBackgroundCopyManager", S"EnumJobs", hr), hr);
          } // else - SUCCEEDED
    } // try
         // Release pJobs
    } // finally
} // method - BackgroundCopyManager::GetJobs
Finally, we're going to going to get a job by a Guid.  This of course must be converted to a BITS GUID before we can pass it to the service.  This requires a bit of translation which we have in an internal class.  Here is the implementation:
Podwysocki::Services::BackgroundTransferServices::BackgroundCopyJob* Podwysocki::Services::BackgroundTransferServices::BackgroundCopyManager::GetJobById(System::Guid id)
     // Define locals
     HRESULT hr;
     IBackgroundCopyJob* pJob = NULL;
     REFGUID wGuid = BackgroundTransferServicesUtility::ConvertToWinGuid(id);
     // Get by ID
     hr = pCopyManager->GetJob(wGuid, &pJob);
     if(BG_E_NOT_FOUND == hr)
          throw new ArgumentException(ResourceMessageManager::JobNotFoundExceptionMessage(id.ToString()), S"id");
     else if(E_ACCESSDENIED == hr)
          thow new SecurityException(ResourceMessageManager::GetJobAccessDeniedExceptionMessage);
     else if(FAILED(hr))
          throw new COMException(ResourceMessageManager::UnknownExceptionMessage(S"IBackgroundCopyManager", S"GetJob", hr), hr);
     return new BackgroundCopyJob(pJob);
} // method - BackgroundCopyManager::GetJobById
As you can see, it's not the most pretty thing to convert between managed and unmanaged types.  Once you get the pattern down, the conversion process can be quite easy as I found.  As always you must clean up after your objects.  I will cover a little more in depth, but the code can get massive for just a little blog.  I just want people to get the absolute basics of going between managed and unmanaged types.
Posted on Monday, May 15, 2006 3:08 PM Microsoft , Background Intelligent Transfer Service , .NET , Windows | Back to top

Comments on this post: Day 5 of the Background Intelligent Transfer Service (BITS) Managed Wrapper

# re: Day 5 of the Background Intelligent Transfer Service (BITS) Managed Wrapper
Requesting Gravatar...
I am looking for a way to automate BITS monitoring - I have an application that uses BITS and I want to monitor any and all performance counters regarding BITS that I can find (queue length, status, job avg time etc)
Do you think your code can help me with this?
Left by yariv on Mar 15, 2010 12:48 PM

Your comment:
 (will show your gravatar)

Copyright © Matthew Podwysocki | Powered by: