czwartek, 5 lipca 2012

Pobranie ścieżki instalacyjnej zainstalowanego produktu po przez GUID - Get Install location by Product GUID in InstallShield

Przy tworzeniu aktualizacji czasami zachodzi potrzeba odczytania ścieżki instalacyjnej zainstalowanego wcześniej produktu. Jeżeli mamy GUID poprzedniego produktu możemy do tego wykorzystać poniższą funkcję. Funkcja odczytuje wartości rejestru zainstalowanych produktów.
Parametry:
  • GUID  - GUID zainstalowanego  produktu\
  • Path - odczytana ścieżka
  • Name - odczytana nazwa produktu
  • Version - odczytana wersja zainstalowanego produktu
  • bLog - zapis do loga 

Funkcja zwraca true/false, wartość true w przypadku pozytywnego odczytania ścieżki instalacyjnej.

Nagłówek funkcji

export prototype BOOL GetInstallLocationGUID(STRING, /*GUID*/ BYREF STRING /*Path*/, BYREF STRING /*Name*/, BYREF STRING /*Version*/, BOOL /*bLog*/); 

Ciało funkcji
function BOOL GetInstallLocationGUID(szGUID, svPath, svName, svVersion, bLog)
#define UKEY  "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
string RegPath, sKey, sValue, sData, sFolder;   
number nReturn, nResult, nType, nSize, i, nData;
BOOL bResult;
LIST   listSubKeys;
begin
  bResult = FALSE;
  
  if (bLog) then  WriteLog(1,"Odczyt ścieżki do zainstalowanego produktu"); endif;   
   
  listSubKeys  =  ListCreate(STRINGLIST);   
  RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
  nReturn = RegDBQueryKey(UKEY, REGDB_KEYS, listSubKeys );
  if (nReturn=0) then
   ListGetFirstString ( listSubKeys, sKey );
   if (ListCount(listSubKeys)>0) then        
       
     ListSetIndex(listSubKeys, LISTFIRST);
     for i=0 to ListCount(listSubKeys)-1
       ListCurrentString ( listSubKeys, sKey ); 
       if (sKey==szGUID) then                                 
         if (bLog) then  WriteLog(2,"- znaleziono zainstalowany produkt "+szGUID); endif;   
                
         RegPath=UKEY+"\\"+sKey;
         sFolder=sKey;
         if (RegDBKeyExist(RegPath)==1) then                      
                         
            sKey = RegPath;                            
            sValue="DisplayName";
            nType = REGDB_STRING;
            if (RegDBGetKeyValueEx( sKey, sValue, nType, sData, nSize )==0) then
              svName = sData;
              if (bLog) then  WriteLog(3,"- nazwa produktu "+sData); endif;   
            else
              svName = "";
              if (bLog) then WriteLog(3,"- brak klucza nazwy produktu "); endif;   
            endif;                         
                                                   
            sValue="DisplayVersion";                         
            if (RegDBGetKeyValueEx( sKey, sValue, nType, sData, nSize )==0) then
             svVersion = sData;
             if (bLog) then  WriteLog(3,"- wersja produktu "+sData); endif;   
            else
             svVersion = "";
             if (bLog) then  WriteLog(3,"- brak klucza wersji produktu "); endif;   
            endif;
                         
            sValue="InstallLocation";                                   
            if (RegDBGetKeyValueEx( sKey, sValue, nType, sData, nSize )==0) then
              if (bLog) then  WriteLog(3,"- ścieżka instalacji "+sData); endif;          

              svPath = sData;
              bResult = TRUE;
            else
              if (bLog) then  WriteLog(3,"- brak klucza ścieżki instalacyjne "); endif;   
            endif;
                        
            sValue="InstallDate";                                   
            if (RegDBGetKeyValueEx( sKey, sValue, nType, sData, nSize )==0) then
              if (bLog) then  WriteLog(3,"- data instalacji "+sData); endif;                                
              bResult = TRUE;
            else
              if (bLog) then  WriteLog(3,"- brak klucza daty instalacji "); endif;   
            endif;
          endif;
        endif;   
                 
        ListSetIndex(listSubKeys, LISTNEXT);
      endfor;
         
    else
      if (bLog) then  WriteLog(2,"- brak listy zainstalowanych produktow GUID"); endif;   
    endif;
     
   else
     if (bLog) then  WriteLog(2,"- błąd odczytu rejestru"); endif;   
   endif;           

  return bResult;         
