Başvuru DLL'lerini kullanarak .NET ve C# içinden BITS'ye çağırma
.NET programından BITS COM sınıflarını çağırmanın bir yolu, MIDL ve TLBIMP araçlarını kullanarak Windows SDK'daki BITS IDL (Arabirim Tanım Dili) dosyalarıyla başlayan bir başvuru DLL dosyası oluşturmaktır. Başvuru DLL'i, BITS COM sınıfları için bir sınıf sarmalayıcı kümesidir; Daha sonra sarmalayıcı sınıflarını doğrudan .NET'ten kullanabilirsiniz.
Otomatik olarak oluşturulan başvuru DLL'lerini kullanmanın bir alternatifi, GitHub ve NuGet 'tan üçüncü taraf bir .NET BITS sarmalayıcı kullanmaktır. Bu sarmalayıcılar genellikle daha doğal bir .NET programlama stiline sahiptir, ancak BITS arabirimlerindeki değişikliklerin ve güncelleştirmelerin gerisinde kalabilirler.
Referans DLL'leri oluşturma
BITS IDL dosyaları
BITS IDL dosyaları kümesiyle başlayacaksınız. Bunlar BITS COM arabirimini tam olarak tanımlayan dosyalardır. Dosyalar Windows Kits dizininde bulunur ve bitssürüm.idl (örneğin, bits10_2.idl) olarak adlandırılır. Ancak, sürüm 1.0 için dosya sadece Bits.idl olarak adlandırılmıştır. BITS'in yeni sürümleri oluşturulduktan sonra yeni BITS IDL dosyaları da oluşturulur.
Otomatik olarak .NET eşdeğerlerine dönüştürülmeyen BITS özelliklerini kullanmak için SDK BITS IDL dosyalarının bir kopyasını da değiştirmek isteyebilirsiniz. Olası IDL dosya değişiklikleri daha sonra açıklanacaktır.
BITS IDL dosyaları başvuruya göre birkaç farklı IDL dosyası içerir. Ayrıca iç içe yerleştirilmiştir, böylece bir sürüm kullanırsanız tüm alt sürümleri içerir.
Programınızda hedeflemek istediğiniz her BITS sürümü için bu sürüm için bir başvuru DLL'sine ihtiyacınız olacaktır. Örneğin, BITS 1.5 ve üstü üzerinde çalışan ancak BITS 10.2 mevcut olduğunda ek özelliklere sahip bir program yazmak istiyorsanız, hem bits1_5.idl hem de bits10_2.idl dosyalarını dönüştürmeniz gerekir.
MIDL ve TLBIMP yardımcı programları
MIDL (Microsoft Arabirim Tanım Dili) yardımcı programı, BITS COM arabirimini açıklayan IDL dosyalarını TLB (Tür Kitaplığı) dosyasına dönüştürür. MIDL aracı, IDL dil dosyasını doğru okumak için CL yardımcı programı (C ön işlemci) bağlıdır. CL yardımcı programı Visual Studio'nun bir parçasıdır ve Visual Studio yüklemesine C/C++ özellikleri eklediğinizde yüklenir.
MIDL yardımcı programı normalde bir dizi C ve H (C dil kodu ve C dil üst bilgisi) dosyası oluşturur. Çıkışı NUL: cihazına göndererek bu ek dosyaları gizleyebilirsiniz. Örneğin, /dlldata NUL: anahtarının ayarlanması dlldata.c dosyasının oluşturulmasını gizler. Aşağıdaki örnek komutlar, hangi anahtarların NUL: olarak ayarlanması gerektiğini gösterir.
TLBIMP (Tür Kitaplığı İçeri Aktarıcı) yardımcı programı bir TLB dosyasını okur ve karşılık gelen başvuru DLL dosyasını oluşturur.
MIDL ve TLBIMP için örnek komutlar
Bu, bir dizi başvuru dosyası oluşturmaya yönelik tam komut kümesinin bir örneğidir. Komutları Visual Studio ve Windows SDK yüklemenize ve hedeflediğiniz BITS özelliklerine ve işletim sistemi sürümlerine göre değiştirmeniz gerekebilir.
Örnek, başvuru DLL dosyalarını yerleştirmek için bir dizin oluşturur ve bu dizine işaret eden bir ortam değişkeni BITSTEMP oluşturur.
Örnek komutlar daha sonra Visual Studio yükleyicisi tarafından oluşturulan vsdevcmd.bat dosyasını çalıştırır. Bu BAT dosyası, MIDL ve TLBIMP komutlarının çalışması için yollarınızı ve bazı ortam değişkenlerini ayarlar. Ayrıca WindowsSdkDir ve WindowsSDKLibVersion değişkenlerini en son Windows SDK dizinlerine işaret eden şekilde ayarlar.
REM Create a working directory
REM You can select a different directory based on your needs.
SET BITSTEMP=C:\BITSTEMPDIR
MKDIR "%BITSTEMP%"
REM Run the VsDevCmd.bat file to locate the Windows
REM SDK directory and the tools directories
REM This will be different for different versions of
REM Visual Studio
CALL "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\Tools\vsdevcmd.bat"
REM Run the MIDL command on the desired BITS IDL file
REM This will generate a TLB file for the TLBIMP command
REM The IDL file will be different depending on which
REM set of BITS interfaces you need to use.
REM Run the MIDL command once per reference file
REM that you will need to explicitly use.
PUSHD .
CD /D "%WindowsSdkDir%Include\%WindowsSDKLibVersion%um"
MIDL /I ..\shared /out "%BITSTEMP%" bits1_5.idl /dlldata NUL: /header NUL: /iid NUL: /proxy NUL:
MIDL /I ..\shared /out "%BITSTEMP%" bits4_0.idl /dlldata NUL: /header NUL: /iid NUL: /proxy NUL:
MIDL /I ..\shared /out "%BITSTEMP%" bits5_0.idl /dlldata NUL: /header NUL: /iid NUL: /proxy NUL:
MIDL /I ..\shared /out "%BITSTEMP%" bits10_1.idl /dlldata NUL: /header NUL: /iid NUL: /proxy NUL:
MIDL /I ..\shared /out "%BITSTEMP%" bits10_2.idl /dlldata NUL: /header NUL: /iid NUL: /proxy NUL:
REM Run the TLBIMP command on the resulting TLB file(s)
REM Try to keep a parallel set of names.
TLBIMP "%BITSTEMP%"\bits1_5.tlb /out: "%BITSTEMP%"\BITSReference1_5.dll
TLBIMP "%BITSTEMP%"\bits4_0.tlb /out: "%BITSTEMP%"\BITSReference4_0.dll
TLBIMP "%BITSTEMP%"\bits5_0.tlb /out: "%BITSTEMP%"\BITSReference5_0.dll
TLBIMP "%BITSTEMP%"\bits10_1.tlb /out: "%BITSTEMP%"\BITSReference10_1.dll
TLBIMP "%BITSTEMP%"\bits10_2.tlb /out: "%BITSTEMP%"\BITSReference10_2.dll
DEL "%BITSTEMP%"\bits*.tlb
POPD
Bu komutlar çalıştırıldıktan sonra BITSTEMP dizininde bir dizi başvuru DLL'sine sahip olursunuz.
Projenize referans DLL'lerini ekleme
C# projesinde başvuru DLL'si kullanmak için, C# projenizi Visual Studio'da açın. Çözüm Gezgini'nde Başvurular'a sağ tıklayın ve Başvuru Ekle'ye tıklayın. Ardından Gözat düğmesine ve ardından Ekle düğmesine tıklayın. Başvuru DLL'leri içeren dizine gidin, bunları seçin ve Ekle'ye tıklayın. Başvuru Yöneticisi penceresinde başvuru DLL'leri denetlenecektir. Ardından Tamam'a tıklayın.
BITS başvuru DLL'leri artık projenize eklenir.
Başvuru DLL dosyalarındaki bilgiler son programınıza eklenir. Başvuru DLL dosyalarını programınızla birlikte göndermeniz gerekmez; sadece .EXE göndermeniz gerekiyor.
Başvuru DLL'lerinin son EXE'ye eklenip eklenmeyeceğini değiştirebilirsiniz. Başvuru DLL'lerinin gömülüp gömülmeyeceğini ayarlamak için Embed Interop Types özelliğini kullanın. Bu, her referans için yapılabilir. DLL'leri eklemek için varsayılan değer True'dur.
Daha eksiksiz .NET kodu için IDL dosyalarını değiştirme
BITS IDL (Microsoft Arabirim Tanım Dili) dosyaları, BackgroundCopyManager DLL dosyasını yapmak için değiştirilmeden kullanılabilir. Ancak, sonuçta elde edilen .NET referans DLL'sinde bazı dönüştürülemeyen birlikler eksik olur ve bazı yapılar ve sabit listeler için kullanımı zor adlara sahiptir. Bu bölümde, .NET DLL'sini daha eksiksiz ve kullanımı kolay hale getirmek için yapabileceğiniz bazı değişiklikler açıklanmaktadır.
Daha basit ENUM adları
BITS IDL dosyaları genellikle enum değerlerini şu şekilde tanımlar:
typedef enum
{
BG_AUTH_TARGET_SERVER = 1,
BG_AUTH_TARGET_PROXY
} BG_AUTH_TARGET;
BG_AUTH_TARGET, tür tanımının adıdır; gerçek enum ise adlandırılmamıştır. Bu genellikle C koduyla ilgili sorunlara neden olmaz, ancak .NET programıyla kullanmak için uygun değildir. Yeni bir ad otomatik olarak oluşturulur, ancak insan tarafından okunabilir bir değer yerine _MIDL___MIDL_itf_bits4_0_0005_0001_0001 gibi görünebilir. MIDL dosyalarını bir enum adı içerecek şekilde güncelleştirerek bu sorunu çözebilirsiniz.
typedef enum BG_AUTH_TARGET
{
BG_AUTH_TARGET_SERVER = 1,
BG_AUTH_TARGET_PROXY
} BG_AUTH_TARGET;
Enum adının typedef adıyla aynı olmasına izin verilir. Bazı programcıların, farklı tutulmalarını sağlamak için bir adlandırma kuralı vardır (örneğin, enum adının önüne bir alt çizgi koyarak), ancak bu .NET çevrimlerini sadece kafa karıştırıcı hale getirir.
Birleşimlerdeki string türleri
BITS IDL dosyaları, LPWSTR (geniş karakter dizesine uzun işaretçi) kuralını kullanarak dizeleri geçirir. İşlev parametreleri geçirilirken (Job.GetDisplayName([out] LPWSTR *pVal) yöntemi gibi) bu çalışsa da, metinler birleşimlerin parçası olduğunda çalışmaz. Örneğin, bits5_0.idl dosyası BITS_FILE_PROPERTY_VALUE birleşimini içerir:
typedef [switch_type(BITS_FILE_PROPERTY_ID)] union
{
[case( BITS_FILE_PROPERTY_ID_HTTP_RESPONSE_HEADERS )]
LPWSTR String;
}
BITS_FILE_PROPERTY_VALUE;
LPWSTR alanı birleşimin .NET sürümüne dahil edilmeyecektir. Bunu düzeltmek için LPWSTR değerini WCHAR* olarak değiştirin. Sonuçta elde edilen alan (Dize olarak adlandırılır) IntPtr olarak geçirilir. System.Runtime.InteropServices.Marshal.PtrToStringAuto(value.String) yöntemini kullanarak bunu bir dizeye dönüştürün.
Yapılardaki birleşimler
Bazen yapılara gömülü olan birleşimler yapıya hiç dahil edilmez. Örneğin, Bits1_5.idl dosyasında BG_AUTH_CREDENTIALS aşağıdaki gibi tanımlanır:
typedef struct
{
BG_AUTH_TARGET Target;
BG_AUTH_SCHEME Scheme;
[switch_is(Scheme)] BG_AUTH_CREDENTIALS_UNION Credentials;
}
BG_AUTH_CREDENTIALS;
BG_AUTH_CREDENTIALS_UNION aşağıdaki gibi bir birleşim olarak tanımlanır:
typedef [switch_type(BG_AUTH_SCHEME)] union
{
[case( BG_AUTH_SCHEME_BASIC, BG_AUTH_SCHEME_DIGEST, BG_AUTH_SCHEME_NTLM,
BG_AUTH_SCHEME_NEGOTIATE, BG_AUTH_SCHEME_PASSPORT )] BG_BASIC_CREDENTIALS Basic;
[default] ;
} BG_AUTH_CREDENTIALS_UNION;
BG_AUTH_CREDENTIALS Kimlik Bilgileri alanı .NET sınıf tanımına dahil edilmeyecektir.
Birleşimin, BG_AUTH_SCHEME'den bağımsız olarak her zaman BG_BASIC_CREDENTIALS olarak tanımlandığını unutmayın. Birlik gerçek bir birlik olarak kullanılmadığından, BG_BASIC_CREDENTIALS'i böyle geçebiliriz:
typedef struct
{
BG_AUTH_TARGET Target;
BG_AUTH_SCHEME Scheme;
BG_BASIC_CREDENTIALS Credentials;
}
BG_AUTH_CREDENTIALS;
C# ile BITS kullanma
Using deyimini kullanmanız önerilir
C# dilinde bazı using deyimlerinin ayarlanması, farklı BITS sürümlerini kullanmak için yazmanız gereken karakter sayısını azaltır. "BITSReference" adı, başvuru DLL'sinin adından gelir.
// Set up the BITS namespaces
using BITS = BITSReference1_5;
using BITS4 = BITSReference4_0;
using BITS5 = BITSReference5_0;
using BITS10_2 = BITSReference10_2;
Hızlı Örnek: dosya indirme
Url'den dosya indirmek için C# kodunun kısa ama eksiksiz bir kod parçacığı aşağıda verilmiştir.
var mgr = new BITS.BackgroundCopyManager1_5();
BITS.GUID jobGuid;
BITS.IBackgroundCopyJob job;
mgr.CreateJob("Quick download", BITS.BG_JOB_TYPE.BG_JOB_TYPE_DOWNLOAD, out jobGuid, out job);
job.AddFile("https://aka.ms/WinServ16/StndPDF", @"C:\Server2016.pdf");
job.Resume();
bool jobIsFinal = false;
while (!jobIsFinal)
{
BITS.BG_JOB_STATE state;
job.GetState(out state);
switch (state)
{
case BITS.BG_JOB_STATE.BG_JOB_STATE_ERROR:
case BITS.BG_JOB_STATE.BG_JOB_STATE_TRANSFERRED:
job.Complete();
break;
case BITS.BG_JOB_STATE.BG_JOB_STATE_CANCELLED:
case BITS.BG_JOB_STATE.BG_JOB_STATE_ACKNOWLEDGED:
jobIsFinal = true;
break;
default:
Task.Delay(500); // delay a little bit
break;
}
}
// Job is complete
Bu örnek kodda, mgr adlı bir BITS yöneticisi oluşturulur. Doğrudan IBackgroundCopyManager arabirimine karşılık gelir.
Yönetici tarafından yeni bir iş oluşturulur. CreateJob yöntemindeki iş, bir out parametresidir. Geçirilen iş adı (benzersiz olması gerekmez) ve indirme türü de indirme işi olarak tanımlanır. İş tanımlayıcısı için BITS GUID'i de doldurulur.
İş oluşturulduktan sonra AddFile yöntemiyle işe yeni bir indirme dosyası eklersiniz. Biri uzak dosya (URL veya dosya paylaşımı) ve biri yerel dosya için olmak üzere iki dize geçirmeniz gerekir.
Dosyayı ekledikten sonra, işi başlatmak için Devam Et'e tıklayın. Ardından kod, iş son duruma gelene kadar (HATA veya AKTARILDI) bekler ve ardından tamamlanır.
BITS Sürümleri, Atama ve QueryInterface
Genellikle hem BITS nesnesinin erken bir sürümünü hem de programınızda daha yeni bir sürümü kullanmanız gerekecektir.
Örneğin, bir iş nesnesi oluşturduğunuzda, daha yeni bir yönetici nesnesi kullanıyor olsanız ve daha yeni bir IBackgroundCopyJob nesnesi de mevcut olsa bile, yine de bir IBackgroundCopyJob (BITS sürüm 1.0'ın bir parçası) alırsınız. CreateJob yöntemi daha yeni sürüm için bir arabirim kabul etmediğinden, doğrudan daha yeni sürümü yapamazsınız.
Eski bir tür nesnesinden daha yeni bir tür nesnesine dönüştürmek için .NET ataması kullanın. Dönüşüm, COM QueryInterface'i uygun şekilde otomatik olarak çağırır.
Bu örnekte, "job" adlı bir BITS IBackgroundCopyJob nesnesi vardır ve BITS 5.0 GetProperty yöntemini çağırabilmemiz için bunu "job5" adlı bir IBackgroundCopyJob5 nesnesine dönüştürmek istiyoruz. IBackgroundCopyJob5 türüne şöyle dönüştürme yaptık:
var job5 = (BITS5.IBackgroundCopyJob5)job;
job5 değişkeni doğru QueryInterface kullanılarak .NET tarafından başlatılır.
Kodunuz belirli bir BITS sürümünü desteklemeyen bir sistemde çalıştırılabilirse, atamayı deneyebilir ve System.InvalidCastException'ı yakalayabilirsiniz.
BITS5.IBackgroundCopyJob5 job5 = null;
try
{
job5 = (BITS5.IBackgroundCopyJob5)Job;
}
catch (System.InvalidCastException)
{
; // Must be running an earlier version of BITS
}
Yaygın bir sorun, yanlış türde bir nesneye dönüştürmeye çalışmanızdır. .NET sistemi, BITS arabirimleri arasındaki gerçek ilişkiyi bilmez. Yanlış türde bir arabirim isterseniz, .NET bunu sizin için yapmaya çalışır ve InvalidCastException ve HResult 0x80004002 (E_NOINTERFACE) ile başarısız olur.
BITS Sürümleri 10_1 ve 10_2 ile çalışma
Windows 10'un bazı sürümlerinde, 10.1 veya 10.2 arabirimlerini kullanarak doğrudan BITS IBackgroundCopyManager nesnesi oluşturamazsınız. Bunun yerine, BackgroundCopyManager DLL başvuru dosyalarının birden çok sürümünü kullanmanız gerekir. Örneğin, 1.5 sürümünü kullanarak bir IBackgroundCopyManager nesnesi oluşturabilir ve ardından 10.1 veya 10.2 sürümlerini kullanarak sonuçta elde edilen işi veya dosya nesnelerini yayınlayabilirsiniz.