Vítejte na blog.vyvojar.cz Přihlásit | Registrovat | Pomoc

Jak na výběr informačního systému

K napsání tohoto povídání mě přivedl příspěvek z 31.3.2009 pod článkem Čárové kódy na webu: Základy, zní: "Chtela bych zavest v logistickem centru prijem a vydej zbozi pres carove kody. Muzete mi poradit, jak postupovat." Protože jsem se v minulosti s podobnou otázkou setkal, pokusím se odpovědět.

Jednoduchá odpověď je: Vy se do toho nepouštějte. Může se totiž stát, že si pořídíte krásný a drahý systém, který bude dělat přesně to co má, ale nebude to to co potřebujete aby dělal. Představte si, že si jdete koupit auto. Prodejce vám nabídne krásné, červené a rychlé auto. Doplní to mnoha fotografiemi a reklamními letáky. Zaplatíte zálohu a za 3 měsíce vám ho dovezou. Je krásné, rychlé a červené. Je to Ferrari, splňuje vše co prodejce říkal, ALE vy máte tři děti a potřebujete auto na to, aby jste je vozila do školy. To ale v krásném sporťáku nepůjde. Chyba se stala hned na začátku, nedomluvili jste se s prodejce na co auto vlastně potřebujete a prodejce zrovna chtěl prodat nějaké to Ferrari. U auta se vám to asi nestane, ale co u informačního systému?

Pozn.: Ano, je to informační systém, nebo jeho část.

Jak vybrat dobře?

Nejlepší by bylo, kdyby zákazník měl špičkové znalosti v oboru informačních systémů, přehled v jejich slabinách a možnostech. Takový ale není. Jsou v zásadě tři možnosti:

  1. Najdu a zaměstnám takového člověka
  2. Najdu konzultantskou firmu, která má takového člověka a té výběr svěřím
  3. Najdu firmu, která to udělá celé

1. Najdu a zaměstnám takového člověka

Najít přímo člověka by bylo fajn, chvíli se ve firmě bude rozkoukávat, pozná její potřeby a potom je bude schopen sdělit dál a ohlídat, že systém bude potřebám firmy vyhovovat. Jenže co s ním po dokončení projektu.

2. Najdu konzultantskou firmu, která má takového člověka a té výběr svěřím

K těmhle firmám mám averzi danou zkušeností. Pokud firma zároveň není realizítorem, budou jí pravděpodobně chybět některé zkušenosti. Není schopna předvést, že dotáhne věci do konce. Její práci nelze zhodnotit, pokud nepočítám dojem.

Jednu takovou jsem potkal dokonce 2x. Na první zakázce byla během výběrového řízení zákazníkem odstraněna. Nedoděla ani výběr, přesto má tuto zakázku ve svých referencích, dokonce napsanou tak, že to vypadá, že systém realizovala.

Ale byl by to ideální stav, bohužel jsem přesvědčen, že výběr takovéto firmy je mnohem těžší a snáze se naletí na reklamní letáky a slogany. Ale pro případný výběr platí stejné věci jako pro třetí možnost.

3. Výběr firmy udělám sám

Ale jak, když nic nevím. Nejlépe je začít tím, že se pokusím formalizovat co nejpřesněji své požadavky. S těmi potom oslovím zájemce o realizaci zakázky.

Oslovené firmy buď podají rovnou nabídku nebo budou chtít znát doplňující informace. Pokud podají rovnou nabídku, znamená to, že jsem sepsal zadání naprosto přesně nebo je nabídka jen podivný odhad. Z otázek firem se můžeme poučit a udělat si obrázek jak bude firma postupovat při další práci. Jestli se bude ptát na náš názor a naše potřeby nebo nám bude vnucovat svoje.

Po obdržení všech nabídek bych vyřadil ty, kteří se neptali, příliš levné i příliš drahé. Mohlo se stát, že jsem během této fáze zjistil, že potřebuji něco trochu jiného. Potom můžu vybrané firmy požádat o přepracování nabídky a zapracování změn.

Může být výhodné si vymínit, že vybraná firma nejdříve udělá důkladnou analýzu a potom případně nabídku upraví. Při této analýze totiž můžeme přijít na další věci. A mám stále možnost zjistit, že mě dodavatel tlačí někam, kde nechci být. A nebude to stát celé peníze na projekt.

První zadání

Nejprve je potřeba pokusit se najít všechny osoby, které s předpokládaným projektem přijdou do styku. Předložit jim předpoklad a zjistit jejich případné požadavky.

Pokud jsme součástí mezinárodní korporace, tak je dobré vědět která omezení nebo výhody mi z toho plynou. Může se jednat třeba o ceny některých komponent, požadavky a podobně.