end;


Oprócz ścieżki instalacyjnej (Path) , funkcja zwraca nazwę produktu (Name) i wersję (Version)

poniedziałek, 2 lipca 2012

Walidacja numeru Dowodu Osobistego w c#

Funkcja walidująca numer dowodu osobistego w c# wraz z formatowaniem.
Funkcja oparta o sumę kontrolną

/// <summary>
/// Weryfikacja Nr Dowowdu Osobistego
/// </summary>
/// <param name="szNR">Nr Dowodu</param>
/// <param name="retFormated">Czy zwracać numer w postaci sformatowanej</param>
/// <returns>true/false</returns>
public static bool ValidateDO(ref string szNR, bool retFormated = true)
{
    byte[] tab = new byte[9] { 7, 3, 1, 9, 7, 3, 1, 7, 3 };
    byte[] tablicz = new byte[] { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57 };
          
    bool bResult = false;
    int sumcontrol = 0;
    int sum = 0;

    szNR = szNR.Trim().Replace(" ", "");
           
    if (szNR.Length == 9)
    {               
        byte b;
               
        for (int i = 0; i < 3; i++)
        {
            b = Convert.ToByte(szNR[i]);
            if (b < 65 || b > 90) return false;
        }
        for (int i = 3; i < 9; i++)
        {
            b = Convert.ToByte(szNR[i]);
            if (b < 48 || b > 57) return false;
        }
               
        sumcontrol = Convert.ToInt32(szNR[3].ToString());

        for (int i = 0; i < 9; i++)
        {
            if (i < 3)
            {
                sum += (Convert.ToByte(szNR[i]) - 55) * tab[i];
            }
            else
            {
                sum += Convert.ToInt32(szNR[i].ToString()) * tab[i];
            }
        }

        bResult = ((sum % 10) == 0);

    }
    else return false;

    if (bResult && retFormated)
    {
        szNR = szNR.Insert(3, " ");                               
    }

    return bResult;
}

Walidacja numeru konta bankowego w c#

Poniżej przedstawiam funkcję walidującą numer konta bankowego zarówno przyjętego w Polsce 26 i 28 znakowy.
Funkcja może zwrócić podany numer w postaci sformatowanej tj ze spacjami.

/// <summary>
/// Walidacja numeru bankowego
/// </summary>
/// <param name="szNR">weryfikowany numer</param>
/// <param name="retFormated">Czy zwracać numer w postaci sformatowanej</param>
/// <returns>true/false</returns>
public static bool ValidateIBAN_NRB(ref string szNR, bool retFormated = true)
{
    bool bResult = false;

    szNR = szNR.Trim()
                .Replace(" ", "")
                .Replace("-", "");
          
    if (szNR.Length == 26 || szNR.Length == 28)
    {
        string nr = szNR;
        if (nr.Length == 26)
        {
            nr = (nr +"PL"+ nr.Substring(0, 2)).Remove(0, 2);
        }
        else
        {
            nr = (nr + nr.Substring(0, 4)).Remove(0, 4);
        }

        nr = nr.Replace("P", "25").Replace("L", "21");

        String nr6 = nr.Substring(0, 6);
        String nr12 = nr.Substring(6, 6);
        String nr18 = nr.Substring(12, 6);
        String nr24 = nr.Substring(18, 6);
        String nr30 = nr.Substring(24);

        int r = Convert.ToInt32(nr6) % 97;
        nr12 = (r > 0 ? r.ToString() : "") + nr12;
        r = Convert.ToInt32(nr12) % 97;
        nr18 = (r > 0 ? r.ToString() : "") + nr18;
        r = Convert.ToInt32(nr18) % 97;
        nr24 = (r > 0 ? r.ToString() : "") + nr24;
        r = Convert.ToInt32(nr24) % 97;
        nr30 = (r > 0 ? r.ToString() : "") + nr30;               

        bResult = (Convert.ToInt32(nr30) % 97 == 1);
    }
    else return false;

    if (bResult && retFormated)
    {
        if (szNR.Length==26)
        {
            szNR = szNR.Insert(22, " ").Insert(18, " ").Insert(14, " ").Insert(10, " ").Insert(6, " ").Insert(2, " ");
        }
        else
        {
            szNR = szNR.Insert(24, " ").Insert(20, " ").Insert(16, " ").Insert(12, " ").Insert(8, " ").Insert(4, " ");
        }
    }

    return bResult;
}

