C# Kodundan MBX’e Parametre Gönderme
Bir integrated mapping uygulamasında bazen elimizde hazır bulunan bir MBX uygulamasını kullanmak isteyebiliriz. Bunun bazı faydaları olabilir:
1) Tekrar kullanım: Daha önce sapasağlam çalışan bu MBX uygulamasını integrated mapping e taşıma zahmetinden kurtulabiliriz.
2) Senkronizasyon problemlerine çözüm: Integrated mapping de özellikle uzun süren bazı işlemlerde karşımıza çıkabilen senkronizasyon problemlerini çözmede kullanabiliriz. Peki ne zaman çıkar bu senkronizasyon problemleri? Bir MapBasic programındaki kod satırları sırayla, yani senkron olarak çalışır. Örneğin bir MapBasic kod satırı saatlerce süren bir işlem yapıyor olsa bile, bu işlem bitmeden sonraki kod satırına geçilmez. Ama integrated mapping uygulamalarında durum böyle değildir çünkü ortada birbirinden bağımsız çalışan 2 ayrı proses (C# uygulama exe si ve MapInfow.exe) vardır. Gerçi normal olarak MapInfo C# tarafından gelen MapBasic komutlarını kuyruğa (queue) alır ve bu komutları sırayla çalıştırır. Ama bazı durumlarda (mesela Spatial VT den linked tablo ile download yapan bazı MapBasic komutlarında) senkronizasyon problemi olabiliyor. Böyle bir durumda uzun süren bu gibi işlemleri bir MBX e yaptırmak daha uygun olabilir.
Tabi burada daha önceden belirlenmiş sabit bir iş yapan bir MBX den söz etmiyoruz. Herhangi bir parametre almayan statik bir MBX i çalıştırmak bildiğimiz gibi gayet kolay:
mi.Do("Run Application ... MBX yolu");
gibi tek satırlık bir kodla bu işi kolayca yapabiliyoruz. Peki bir MBX e C# tarafından parametre göndermemiz gerekirse ne yapacağız? Bu sorunun cevabı MBApplications koleksiyonuyla verilebilir. MBApplications, MapInfo’nun o an çalıştırdığı tüm MapBasic uygulamalarını döndüren bir koleksiyondur. MBApplications kullanımı VB6 ve C# ta farklılık arz ediyor. VB6’daki kullanımı son derece kolay. Mesela çalışan bir MBX uygulamasına rahatça ulaşabilir ve bu uygulamadaki global MapBasic değişkenlerine aşağıdaki gibi değer atayabiliriz:
mi.MBApplications("test.mbx").MBGlobals("globalVar").Value = Text1.Text
Veya test.mbx deki RemoteMsgHandler prosedürüne şu şekilde parametre gönderebiliriz:
mi.MBApplications("test.mbx").Do ("parametre")
Ama C# ta işimiz bu kadar kolay değil. Öncelikle şunu belirtelim ki yukarıdaki örneklerden de anlaşılacağı üzere C# tan (aynı zamanda diğer dillerden) bir MBX e parametre göndermenin 2 yolu (DDE yi de sayarsak 3 olur ama şu anki konumuzun dışında oluyor kendileri) vardır:
1) MBGlobals koleksiyonunu kullanıp Global MapBasic değişkenlerine değer atamak:
mi.MBApplications
bize object tipinde bir nesne döndürdüğü için MBApplications koleksiyonunun elemanlarına yani çalışmakta olan MBX uygulamalarına doğrudan ulaşamayız. İşte burada yapmamız gereken DMBApplications interface ini kullanmaktır:
(DMBApplications)mi.MBApplications
ifadesi bize gerekli yardımı sağlayacaktır. DMBApplications interface i IEnumerable dan extend ettiği için bir foreach döngüsüyle çalışmakta olan tüm MBX’lere ulaşabiliriz:
private DMapBasicApplication GetMBXByName(string mbxName) { foreach (DMapBasicApplication mbApp in (DMBApplications)mi.MBApplications) { if (mbApp.Name.Equals(mbxName)) { return mbApp; } } return null; }
Bu kod bize adı verilen bir MBX uygulamasını DMapBasicApplication tipinde döndürür.
İstediğimiz MBX e bu şekilde ulaştıktan sonra sıra geldi MBX’imizin içindeki global MapBasic değişkenlerine ulaşmaya:
private DMBGlobals GetMapBasicGlobals(string mbxName) { return (DMBGlobals)GetMBXByName(mbxName).MBGlobals; }
Bu MapBasic global değişkenlerine C# tarafından değer atayabilmek için aşağıdaki gibi bir metot kullanabiliriz:
private void SetMapBasicGlobalVariable(string mbxName, string globalName, string globalValue) { DMBGlobals mbGlobals = GetMapBasicGlobals(mbxName); if (mbGlobals != null) { foreach (DMBGlobal mbGlobal in mbGlobals) { if (mbGlobal.Name.ToUpper().Equals(globalName.ToUpper())) { mbGlobal.Value = globalValue; } } } }
Peki MBX de bulunan ve asıl işi yapacak olan ShadeByRangeOfValues() metodunu C# tarafından nasıl çağıracağız?
Direkt olarak çağıramıyoruz. Zaten bu yüzden bu işlerle uğraşıyoruz. 🙂 Önceki adımlardan sonra MBX deki 3 global değişkenimizi set ettik ve ShadeByRangeOfValues() metodu da bu değişkenleri kullanıyor. Bu yüzden yapılması gereken şey RemoteMsgHandler prosedürüne
Call ShadeByRangeOfValues()
satırı ekleyerek ShadeByRangeOfValues() prosedürünü çalıştırmak. RemoteMsgHandler prosedürünü çalıştırmak için ise tek yapmamız gereken C# tarafındaki MBX uygulamamızın Do() metodunu aşağıdaki gibi çağırmak:
private void MbxDo(string mbxName, string command) { DMapBasicApplication mbApp = GetMBXByName(mbxName); if (mbApp != null) { mbApp.Do(command); } }
Bu metodu örneğin
MbxDo("Shade.mbx", "");
şeklinde çağırırsak MBX imize tablo, kolon ve aralık sayısı parametrelerini göndererek tematik yaptırmış oluruz. Global MapBasic değişkenlerine değer atama yöntemi bu şekilde. Bu arada kullanacağımız MapBasic dosyası da aşağıdaki gibi olsun:
include "mapbasic.def" declare sub Main declare sub RemoteMsgHandler declare sub ShadeByRangeOfValues global tableName as string global columnName as string global rangeNum as integer Sub Main 'Burada bir şey yapmamıza gerek yok. 'MBX çalıştırıldığında RemoteMsgHandler dinlemeye geçer ve 'C# tarafından Form1.MbxDo() metodu ile gelecek parametreyi bekler. End Sub Sub RemoteMsgHandler 'C# ta Form1.MbxDo() metodunda bulunan mbApp.Do(command); satırı ile gönderilen command değerini al Note CommandInfo(CMD_INFO_MSG) Call ShadeByRangeOfValues() End Sub Sub ShadeByRangeOfValues() '... Shade tableName With columnAlias Ranges From Variable range_limits Style Variable brush_styles End Sub
2) MBX.Do() metodu ile MapBasic tarafındaki RemoteMsgHandler prosedürüne komut (parametre) göndermek:
Global değişkenleri hiç kullanmadan aşağıdaki gibi daha kısa bir MapBasic ile RemoteMsgHandler prosedürüne bir ayıraç ile ayrılmış değerler gönderebiliriz:
private void MbxDo(string mbxName, string command) { DMapBasicApplication mbApp = GetMBXByName(mbxName); if (mbApp != null) { // Bu satır çalıştığında göndermekte olduğumuz command değeri Shade.mb de bulunan // RemoteMsgHandler prosedüründeki CommandInfo(CMD_INFO_MSG) komutu ile alınabilir. mbApp.Do(command); } }
include "mapbasic.def" declare sub Main declare sub RemoteMsgHandler declare sub ShadeByRangeOfValues Sub Main 'Burada bir şey yapmamıza gerek yok. 'MBX çalıştırıldığında RemoteMsgHandler dinlemeye geçer ve 'C# tarafından Form1.MbxDo() metodu ile gelecek parametreyi bekler. End Sub Sub RemoteMsgHandler 'C# ta Form1.MbxDo() metodunda bulunan mbApp.Do(command); satırı ile gönderilen command değerini al Note CommandInfo(CMD_INFO_MSG) 'Burası örneğin "Mahalle|Nufus|5" gibi bir string olabilir. (Ayıraç olarak pipe (|) kullandık.) Call ShadeByRangeOfValues() End Sub Sub ShadeByRangeOfValues() 'CommandInfo(CMD_INFO_MSG) ile alınan ve ayıraç ile ayrılan parametreleri parse et ve 'tableName, columnName vb. değişkenlerinin değerini buradan al. Shade tableName With columnAlias Ranges From Variable range_limits Style Variable brush_styles End Sub
Örnek C# projesini aşağıdaki linkten indirebilirsiniz:
https://dl.dropboxusercontent.com/u/54151940/GIS/MapInfo/IntegratedMapping/CS_MBApplications.rar
http://www.sonercelix.com/MakaleDetay/2060/C-ile-exe-dosyasina-parametre-gonderimi
Bu konuyla ilgili anlatımlar sitede mevcuttur. Ayrıca bu tarz konularla ilgili bilgi bulabileceğiniz bir sitedir. Uzun zamandır takip ettiğim ve beğendiğim bir sitedir. Tavsiye ederim.
Bağlantısını verdiğiniz sitede C# hakkında faydalı yazılar olmakla birlikte, bu sayfada bahsettiğim konu biraz farklı. Burada bahsedilen, bir C# uygulamasından bir *.exe ye parametre göndermek değil, bir MapBasic programına (*.mbx) parametre göndermektir.