Abych nebyl obecný, tak tady jsou body které je potřeba připravit, když ne na první zadání, tak určitě před začátkem projektu:

  • Zajistit aby všechno co prochází logistickým centrem mělo čárový kód ve tvaru jaký je potřeba. Tzn. třeba nejen EAN13, ale všechny informace, inspirace třeba na www.gs1cz.org/system-gs1/logisticke-informace-ai. Nepodcenit, může to trvat dlouho.
  • Na které další systémy bude nový systém navázaný. Může se jednat např. o systém odměňování skladníků za odbavené kamiony, docházkový systém, ERP (objednávky, příjemky/výdejky).
  • Jaké výstupy bude systém mít. Třeba výše zmíněný způsob hodnocení skladníků, nebo výstup o čekací době kamionu na naložení/vyložení (potom musí být kousek systému i na vrátnici).
  • Forma prezentace dat (intranet, integrace do stávajícího systému manažerských sestav)
  • Rozdělení budoucích uživatelů do skupin - rolí (skladník, směnový vedoucí, ...)
  • Kolik lidí bude systém používat a jak. Tohle bude mít vliv na počet koncových zařízení nebo licence.
  • Jak dlouho je třeba archivovat data ze systému a jaká. Např. pokud se informace dodávají do ERP, není potřeba informace skladovat příliš dlouho (rok stačí).
  • Jazyk systému (multijazyčnost).
  • Seznam preferovaného/požadovaného hardware a software. Pokud již máme nějaké čtečky ve firmě, bude výhodné mít stejné. Software by mělo být naopak schopno spravovat i naše IT oddělení.
  • Jaké další předpisy platí pro naše prostředí.

Co čekat

  • Projekt bude trvat nějakou dobu a bude vyžadovat naši spolupráci.
  • Projekt bude něco stát, zpravidla je dobré čekat navýšení ceny proti nabídce tak 10 - 15 %
  • Nebude to jednoduché
Posted by arci | 6 Comments
Vedeno pod:

Počítače v průmyslové praxi podruhé

Ve svém minulém povídání jsem uvedl pár postřehů k využití počítačů v průmyslovém prostředí. Rád bych doplnil radu:

Pokud nevíte o co jde, nepouštějte se do toho!.

Příliš mnoho projektů končí neúspěchem jen proto, že se programátor setká s reálným světem. V téhle úvaze se pokusím nastínit některá úskalí. Lidé z průmyslového prostředí jsou obecně méně tolerantní k výpadkům počítače než v kanceláři. Prostě si ještě nezvykli.

Mechanické provedení

Při návrhu aplikace a hlavně použitého hardware je nutné vzít v úvahu prostředí a zvyky lidí. To co projde v kanceláři, je v takovémto prostředí nemožné. Lidé ve výrobě netolerují pády a restarty. A pozor, necháte-li někde neobsazenou zásuvku, je jen otázka času kdy se v ní objeví vrtačka.

Představy IT firem o takovémto prostředí jsou často velmi zkreslené. Nedávno jsme se nechali zlákat a od dodavatele serverů jsme objednali i rack, s tím nás produktový manažer ubezpečoval, že se jedná o provedení do lehkého průmyslu. Přišel rám, bez bočnic a dveře byly z děrovaného plechu. Asi provedení lehký průmysl s klimatizovanou serverovnou.

V reakci na minulé povídání je pár fotek jak lze využít panelové PC a schovat jej do bedny, jinak je lépe se poohlédnout po výrobcích elektrických rozvaděčů, z nichž někteří nabízejí docela pěkné. V každém případě se podívat na krytí IP dle ČSN EN 60529.

Přikládám odkaz na něco veselého na téma krytí IP. Mimochodem v článku uváděná zkratka nn, znamená nízké napětí, což je 50V až 1000V. A to za jistých okolností může zabít. Více třeba zde.

Software

V operačním systému je potřeba nastavit, aby se vše provádělo automaticky a bez zásahu uživatele a nejlépe i bez jakékoliv interakce. To se týká automatických aktualizací (ty je lépe vypnout a dělat ručně), antivirů a podobně. Hodně pomůže pokud je možno oddělit síť pro zařízení ve výrobě od kancelářské, nejlépe tak, že server má 2 síťové karty. Takhle se podařilo přežít i opravdu masivní útok červa, kdy z kancelářských počítačů se odstraňoval několik dní. Ono totiž občas jsou tyto sítě korporátní a to znamená několik časových pásem a spoustu počítačů.

Speciální harware a periferie

Tím myslím všechno co se k počítači ve výrobě připojuje a nemáte to zrovna na stole. Jedná se o čtečky čárového kódu a identifikačních čipů, speciální tiskárny, různé displeje (jako jsou pokladní), váhy, menší či větší stroje nebo celé výrobní linky a technologie. Čím je inteligentnější tím tužší odpor klade vůči jakémukoliv ovlivňování své funkce ze strany jakéhokoliv jiného programu.

Lidé

Nebudou rozumět vám a vy nebude rozumět jim. Každý výrobní závod má naprosto jinou terminologii a to někdy i v rámci jedné korporace. Chvíli trvá než se to naučíte. Namátkou, víte co je:

  • ajpina
  • šuskanál
  • roubík
  • tambor
  • džambo / jumbo

Odradil jsem vás? Vlastně jsem to chtěl. Pokud ne a chcete něco dalšího, napište si co.

Posted by arci | 0 Comments
Vedeno pod:

Počítače v průmyslové praxi

K napsání těchto řádek mě inspiroval jeden z komentářů na článek http://www.aspnet.cz/Articles/210-ovladani-led-panelu-sigma-asc-105.aspx. Je to jen pár postřehů k využití počítačů v průmyslové praxi.