Walidacja numeru Regon w c#

Funkcja walidująca numer Regon w c# zarówno 9-cio jak i 14 cyfrowy.
Walidacja na podstawie sumy kontrolnej jak oraz długości ciągu cyfr.
Funkcja zwrac true w przypadku poprawnego numeru

public static bool ValidateRegon(ref string szRegon)
{
    byte[] tab8 = new byte[8] { 8, 9, 2, 3, 4, 5, 6, 7 };
    byte[] tab13 = new byte[13] { 2, 4, 8, 5, 0, 9, 7, 3, 6, 1, 2, 4, 8 };
    byte[] tablicz = new byte[] { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57 };
    bool bResult = false;
    int suma = 0;
    int sumcontrol = 0;

    szRegon = szRegon.Trim();

    if ((szRegon.Length == 9)||(szRegon.Length==14))
    {
        foreach (char l in szRegon)
        {
            byte b = Convert.ToByte(l);
            if (Array.IndexOf(tablicz, Convert.ToByte(l)) == -1) return false;
        }

        sumcontrol = Convert.ToInt32(szRegon[(szRegon.Length==9)?8:13].ToString());

        for (int i = 0; i < ((szRegon.Length==9)?8:13); i++)
        {
            suma += ((szRegon.Length==9)?tab8[i]:tab13[i]) * Convert.ToInt32(szRegon[i].ToString());
        }

        bResult = ( (((suma % 11)!=10)?(suma % 11):0) == sumcontrol);
    }
    else return false;
          
    return bResult;
}

Walidacja numeru NIP w c#

Funkcja walidująca numer NIP w c# wraz z formatowaniem.

/// <summary>
/// Walidacja NIP
/// </summary>
/// <param name="szNIP"></param>
/// <param name="retFormated"> Zwracany NIP jest w postaci sformatowanej</param>
/// <returns>zwraca true/false</returns>


public static bool ValidateNIP(ref string szNIP, bool retFormated = true)
{
    byte[] tab = new byte[9] { 6, 5, 7, 2, 3, 4, 5, 6, 7 };
    byte[] tablicz = new byte[] { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57 };
    bool bResult = false;
    int suma = 0;
    int sumcontrol = 0;

    szNIP = szNIP.Replace("-", "");
    szNIP = szNIP.Trim();

    if (szNIP.Length == 10)
    {
        foreach (char l in szNIP)
        {
            byte b = Convert.ToByte(l);
            if (Array.IndexOf(tablicz, Convert.ToByte(l)) == -1) return false;
        }

        sumcontrol = Convert.ToInt32(szNIP[9].ToString());

        for (int i = 0; i < 9; i++)
        {
            suma += tab[i] * Convert.ToInt32(szNIP[i].ToString());
        }

        bResult = ((suma % 11) == sumcontrol);
    }
    else return false;

    if (bResult && retFormated)
    {
        szNIP = szNIP.Insert(8, "-")
                        .Insert(6, "-")
                        .Insert(3, "-");              
    }

    return bResult;
}

