Wednesday, August 18, 2004

BITS C# Wrapper

I was recently using BITS (Background Intelligent Transfer Service) to create a component for uploading and downloading files asynchronously from a windows sharepoint services document library. One of the requirement was transfer can only be done by authenticated users. BITS version 1.5 and above supports this via the IBackgroundCopyJob2::SetCredentials method. However, this method uses an union in its parameter and C# does not have union. After playing with interop attributes for a while I've worked out the necessary attributes to make this work with a C# only wrapper without going to managed C++.

After looking at the definition for BG_AUTH_CREDENTIALS in the .h file from the SDK, it turns out that the union (BG_AUTH_CREDENTIALS_UNION) only contains one type which is BG_BASIC_CREDENTIALS. I was able to make the call to SetCredentials work by using the FieldOffset attribute in the struct definitions.

Here is an extract of the important struct definitions.

internal enum BG_AUTH_SCHEME
{
// Fields
BG_AUTH_SCHEME_BASIC = 1,
BG_AUTH_SCHEME_DIGEST = 2,
BG_AUTH_SCHEME_NTLM = 3,
BG_AUTH_SCHEME_NEGOTIATE = 4,
BG_AUTH_SCHEME_PASSPORT = 5
}

internal enum BG_AUTH_TARGET
{
// Fields
BG_AUTH_TARGET_SERVER = 1,
BG_AUTH_TARGET_PROXY = 2,
}

[StructLayout(LayoutKind.Explicit, Size=16, Pack=4)]
internal struct BG_AUTH_CREDENTIALS
{
[FieldOffset(0)]
public BG_AUTH_TARGET Target;

[FieldOffset(4)]
public BG_AUTH_SCHEME Scheme;

[FieldOffset(8)]
public BG_AUTH_CREDENTIALS_UNION Credentials;
}

[StructLayout(LayoutKind.Explicit, Size=8, Pack=4)]
internal struct BG_AUTH_CREDENTIALS_UNION
{
[FieldOffset(0)]
public BG_BASIC_CREDENTIALS Basic;
}

[StructLayout(LayoutKind.Explicit, Size=8, Pack=4)]
internal struct BG_BASIC_CREDENTIALS
{
[FieldOffset(0)]
[MarshalAs(UnmanagedType.LPWStr)]
public string UserName;

[FieldOffset(4)]
[MarshalAs(UnmanagedType.LPWStr)]
public string Password;
}

I've posted the interop library at http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=99f2f473-26de-41cd-bf39-8f7e75fda5aa

9 comments:

TDC said...

Many thanks for your work ont he C# wrapper. I'm trying to set up a callback but am getting errors that my method parameters are less accessible than the in the interface.

Also any chance of getting sample upload code?

Any response is much appreciated, code is below:

public class JobCallback : BITS.IBackgroundCopyCallback
{
public JobCallback()
{
//
// TODO: Add constructor logic here
//
}
public void JobTransferred(IBackgroundCopyJob job)
{
}
public void JobError(IBackgroundCopyJob job, IBackgroundCopyError error)
{
}
public void JobModification(IBackgroundCopyJob job, uint dwReserved)
{
}
}

Eddie Tse said...

Most of the definitions are marked "internal" because I need the final assembly to be CLR compliant and some of types defined in the interface definition were not.

If you don't need your assembly to be CLR compliant, you can change the interfaces and types from internal to public. Or you can mark your JobCallback class to be internal as well.

Carl said...

Hi Eddie, great Interop. I was trying to use the AddFileSet method though and could not get it to work. Do you have an example for me please?

Anonymous said...

This is a great piece of work. Suits my needs perfectly

xavier said...

So many thanks for your work ! I can't understand why MS don't provide it ... Anyway, you did it.
Regards

Anonymous said...

Hi Thanks for the workaround. I had problems running my application in 64 bit and found that I needed to change the LayoutKind for the _BG_BASIC_CREDENTIALS struct to Sequential. Then it all worked fine.

remote server administration said...

thanks for explanation using code... nice stuff...

Anonymous said...

Can anyone help me with setting up credentials? If I set them before I Activate() or Resume() it throws an error.

If I do it after, it doesn't seem to use the credentials since when I call resume the file upload errors out saying that authentification is required.

Does anyone understand what I'm doing wrong?

Thanks

digitis @ yahoo dot com

Anonymous said...

Now that gotdotnet.com is dead, here is the download link on MSDN Code Gallery.