Postřeh první (možná ne nejdůležitější)

Vezmete-li obyčejné PC a umístíte-li jej ve výrobě, odejde během prvního týdne. Většinou přes vrátnici. Takové PC ve výrobě je nutno přivázat na pořádné vodítko nebo řetěz, nejlepší je umístit jej do klece, to jeho choutky na odcházení VELMI sníží. V kleci PC vydrží cca 2 roky. Průběžně je potřeba kontrolovat funkci větráků (stačí 2 x ročně). Potom je nutné počítat s tím, že nevydrží pevný disk, případně základní deska. Přeci jen to není konstruované na provoz 24 hodin denně. CRT monitor má vypálené znaky tak po 2 až 3 měsících, ale nejméně rok se s tím dá žít. Existují varianty počítačů bez točivých částí, ale ne vždy je možné je použít.

Postřech druhý (ergonomie)

Ergonomie ovládání je věc subjektivní. Kromě toho, že je potřeba počítat s lidmi nosícími brýle na blízko i na dálku, vyskytnou se i další anomálie. Potkal jsem se s člověkem barvoslepým, pro kterého bylo nutné vymyslet barevné schéma tak, abychom se vyhnuli barvě kterou nevidí. Umístění monitoru, případně klávesnice je také potřeba pečlivě rozvrhnout.  Kromě toho, že kolem strojů se nevyskytuje mnoho vhodných stolů a vše se musí "věšet", tak musíme myslet na různou výšku operátorů. Bývá to od 160 cm do 2 m, ale opět jsou vyjímky.

Postřeh třetí (počítačová gramotnost)

I když se bude zdát, že pomocný dělník není schopen zvládnou ani jednoduše navrženou obrazovku, tak na nahrání porna nebo hry do počítače je schopný dost. Bohužel některé programy právě pro výrobní sektor potřebují poměrně vysoká práva v operačním systému.

Postřeh čtvrtý (luddismus)

Průmyslová revoluce není mrtvá. Nejnižší forma odporu proti závádění strojů, jejich rozbíjením, je stále účinná. Prostě ten monitor praskl sám, tady kladivo nikdo nemá.

Postřeh pátý (cena)

Ne vždy je nejlevnější věc ta najlepší. Například nejlevnější čtečka čárového kódu stojí cca. 1000 Kč. V dělnické ruce vydrží tak týden. A to přesto, že se nejedná o zlý úmysl. Jeden dodavatel na předváděčce ukazoval zatloukání hřebíků s novým modelem. Za půl roku jsem mu vrátil ten úžasný model umlácený (chybělo sklíčko, tlačítko někdo promáčkl a kryt měl škrábanců požehnaně, v jednom místě byl obroušený skoro o 1 mm). Zjednodušeně řečeno je vždy potřeba volit mezi cenou a "výdrží" a počítat s výměnou.

Postřeh šestý (stáří)

Životnost mechanických částí je výrazně vyšší než elektrických a elektronických. Na internetu se dají najít prodeje strojů i přes 50 let starých a to ne do muzea, ale do výroby. Poslední počítač s Windows 3.11 jsem nahrazoval kolem roku 2005 a to jen kvůli možnosti, že by mohl vysadit a nebyl by náhradní (asi 2 měsíce jsme sháněli síťovou kartu 3C509, kterých svého času byly hromady).

Závěr (Murphyho zákony)

Stejně to není všechno a na něco jste zapomněli! Vynalézavost lidí nezná hranic. A náhoda je ...

Posted by arci | 3 Comments
Vedeno pod:

Team Build a automatické verzování

Simple description of one way how to setup automatic versioning and Team Build (Team Foundation Server 2005), including WiX

Krátký popis jak se dá nastavit automatické verzování na Team Build Serveru (Team Foundation Server 2002), včetně změny verze pro WiX.

Popis je rozdělen do několika částí popisující jednotlivé kroky. Není je však potřeba provádět přesně v popsaném pořadí, některé lze i vynechat. V popisu je zdůvodněno proč se co dělá, ale není to úplný návod.

Všechny projekty v solution mají vložen odkaz na soubor pojmenovaný SolutionVersion.cs, který je součástí solution a je při automatickém sestavení vždy vytvořen s novým číslem verze. Obsahuje tedy jen řádek s AssemblyVersion atributem.

Při automatickém sestavení se mění číslo sestavení (Major.Minor.Build.Revision), přičemž číslo revize je nastaveno na 0. Pro vývojáře je v TFS repozitory je číslo revize nahrazeno znakem '*', takže vývojářské verze se liší od produkční. Informace o verzi jsou ukládány do souboru version.txt, který je součástí solution. V něm je možné měnit čísla verzí Major, Minor ručně a při dalším automatickém sestavení budou použity.

Jednotlivá automatická sestavení jsou pojmenována ve tvaru <jméno>_<verze>, místo výchozího pojmenování pomocí datumů.

Protože používám WiX pro vytváření instalátorů, tak je popsána i možnost verzování WiX projektů. A výsledkem celého snažení je pouze již hotový MSI balíček.

Co je potřeba