Walidacja numeru Pesel w C#

Przedstawiam funkcje walidującą numer PESEL.
Funkcja sprawdza sumę kontrolną numeru, długość oraz logiczność.
Zakres sprawdzanych numerów dat w Peselu od 1800 do 2200 (w przybliżeniu)
Zwraca true - w przypadku poprawnego numeru.

public static bool ValidatePesel(ref string szPesel)
{           
byte[] tab = new byte[10] { 9, 7, 3, 1, 9, 7, 3, 1, 9, 7 };
byte[] tablicz = new byte[] {48,49,50,51,52,53,54,55,56,57};
bool bResult = false;
int suma = 0;
int sumcontrol = 0;
               
szPesel = szPesel.Trim();

if (szPesel.Length == 11)
{
    foreach (char l in szPesel)
    {
        byte b = Convert.ToByte(l);
        if (Array.IndexOf(tablicz,Convert.ToByte(l)) == -1) return false;
    }
              
    sumcontrol = Convert.ToInt32(szPesel[10].ToString());

    for (int i = 0; i < 10; i++)
    {
        suma += tab[i] * Convert.ToInt32(szPesel[i].ToString());
    }

    bResult = ((suma % 10) == sumcontrol); 
               
    if (bResult)
    {
        int rok = 0;
        int mies = 0;
        int dzien = Convert.ToInt32(szPesel[4].ToString()) * 10 + Convert.ToInt32(szPesel[5].ToString());

        if (szPesel[2] == '0' || szPesel[2] == '1')
        {
            rok = 1900;
            mies = Convert.ToInt32(szPesel[2].ToString()) * 10 + Convert.ToInt32(szPesel[3].ToString());
        }
        else if (szPesel[2] == '2' || szPesel[2] == '3')
        {
            rok = 2000;
            mies = (Convert.ToInt32(szPesel[2].ToString()) * 10 + Convert.ToInt32(szPesel[3].ToString()) - 20);
        }
        else if (szPesel[2] == '4' || szPesel[2] == '5')
        {
            rok = 2100;
            mies = (Convert.ToInt32(szPesel[2].ToString()) * 10 + Convert.ToInt32(szPesel[3].ToString()) - 40);
        }
        else if (szPesel[2] == '6' || szPesel[2] == '7')
        {
            rok = 2200;
            mies = (Convert.ToInt32(szPesel[2].ToString()) * 10 + Convert.ToInt32(szPesel[3].ToString())-60);
        }
        else if (szPesel[2] == '8' || szPesel[2] == '9')
        {
            rok = 1800;
            mies = (Convert.ToInt32(szPesel[2].ToString()) * 10 + Convert.ToInt32(szPesel[3].ToString())-80);
        }
        rok += Convert.ToInt32(szPesel[0].ToString()) * 10 + Convert.ToInt32(szPesel[1].ToString());
        String szDate = rok.ToString() + "-" + (mies < 10 ? "0" + mies.ToString() : mies.ToString()) + "-" + (dzien < 10 ? "0" + dzien.ToString() : dzien.ToString());
        DateTime dt;
        bResult = DateTime.TryParse(szDate, out dt);
    }
}
else return false;
           
return bResult;
}

Weryfikacja numeru pesel w MFC C++

Dzisiaj prezentuję funkcję weryfikującą numer Pesel.
Funkcja sprawdza zgodność numerów pesel z zakresu 1800 - 2200 roku (w przybliżeniu).
Weryfikowana jest suma kontrolna oraz logika zapisu samego numeru pesel.
Funkcja zwraca true - jeśli numer pesel jest poprawny, false jeśli błędny.

BOOL CheckPesel(CString a_Pesel)
{
    BOOL res=false;
    BOOL sumResult = false;
    int suma = 0;
    int tabSum[] = {1, 3, 7, 9, 1, 3, 7, 9, 1, 3};
    CString mDate = "";

    if(a_Pesel.GetLength() > 0)
    {
        for(int i = 0; i < 10; i++)
        {
            suma += tabSum[i] * stoi(a_Pesel[i]);
        }

        if ((suma % 10) == 0)
            sumResult = ((suma % 10) == stoi(a_Pesel[10]));
        else
            sumResult = ( (10 - (suma % 10)) == stoi(a_Pesel[10]));
    }

    if(sumResult){
        int year = 0;
        int month = 0;
        int day = stoi(a_Pesel.Mid(4,2));   

        if(a_Pesel[2] == '0' || a_Pesel[2] == '1')
        {
            year = 1900;
            month = stoi(a_Pesel[2]) * 10 + stoi(a_Pesel[3]);
        }else if (a_Pesel[2] == '2' || a_Pesel[2] == '3')
        {
            year = 2000;
            month = stoi(a_Pesel[2] - 20) * 10 + stoi(a_Pesel[3]);
        }else if (a_Pesel[2] == '4' || a_Pesel[2] == '5')
        {
            year = 2100;
            month = stoi(a_Pesel[2] - 40) * 10 + stoi(a_Pesel[3]);
        }else if (a_Pesel[2] == '6' || a_Pesel[2] == '7')
        {
            year = 2200;
            month = stoi(a_Pesel[2] - 60) * 10 + stoi(a_Pesel[3]);
        }else if (a_Pesel[2] == '8' || a_Pesel[2] == '9')
        {
            year = 1800;
            month = stoi(a_Pesel[2] - 80) * 10 + stoi(a_Pesel[3]);
        }

        year += stoi(a_Pesel[0]) * 10 + stoi(a_Pesel[1]);
        mDate = itos(year) + "-" + itos(month) + "-" + itos(day);
        COleDateTime tm;
        res=tm.ParseDateTime(mDate);

    }else{
        AfxMessageBox("Nieprawidłowy numer Pesel");
        return false;
    }

    return res;
}

Hex to Int

Prosta funkcja konwertująca Hex CString na Int
int hstoi(CString hexString)
{
   int value = 0;
   CString hex = "0123456789ABCDEF";

   hexString.MakeUpper();

   for(int i = 0; i<hexString.GetLength(); i++)
   {
        value=(value*16) + hex.Find(hexString.GetAt(i));
   }
   return value;
}

CString to Int

Prosta funkcja konwertująca CString na Int
int stoi(CString a_Str) { 
int res = INT_MIN; 
try { res = atoi( a_Str ); } 
catch(CException * e) 
{ e = e; } 
return res; }

Int to CString

Prosta funkcja zwracająca CString przy konwersji int
CString itos(const int aInt) { char buf[20]; return _itoa( aInt, buf, 10 ); }

piątek, 29 czerwca 2012

Tworzenie Upgrade do projektu Basic MSI w Install Shield 2008

    Tworzenie upgrade do projektu MSI należy zaplanować już przy tworzeniu instalatra MSI.
Jeżeli zakładamy,że nasz projekt będzie upgradowany a zazwyczaj tak jest, to musimy wykonać pewne kroki na początku. Najważniejszą rzeczą do wykonania jest ustawienie wersji produktu "Version" w "Product properties" na drzewie "General Information". Ustawiamy tutaj wersję, która będzie rozpoznawana przez instalator podczas instalowania Upgrade-u np: 1.0.0000

Tworzenie Upgrade do istniejącej instalacji MSI.
Przy tworzeniu upgrada do istniejącej paczki MSI możemy wykonać tylko Major Upgrade, do wersji Minor Upgrade potrzebny jest plik setup.exe. Dla paczek MSI (Single MSI Image) wykonujemy tylko Major Upgrade.