Celé je to postaveno tak, aby vývojářské PC nepotřebovalo žádné speciální nastavení. Takže všechno musí být na stroji, který provádí samotný build. Vlastně stačí jenom MSBuild Community Tasks.

A samozřejmě vytvořený Team Build. Na jeho jméně nezáleží, protože skoro všechno je vytvořeno variabilně. Co není, na to zvlášť upozorním.

Předpokládá se, že v adresáři solution jsou sobory version.txt a SolutionVersion.cs. Dále, že solution obsahuje WiX projekt s názvem "Setup", který obsahuje soubor version.template pro vytvoření souboru Version.wxi s verzí pro MSI balíček.

Jak to funguje

V před vlastním sestavením se stáhne z TFS repozitory soubor s poslední verzí. Tato verze se zvedne o 1. Následně se vytvoří soubory s verzemi pro jednotlivé projekty (cs soubor pro projekty v C# a wxi soubor, který je vložen do souboru pro WiX, ze kterého je vytvořen MSI balíček.

Po dokočení kompilací je v souboru cs provedena náhrada čísla revize a všechny vytvořené a změněné verzovací soubory jsou vráceny do TFS repozitory. Tím je zajištěno že všichni vývojáři budou mít nová čísla verzí.

Krok 1: Editace TFSBuild.proj

Celé nastavení automatického buildu je v souboru TFSBuild.proj, uloženém na serveru v adresáři TeamBuildTypes\<jméno buildu>. Tento soubor je vlastně msbuild projektový soubor, který build server vykoná.

Tento soubor je potřeba nejprve pomocí příkazu "Get latest version" stáhnout na lokální disk a pomocí "Check-out" uvolnit pro editaci a otevřít, klidně rovnou ve Visual Studiu, ale stačí i notepad.

Krok 2: Import MSBuild  Community Tasks

Aby fungovali přidané msbuild tasky, je nutné je do projektového souboru naimportovat. Najdeme tedy řádek. kde je proveden import Team Build tasků (najít řádek na kterém je tag "Import") a za něj přidáme nový:

  <Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />

Krok 3: Cesta k tf.exe

Protože budeme potřebovat tahat soubory z Team Serveru a žádná rozumná cesta v msbuildu není, tak si pomůžeme spouštěním řádkového příkazu tf.exe. Cestu k tomuto příkazu zadáme někam mezi PropertyGroup:

<!-- TF.exe -->
<TF>&quot;c:\Program Files\Microsoft Visual Studio 8\Common7\IDE\TF.exe&quot;</TF>

Krok 4: Pojmenování sestavení

Na začátku cyklu sestavení se vytváří jméno sestavení. Toho je využito a nejen, že je jméno změněno na více popisné, než je výchozí, tak jsou také naplněny proměnné verzí. MSBuild target se jmenuje BuildNumberOverrideTarget.

<Target Name="BuildNumberOverrideTarget" Condition="'$(IsDesktopBuild)'!='true'">
 
    <MakeDir
        Directories="$(SolutionRoot)"
        Condition="!Exists('$(SolutionRoot)')" />
 
    <!-- Delete the workspace left by previous run -->
    <DeleteWorkspaceTask
        TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
        Name="$(WorkspaceName)" />
 
    <!-- Create the workspace enlistment -->
    <CreateWorkspaceTask
        TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
        MappingFile="$(WorkspaceMappingFile)"
        LocalPath="$(SolutionRoot)"
        Name="$(WorkspaceName)"
        TeamProject="$(TeamProject)" />
 
    <!-- Get the latest version source from the workspace -->
    <Get
        Condition=" '$(SkipGet)'!='true' "
        Workspace="$(WorkspaceName)"
        Recursive="$(RecursiveGet)"
        FileSpec="$(SolutionRoot)\Source\version.txt"
        Force="$(ForceGet)" />
 
    <!-- Workaround: Version task must have read/write access -->
    <Attrib Files="$(SolutionRoot)\Source\version.txt" ReadOnly="false" />
 
    <!-- Get setup build number -->
    <Version VersionFile="$(SolutionRoot)\Source\version.txt" 
        BuildType="Increment" RevisionType="BuildIncrement">
      <Output TaskParameter="Major" PropertyName="BuildVersionMajor" />
      <Output TaskParameter="Minor" PropertyName="BuildVersionMinor" />
      <Output TaskParameter="Build" PropertyName="BuildVersionBuild" />
      <Output TaskParameter="Revision" PropertyName="BuildVersionRevision" />
    </Version>
 
    <!-- Create BuildNumber property value, 
         if you want "better" default naming convetions
         you may delete it -->
    <CreateProperty Value="$(BuildType)_$(BuildVersionMajor).$(BuildVersionMinor).$(BuildVersionBuild).$(BuildVersionRevision)" >
      <Output TaskParameter="Value" PropertyName="BuildNumber" />
    </CreateProperty>
 
</Target>

Krok 5: Vytváření verzovacích souborů

Všechny změny v souborech vytvořených v BuildNumberOverrideTarget jsou přepsány v okamžiku kdy msbuild vytáhne kompletní zdrojové kódy pro překlad. Hned poté vytvoříme soubory s verzemi. SolutionVersion.cs se vytváří 2x. Nejprve s '*' místo revize a hned se všechno uloží zpět do TFS repozitory. Potom se revize nastaví na 0 se kterou je provedena kompilace.

<Target Name="AfterGet" Condition="'$(IsDesktopBuild)'!='true'">
 
    <!-- Check out version files -->
    <Exec Command="$(TF) checkout &quot;$(SolutionRoot)\Source\version.txt&quot; &quot;$(SolutionRoot)\Source\Setup\version.wxi&quot; &quot;$(SolutionRoot)\Source\SolutionVersion.cs&quot;" WorkingDirectory="$(SolutionRoot)" />
 
    <!-- Set file setup build number -->
    <WriteLinesToFile
       File="$(SolutionRoot)\Source\version.txt"
       Lines="$(BuildVersionMajor).$(BuildVersionMinor).$(BuildVersionBuild).$(BuildVersionRevision)"
       Overwrite="true" />
 
    <!-- Create tokens for wxi file replace -->
    <CreateItem Include="Major" AdditionalMetadata="ReplacementValue=$(BuildVersionMajor)">
      <Output TaskParameter="Include" ItemName="TokenMajor"/>
    </CreateItem>
    <CreateItem Include="Minor" AdditionalMetadata="ReplacementValue=$(BuildVersionMinor)">
     <Output TaskParameter="Include" ItemName="TokenMinor"/>
    </CreateItem>
    <CreateItem Include="Build" AdditionalMetadata="ReplacementValue=$(BuildVersionBuild)">
      <Output TaskParameter="Include" ItemName="TokenBuild"/>
    </CreateItem>
    <CreateItem Include="Revision" AdditionalMetadata="ReplacementValue=$(BuildVersionRevision)">
      <Output TaskParameter="Include" ItemName="TokenRevision"/>
    </CreateItem>
 
    <CreateItem Include="@(TokenMajor);@(TokenMinor);@(TokenBuild);@(TokenRevision)">
      <Output TaskParameter="Include" ItemName="Tokens"/>
    </CreateItem>
 
    <!-- Replace tokens and create version.wxi -->
    <TemplateFile Template="$(SolutionRoot)\Source\Setup\Version.template" 
        OutputFilename="$(SolutionRoot)\Source\Setup\Version.wxi" 
        Tokens="@(Tokens)" />
 
    <!-- Solution version file, change CodeLanguage for VB -->
    <AssemblyInfo CodeLanguage="CS"
        OutputFile="$(SolutionRoot)\Source\SolutionVersion.cs"
        AssemblyVersion="$(BuildVersionMajor).$(BuildVersionMinor).$(BuildVersionBuild).*" />
 
    <!-- Check in version files -->
    <Exec Command="$(TF) checkin &quot;$(SolutionRoot)\Source\version.txt&quot;  &quot;$(SolutionRoot)\Source\Setup\version.wxi&quot; /comment:&quot;Setup version $(BuildVersionMajor).$(BuildVersionMinor).$(BuildVersionBuild)&quot; &quot;$(SolutionRoot)\Source\SolutionVersion.cs&quot; /noprompt /override:BUILDSERVER " WorkingDirectory="$(SolutionRoot)" />
 
    <!-- Workaround: Version task must have read/write access -->
    <Attrib Files="$(SolutionRoot)\Source\SolutionVersion.cs" 
        ReadOnly="false" />
    <!-- Now generate version file with Revision = 0 -->
    <AssemblyInfo CodeLanguage="CS"
        OutputFile="$(SolutionRoot)\Source\SolutionVersion.cs"
        AssemblyVersion="$(BuildVersionMajor).$(BuildVersionMinor).$(BuildVersionBuild).$(BuildVersionRevision)"
        AssemblyFileVersion="$(BuildVersionMajor).$(BuildVersionMinor).$(BuildVersionBuild).$(BuildVersionRevision)" />
 
</Target>

Krok 6: Zabalení výsledků kompilace

Nepovinný krok, pouze pro jistotu zabalím všechny *.dll, *.pdb do zipu a smažu je, potřebujeme jenom MSI balíček. Vlastně je ani balit nemusím a rovnou je smazat. Build server potom všechno přesune do cílového adresáře. A to je vlastně vše.

<Target Name="PackageBinaries"
    Condition="'$(IsDesktopBuild)'!='true'">
 
    <!-- Zip and delete assemblies (without MSI) -->
    <CreateItem Include="$(OutDir)\**\*.*" Exclude="$(OutDir)\**\*.msi">
      <Output ItemName="FilesToDelete" TaskParameter="Include" />
    </CreateItem>
 
    <!-- package (you may remove this line and simply delete files) ... -->
    <Zip Files="@(FilesToDelete)" WorkingDirectory="$(OutDir)" 
        ZipFileName="$(OutDir)\$(BuildNumber).zip" />
 
    <!-- ... and delete -->
    <Delete Files="@(FilesToDelete)" />
 
</Target>

Soubory

Protože všechny zmíněné soubory musí existovat, je nutno je vytvořit:

  • version.txt
1.0.0.0
  • SolutionVersion.cs
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
 
[assembly: AssemblyVersion("1.0.0.*")]
  • version.template
<?xml version="1.0" encoding="utf-8"?>
<Include>
    <?define ProductMajor = "${Major}" ?>
    <?define ProductMinor = "${Minor}" ?>
    <?define ProductBuild = "${Build}" ?>
    <?define ProductRevision = "${Revision}" ?>
    <?define ProductVersion = "${Major}.${Minor}.${Build}" ?>
</Include>
  • version.wxi
<?xml version="1.0" encoding="utf-8"?>
<Include>
    <?define ProductMajor = "1" ?>
    <?define ProductMinor = "0" ?>
    <?define ProductBuild = "0" ?>
    <?define ProductRevision = "0" ?>
    <?define ProductVersion = "1.0.0" ?>
</Include>

Trocha WiXu na závěr

Jen malá ukázka jak potom vypadá wxs soubor. Je to jenom začátek ...

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
 
    <?include Version.wxi ?>
 
    <Product Id="*" Name="Program $(var.ProductVersion)" 
             Language="1033"
            Version="$(var.ProductVersion)" Manufacturer="Me"
            UpgradeCode="{AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAA0}">
        <Package InstallerVersion="200" Compressed="yes" />
 
        <Upgrade Id='{AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAA1}'>
            <UpgradeVersion OnlyDetect='yes' Property='PATCHFOUND'
              Minimum='$(var.ProductVersion)' IncludeMinimum='yes' 
              Maximum='$(var.ProductVersion)' IncludeMaximum='yes' />
            <UpgradeVersion OnlyDetect='yes' Property='NEWERFOUND'
              Minimum='$(var.ProductVersion)' IncludeMinimum='yes' />
            <UpgradeVersion OnlyDetect='no' Property='UPGRADE'
              Maximum='$(var.ProductVersion)' IncludeMinimum='no'/>
        </Upgrade>
...atd
Posted by arci | 2 Comments
Vedeno pod: ,

Náhrada SQL Server Agent v Express edici

 

SQL Agent - A Job Scheduler Framework je služba umožňující nahradit chybějícího agenta. Jediná nevýhoda je (nebo je to výhoda?), že jednotlivé úlohy jsou psány jako pluginy v C# nebo VB.Net 2005.

Poznámka: Tohle jsem už jednou psal, ale příspěvek odešel do věčných a nekonečných plání velkého prapůvodního disku.

Posted by arci | 0 Comments
Vedeno pod:

Nikdy nedělej nic na poslední chvíli.

Když už všichni píšou o blbostech cizích, tak já něco o té vlastní.

V pátek jsem poslal do několika zařízení aktualizaci. Bylo po pracovní době a tak už nebyl čas otestovat výsledek. Program je samozřejmě v pořádku, bohužel jsem zařízením odeslal špatnou konfiguraci, která je připojila na testovací server místo produkčního. A protože neštěstí nechodí samo, tak lidi přišli do práce o víkendu, aby si něco dodělali.

Posted by arci | 0 Comments
Vedeno pod:

Pár poznámek pro Compact Framework 2.0

Design-time support

Jak přidat design-time support a zbavit se prázdného obdélníku v designeru při vytvážření vlastních ovládacích prvků je popsáno v článku "Compact Framework Custom Control Design Support in Visual Studio 2005"

Užitečné odkazy na ovládací prvky

Smart device Framework (SDF) od OpenNETCF je snad základ.

Bindable ListView for .NetCF je užitečná věcička, která může v některých případech nahradit i DataGrid.

Chyba genasm

Při použití výše uvedeného postupu je možné dostat následující chybovou hlášku:

genasm.exe(1) : error There was an error finalizing type. 
Type 'MyNameSpace.MyClass, MyLibrary, Version=1.0.0.0, 
Culture=neutral, PublicKeyToken=null' was loaded 
in the ReflectionOnly context but the AssemblyBuilder 
was not created as AssemblyBuilderAccess.ReflectionOnly.

případně obměnu (liší se jedním slovem):

genasm.exe(1) : error There was an error initializing type. 
Type 'MyNameSpace.MyClass, MyLibrary, Version=1.0.0.0, 
Culture=neutral, PublicKeyToken=null' was loaded 
in the ReflectionOnly context but the AssemblyBuilder 
was not created as AssemblyBuilderAccess.ReflectionOnly.

Popis důvodů a řešení je tady. Dělá to spojení design-time supportu a public potomek generického listu. Ale zjistil jsem, že je lepší tyhle dvě věci v jedné assembly vůbec nemíchat, nebo rovnou použít workaround.

Posted by arci | 0 Comments
Vedeno pod: ,

Registrace komponent do GAC při instalaci

Před nějakou dobou jsem řešil, jak při instalaci zaregistrovat komponenty do GAC místo ponechání u nainstalované aplikace. Napadlo mě komponenty zabalit do archivu zipem a při instalaci je pomocí Custom Install Action rozbalit do dočasného umístění, zaregistrovat a smazat. Na disku po dokončení instalace zůstane jen zabalený archiv.

Pro rozbalení zip archivu je použita knihovna #ziplib, jejíž licence umožňuje použití i v komerčních projektech. Navíc, protože jsem potřeboval instalovat lokalizace, umožňuje archiv jednu úroveň adresářů, kde se předpokládají lokalizované resource assembly.

Všechno platí pro Visual Studio 2003.

Krok 1

K vytvoření vlastní instalační akce stačí vytvořit potomka třídy System.Configuration.Install.Installer a nastavit atribut RunInstallerAttribute na true, jinak nebude akce spuštěna.

[RunInstaller(true)]
public class CustomInstaller : Installer
{
  public CustomInstaller() : base()
  {		
  }

  /// 
  /// On install action
  /// 
  /// 
  public override void Install(System.Collections.IDictionary stateSaver)
  {
    base.Install(stateSaver);
    // Vlastní instalační akce
  }

  /// 
  /// On uninstall action
  /// 
  /// 
  public override void Uninstall(System.Collections.IDictionary savedState)
  {
    base.Uninstall(savedState);
    // Similar as instal, use p.GacRemove(...);
  }
}

Krok 2

Manipulace s archivem zip pomocí #ziplib je jednoduchá. Stačí použít třídu FastZip.

  FastZip zFile = new FastZip();
  zFile.ExtractZip(zipFileName, tempPath, FastZip.Overwrite.Always, null, "", "");				

Krok 3

K registrace assembly do GAL je možné použít řádkovou utilitu gacutil.exe nebo třídu Publish z namespace System.EnterpriseServices.Internal.

  Publish p = new Publish();
  p.GacInstall(fileName);

Krok 4

Přiložit do instalace assembly, ve které je vlastní akce a soubor s archivem zip, samozřejmě i ICSharpCode.SharpZipLib.dll. Třeba do zvláštního adresáře.

Takhle to vypadá ve studiu

Krok 5

Nastavit spouštění akce při událostech instalace.

Takhle to vypadá ve studiu

A je to hotovo ...

Zdrojové soubory ukázkové aplikace najdete tady. Instalátor do GAC zaregistruje ICSharpCode.SharpZipLib.dll, která je obsažena v archivu InstallGAC.zip

Postupem doby mě napadla ještě další vylepšení

  1. Možnost zadat jméno archivu do Setup projektu.
  2. Možnost instalovat komponenty z více archivů.
  3. Použít jiný formát, třeba CAB, pro který není nutná další knihovna.
Posted by arci | 0 Comments

String resource generator pro VS2003

Jen jako poznámku, pro ty co ještě používají VS2003 a líbí se jim myšlenka generování resources lepším způsobem než ručním psaním např. podobně jako to dělá Microsoft Enterprise Library, tak tady to je.

Posted by arci | 0 Comments
Vedeno pod:

Ukládání stromové struktury do SQL

Na http://www.codeproject.com/cs/database/tree_olap.asp je pěkný popis jak ukládat stromovou strukturu do SQL databáze a efektivně v ní hledat podstrom. Těch 32 úrovní zmíněných v začátku je potom v textu překonáno.

Posted by arci | 8 Comments
Vedeno pod:

Přímý zápis dat na tiskárnu

Nedávno se na Codeproject objevil program pro přímý tisk na tiskárnách Zebra, založený na příkladu ze supportu. Program používá přímý tisk na LPT port nebo UNC cestu.

Možná je lepší použít přímo print spooler. Ukázka použití je zde. VB.Net verze je tady. Výhodou je použití názvu tiskárny.

Mimochodem v C je to tady.

Posted by arci | 0 Comments
Vedeno pod:

Malý program na vylepšení schránky

Už dlouho používám malý program, který umí obsah schránky z formátovaného textu převést na prostý a ještě navíc vložit do aktuálního okna. Dost usnadní kopírování mezi dokumenty, kdy není žádoucí kopírovat formátování. Jmenuje se PureText a jeho stránka je tady.
Posted by arci | 0 Comments
Vedeno pod:

Priorita operátorů

Při psaní nového uživatelského rozhraní pro systém, který mimo jiné má v sobě správu uživatelů jsem musel zachovat ukládání hesel do databáze. Původní aplikace je napsaná v Delphi. Hesla jsou uložena v zakódované formě. Funkce na zakódování hesla v Delphi je celkem jednoduchá:
function cryptPassword(text: String; id: Integer): String;
var
  n, c: Integer;
begin
  text := Trim(text);
  if text <> '123456' then begin
    c := Length(text);
    text := text + 'qwer0yasdf*zxcv=2Z/8';
    for n := 1 to 20 do
      id := id + Byte(text[n]);
    for n := 1 to 20 do begin
      c := c + (Byte(text[n]) XOR ($c5 + n + id)) AND $7f;
      while NOT (((c >= $30) AND (c <= $39)) OR ((c >= $41) AND (c <= $5a)) OR ((c >= $61) AND (c <= $7a))) do begin
        c := (c + 20) MOD $80;
      end;
      text[n] := Char(c);
    end;
    Delete(text, 21, 255);
  end;
  result := text;
end;
Stačí zadat heslo a id uživatele a dostaneme heslo. Přepis do C# ale zabral více než půl dne. První verze byla hotová asi za pět minut, ale když jsem jí zadal jako parametr heslo 0000 a id 1 dostal jsem OSD6hCcSJ7sTS94h3f58 bohužel původní funkce vrátila OSXr8k3gr7sTS94h3f58. Začátek a konec stejný, ale střední část se liší. Po několikahodinovém zkoumání jednotlivých bitů a rozepisování sloupců čísel na papír jsem našel původce zla:
c := c + (Byte(text[n]) XOR ($c5 + n + id)) AND $7f;
V pascalu je totiž operátor XOR na stejné úrovni jako AND na rozdíl od jazyků odvozených od C kde je AND před XOR. Stačilo tedy správně použít závorku a výsledek je:
private string CryptPassword( int id, string text)
{
  int n;
  int c;
  string cryptedText = "";
  text = text.Trim();
  if (text != "123456")
  {
    c = text.Length;
    text = text + "qwer0yasdf*zxcv=2Z/8";
    for (n = 0; n < 20; n++)
    {
      id = id + Convert.ToByte(text[n]);
    }
    for (n = 0; n < 20; n++)
    {
      // originál má C5, ale n je číslováno od 1, takže je nutné jedničku přičíst
      c = c + ((Convert.ToByte(text[n]) ^ (0xC6 + n + id)) & 0x7F);
      while (!(((c >= 0x30) && (c <= 0x39)) || ((c >= 0x41) && (c <= 0x5A)) || ((c >= 0x61) && (c <= 0x7A))))
      {      
        c = (c + 20) % 0x80;
      } 
      cryptedText = cryptedText + Convert.ToChar(c);
    }        
    return cryptedText.Substring(0, 20);
  }
  else
  {
    return text;
  }
}
Posted by arci | 1 Comments
Vedeno pod:

Implementace metody Dispose(bool disposing) v potomcích Component

Nedávno jsem si stáhnul jednu komponentu z internetu. Metoda Dispose bool disposing) však vypadala takhle:
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing ) {
 if( disposing ) {
  if( components != null )
   components.Dispose();
 }
 base.Dispose( disposing );
 numeralBrush.Dispose();
 outlineBrush.Dispose();
 outlinePen.Dispose();
 meterlinePen.Dispose();
}
Asi by se líbila těm, kteří mají rádi úsporné formátování (viz. diskuze). Implemetace však není nejlepší. Když se nebudeme spoléhat na směšné torzo komentáře, které je ve vzoru, a najdeme si nápovědu zjistíme, že trefně nazvaný parametr disposing určuje, zda se mají uvolnit všechny nebo pouze neřízené zdroje. Pohledem do implemetace třídy System.ComponentModel.Component lze zjistit odkud se metoda Dispose(bool dispoing) volá. Jsou to public metody Dispose() a Finalize():
public void Dispose()
{
      this.Dispose(true);
      GC.SuppressFinalize(this);
}