Krok 1. Wersja produktu 
Pierwszą rzeczą, którą powinniśmy zrobić to ustawić nową (nowszą) wersję produktu np: 1.1.0000 (Installation Information->General Information->Product Properties->Version). Zwróć uwagę na właściwość Product Code, Upgrade Code.
Właściwość Upgrade Code musi być taka sama dla całego projektu instalatora.

Krok 2. Kody produktów
Aby nasz Upgrade można było odinstalować i wrócić do poprzedniej wersji należy wygenerować nowy Product Code a także nowy Package Code w "Summary Information Stream".
Nie zmieniamy Upgrade Code!

Krok 3. Przygotowanie Instalatora do Upgrade
Na drzewie Media->Upgrades rozwijamy gałąź "Upgrade Windows Installer Setup" i dodajemy nowy "Major Upgrade Item".
W zakładce "Common" nowego Upgrade wybieramy dla której wersji produktu Upgrade będzie miał zastosowanie:
- dla każdej wcześniejszej (Any earlier version), czy może dla zakresu wersji produktu albo dla wybranej wersji.

Krok 4. Wymiana plików
W tym kroku należy wymień wszystkie pliki które mają być zaktualizowane na wersję użytą w Upgrade.
Ważne. Każdy plik musi posiadać zaszytą nowszą wersje, aby został upgradowany.

Krok 5. Ustawienia Upgrade.
Klikając na drzewo "Upgrade Windows Installer Setup" wyświetlamy właściwości instalacji Upgrade. Mamy 2 opcje do wyboru: Całkowie usunięte starej instalacji i zainstalowanie nowej lub też zainstalowanie Upgrade-u i usunięcie niepotrzebnych plików.
W większości przypadkach zalecana jest opcja pierwsza.

Krok 6. Budowanie paczki
W ostatnim kroku budujemy projekt tworząc nową paczkę MSI typu "MSI Single Image".

czwartek, 16 lutego 2012

Konwersja IList do DataSet - IList to DataSet

Poniżej funkcja konwertująca Ilist-ę do DataSet-a
Param: IList
Return: DataSet

public static DataSet ConvertToDataSet<T>(IList<T> list)
{
  if (list == null || list.Count <= 0)
  {
   return null;
  }
  DataSet ds = new DataSet();
  DataTable dt = new DataTable(typeof(T).Name);
  DataColumn column;
  DataRow row;

  System.Reflection.PropertyInfo[] myPropertyInfo = typeof(T).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);

  foreach (T t in list)
  {
   if (t == null)
   {
     continue;
   }

   row = dt.NewRow();
   for (int i = 0, j = myPropertyInfo.Length; i < j; i++)
   {
    System.Reflection.PropertyInfo pInfo = myPropertyInfo[i];
    string name = pInfo.Name;
    if (dt.Columns[name] == null)
    {
     try
    {
     column = new DataColumn(name, pInfo.PropertyType);
    }
    catch (NotSupportedException)
    {
     column = new DataColumn(name, Nullable.GetUnderlyingType(pInfo.PropertyType));
    }
    catch (Exception)
    {
     column = new DataColumn(name, typeof(object));
    }

    dt.Columns.Add(column);
    }
    row[name] = pInfo.GetValue(t, null);
   }
   dt.Rows.Add(row);
  }
 ds.Tables.Add(dt);
 return ds;
}

środa, 4 stycznia 2012

Domyślny parametr funkcji

Czasami zachodzi potrzeba ustawienie domyślnego parametru przekazywanego funkcji

Aby to wykonać należy sprawdzić czy parametr został zdefiniowany przy przekazaniu np:

function ShowSelected(bCategory)
{
   bCategory = typeof(bCategory) != 'undefined' ? bCategory : true;
...
}

w tym przypadku domyślny parametr jest typu bool i jeżeli nie został przekazany to domyślną wartością jest true;