~Component()
{
      this.Dispose(false);
}
A Dispose(bool disposing) je definována jako protected virtual. To znamená, že jakákoliv odvozená třída bude při expilicitním volání Dispose() uvolňovat vše a zamezí následné, teď už zbytečné, finalizaci.

Navíc je dobré když si komponenta pamatuje, že již jednou byla uvolněna a volání metody base.Dispose(disposing) dát na konec. Nutno podotknout, že uvedený kód není bezpečný v případě vícevláknových aplikací:

// track whether Dispose has been called
private bool disposed = false;

/// <summary>
/// Clean up any resources being used. 
/// </summary>
/// <remarks>
/// Note that this is not thread safe. Another thread could start disposing the object
/// after the managed resources are disposed, but before the disposed flag is set to true.
/// If thread safety is necessary, it must be implemented by the client.
/// </remarks>
/// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
protected override void Dispose(bool disposing) 
{
 // Check to see if Dispose has already been called.
 if (!disposed)
 {
  if (disposing) 
  {
   // Dispose managed resources.
   if (components != null)
    components.Dispose();
   numeralBrush.Dispose();
   outlineBrush.Dispose();
   outlinePen.Dispose();
   meterlinePen.Dispose();
  }
  // Release unmanaged resources. 
  // N/A
  // Release base resources.
  base.Dispose(disposing);
 }
 disposed = true;
}
Jak jednoduché, jen kdyby to bylo ve vzoru pro Visual Studio rovnou.
Posted by arci | 5 Comments
Vedeno pod:

Závorkáři všech zemí, splet jsem se.

Nedávno mě jeden člověk nazval závorkářem. Nikdy jsem tuhle přezdívku pro programátora neslyšel, ale zaujala mě. Prý pořád píšu nějakou závorku. Kolik závorek vlastně obsahuje kód a který znak je nejastější?

Jako vzorek jsem vzak asi 24kB kódu C# který neobsahuje nic generovaného designerem. Takže tady je první desítka písmen:

Pořadí Písmeno Počet
1 E 1908
2 / 1453
3 R 1393
4 S 1264
5 A 1163
6 T 1149
7 I 914
8 O 860
9 N 853
10 M 816
První závorka má 90 výskytů. Take jaký závorkář?

Mimochodem mě napadá, že se podle pořadí lomítka dá usuzovat na množství komentářů v kódu.

Posted by arci | 13 Comments
Vedeno pod: