Het laden van een Assembly vanuit de Resource van je applicatie

Door sanderev66 op maandag 12 december 2011 18:00 - Reacties (41)
Categorie: -, Views: 4.049

Hallo iedereen :)

Vandaag ga ik jullie iets uitleggen wat voor mij het mogelijk maakt om MicroSE Minis te maken. Namelijk het dynamisch laden van assemblies vanuit de resources van je hoofdassembly.

Bron: Jeffrey Richter: Excerpt #2 from CLR via C#, Third Edition

In de bron kan je lezen dat een assembly in een byte-array gelezen worden. Welke dan door de uitvoerende assembly geladen wordt. Dit is een geweldige oplossing, alleen vind ik de uitleg nog wat matig. Dus neem ik je hieronder stap voor stap door wat je moet doen om dit te bereiken.

Stap 1

Open een (nieuw) project in Microsoft Visual Studio. Bouw hierin je applicatie zoals je dit normaal gesproken zal doen. Zet van al je referenties de Property "Copy Local" op false. Hierdoor zullen deze dll bestanden niet meer in de outputmap bij het compilen geplaatst worden. Dus als je nu gaat compilen krijg je een foutmelding.

Stap 2

Als je deze nog niet hebt - maak je een Lib / Library mapje in je project. Let op dat je deze niet in de solution maar in het project zélf zet. Maak deze map via Visual Studio: rechtsklik op je project, Add > New Folder. Geef deze map de gewenste naam.

In deze map plaats je een link naar de libraries die je gebruikt. (Rechtsklik, add, existing item, selecteer "All files *.*", zoek de DLL op en kies in de dropdown van de Add knop voor "Add as link". Visual Studio maakt dan een link naar het DLL bestand in de map, dit is handig als je een nieuwe versie van het DLL bestand hebt, deze automatisch bijgewerkt wordt.

In de eigenschappen van het gelinkte bestand kies voor "Embed Resource" als Build action.

Stap 3

Nu moet je nog je code aanpassen. :) Hiervoor kiezen we de standaard static klasse "Program". Let op, deze klasse mag geen referentie naar de dll hebben, anders gaat dit niet werken.

Om te beginnen heb ik een methode van de code van Jeffrey Richter gemaakt.

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private static Assembly LoadAssemblyFromResource(string defaultNamespacestring folderstring assembly)
{
    var sbName = new StringBuilder();
    sbName.Append(defaultNamespace + ".");
            
    if (!string.IsNullOrWhiteSpace(folder))
        sbName.Append(folder + ".");

    sbName.AppendFormat("{0}.dll"new AssemblyName(assembly).Name);

    using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(sbName.ToString()))
    {
        //Create a buffer.
        var buffer = new byte[16384]; //16 KB bufer

        using(var memStream = new MemoryStream()) //Create a memory-stream
        {
            int read = 0;
            while((read = stream.Read(buffer0buffer.Length)) > 0//Fill the buffer and check if there are bytes written.
            {
                memStream.Write(buffer0read); //Write the buffer to the memorystream.
            }

            return Assembly.Load(memStream.ToArray());
        }
    }
}


Jeffrey had in zijn code al de naam van de DefaultNamespace opgenomen, in mijn methode is dat een parameter. Zo ook is het met mijn code mogelijk de library in een submap te zetten.
Verder heb ik het inlezen van de Stream veranderd zodat deze nu niet gelimiteerd is tot de maximale lengte van wat stream.Read() aankan (int).


C#:
1
2
3
4
5
6
7
8
static void Main()
{
    AppDomain.CurrentDomain.AssemblyResolve += (senderargs) => LoadAssemblyFromResource("Test""Lib"args.Name);

    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form1());
}


Verder werkt het zoals je gewend bent :)

Volgende: Gelukkig 2012! 01-'12 Gelukkig 2012!
Volgende: Idee: De toekomst van de PC 09-'11 Idee: De toekomst van de PC

Reacties


Door Tweakers user StM, maandag 12 december 2011 18:25

Ik zal het vast niet snappen maar waarom wil je in hemelsnaam dll's gaan embedden als resource? Lever ze gewoon netjes zoals het hoort los mee...

Ik vind dit persoonlijk maar een smerige en hacky methode.

Door Tweakers user Eguna, maandag 12 december 2011 18:42

Programmeertips van de grootste knoeikont op Tweakers \o/

Door Tweakers user Snake, maandag 12 december 2011 18:54

@StM: stel je hebt een assembly met een interface en je wilt dat iemand anders een plugin schrijft die die interface implementeert. Hoe ga je die assembly inladen? Juist, via Assembly.Load ;-)

Door Tweakers user Snake, maandag 12 december 2011 18:56

Overigens vind ik dat Sander beetje omslachtig te werk gaat.

Waarom geen gebruik maken van Assembly.LoadFile? http://msdn.microsoft.com/en-us/library/b61s44e8.aspx

Door Tweakers user alwinuzz, maandag 12 december 2011 19:02

@Snake: Omdat je dan de assembly eerst zou moeten opslaan op disk.

@Sander: als je écht mini wil gaan kan je de assemblies gecomprimeerd embedden (gezipt), en dan bij LoadAssemblyFromResource unzippen. Maar dan is het 'Add as Link' van je dll bestand niet meer voldoende.

Door Tweakers user Ellos, maandag 12 december 2011 19:04

waarom geen gebruik maken van ilmerge....

Door Tweakers user Ventieldopje, maandag 12 december 2011 19:21

Ellos schreef op maandag 12 december 2011 @ 19:04:
waarom geen gebruik maken van ilmerge....
ILMerge is a utility for merging multiple .NET assemblies into a single .NET assembly. It works on executables and DLLs alike and comes with several options for controlling the processing and format of the output.
Maargoed, sanderev66 probeert bij veel dingen het wiel opnieuw uit te vinden en plaatst dat dan als wereldnieuws :+

Door Tweakers user sanderev66, maandag 12 december 2011 19:36

Ik gebruik geen ILMerge omdat de maker van ILMerge deze methode de voorkeur geeft. Daarbij vind ik het Wiel niet opnieuw uit, en plaats het al helemaal niet als "wereldnieuws". Als je het niet wilt lezen kan je gewoon op de "Back" knop van je browser klikken. Ik "gebruik" alleen de code van Jeffrey Richter . (zie bron)
quote: Mike Barnett
As the author of ILMerge, I think this is fantastic! If I had known about this, I never would have written ILMerge.

Many people have run into problems using ILMerge for WPF applications because WPF encodes assembly identities in binary resources that ILMerge is unable to modify. But this should work great for them.

Thanks!
Zie bron in item.

Maar natuurlijk zijn jullie zodra ik iets hier plaats direct naar de comments afdeling gescrolled om je gal te spuien.
StM schreef op maandag 12 december 2011 @ 18:25:
Ik zal het vast niet snappen maar waarom wil je in hemelsnaam dll's gaan embedden als resource? Lever ze gewoon netjes zoals het hoort los mee...

Ik vind dit persoonlijk maar een smerige en hacky methode.
Natuurlijk is het niet supernetjes, maar het doet wat het doen moet ;) En feitelijk gebeurt hetzelfde als je gewoon de DLLs er naast zet. .NET opent gewoon een dll bestand en geeft een Assembly terug, waar Jeffrey bij deze een byte-array opent en hiervan een Assembly teruggeeft.
Snake schreef op maandag 12 december 2011 @ 18:56:
Overigens vind ik dat Sander beetje omslachtig te werk gaat.

Waarom geen gebruik maken van Assembly.LoadFile? http://msdn.microsoft.com/en-us/library/b61s44e8.aspx
Omdat je nog geen file hebt ;)
alwinuzz schreef op maandag 12 december 2011 @ 19:02:
@Snake: Omdat je dan de assembly eerst zou moeten opslaan op disk.

@Sander: als je écht mini wil gaan kan je de assemblies gecomprimeerd embedden (gezipt), en dan bij LoadAssemblyFromResource unzippen. Maar dan is het 'Add as Link' van je dll bestand niet meer voldoende.
Tja, dat klopt als je enkel naar bestandsgrootte kijkt. Maar je verliest wel snelheid als je dat gaat doen ;)

En nogmaals over het uitvinden van het wiel. Dat ik het nou eenmaal leuk vind om dingen zelf uit te vinden, voordat ik ga Googlen is waar. Op die manier leer ik mijzelf een betere programmeur te worden. En, wanneer ik iets ontdek vind ik dat zó leuk dat ik dat met de rest van de wereld wil delen. Dus dat doe ik dan ook, door middel van mijn applicaties. Of, zoals in dit geval, met een leuke blogpost - ook al is dit niet mijn eigen vinding. Ik heb hier wel alles op een rijtje gezet om het werkend te krijgen.

Maar nogmaals, je hoeft het niet te lezen. Echt niet. Maar voor een enkeling kan het wel eens extreem handig zijn. Dat is voor mij genoeg.
Eguna schreef op maandag 12 december 2011 @ 18:42:
Programmeertips van de grootste knoeikont op Tweakers \o/
Nee, dat ben jij al.

[Reactie gewijzigd op maandag 12 december 2011 20:26]


Door Tweakers user RobIII, maandag 12 december 2011 20:27

sanderev66 schreef op maandag 12 december 2011 @ 19:36:
Tja, dat klopt als je enkel naar bestandsgrootte kijkt. Maar je verliest wel snelheid als je dat gaat doen ;)
Meten == weten ;)
In veel gevallen hoef je dankzij compressie een behoorlijke factor minder van de HD te lezen (= bottleneck) en de-compress je 't in een fractie van de tijd die de uncompressed versie nodig zou hebben om te transferren.

Door Tweakers user Hadron, maandag 12 december 2011 20:36

Wat betreft het uitvinden van het wiel: Soms wil je wel eens wat proberen. Gewoon, om in vorm te blijven, of om gevoel voor een concept of API te krijgen. En gezien 99% van alle simpele code al bedacht is, kom je vaak op een wiel uit dat al eerder uitgevonden is.

Toch heb ik nog wel een vraag: Waarom?
Ik kan me voorstellen dat je de LoadAssembly( byte[]) gebruikt om een versleutelde, gecomprimeerde of handmatig gesignde assembly te laden als plugin o.i.d., maar waarom wil je een assembly uit de resource file laden? Is het dan niet handiger om de code in de assembly op te nemen waar de resource file in zit?

Door Tweakers user ZpAz, maandag 12 december 2011 20:38

Zo groot zullen "DLL" bestanden wel niet zijn, dus de de-compressie komt éénmaal voor. De snelheidswinst die je daar zou kunnen behalen is nihil.

Door Tweakers user sanderev66, maandag 12 december 2011 20:41

Dat hangt af van welke lib je gebruikt om in/uit te pakken. Hiervoor kán je echter wel alleen die van .NET zelf gebruiken (gzip) - anders heb je alsnog een extra assembly nodig.

Wat betekend dat je de volgende dingen moet doen.
gzip uit resource inlezen (mooie byte-array zoals in het code voorbeeld)
gzip uitpakken - ik denk dat dit wel naar een Memstream kan, maar hier kan ik verder weinig over zeggen (heb nog niet met dit gedeelte van .NET gewerkt)
deze uitgepakte bytes inlezen naar Assembly.

Tegen assembly uit resource inlezen naar byte array en deze array aan de Assembly.Load() meegeven.

En dan heb je 100% gelijk met meten = weten. Maar ja, veel langzamer is de bovengenoemde methode niet vergeleken met het gewone "inlezen van assembly van de HDD" sterker nog - ik meet geen verschil.

Door Tweakers user alwinuzz, maandag 12 december 2011 20:58

Het hangt ook af van wat je wilt bereiken. Snelheidswinst als programma draait is één ding, maar je kan ook je resources zippen om de downloadgrootte te verkleinen.

Door Tweakers user Knutselwout, maandag 12 december 2011 21:06

sanderev66 schreef op maandag 12 december 2011 @ 19:36:
Dat ik het nou eenmaal leuk vind om dingen zelf uit te vinden, voordat ik ga Googlen is waar. Op die manier leer ik mijzelf een betere programmeur te worden.
Als ik jou was dan zou ik maar gaan Googlen want ik merk geen vooruitgang.zo. Van de andere kant verklaart dit wel heeeeeeeeeeeeeeel veel,

Door Tweakers user sanderev66, maandag 12 december 2011 21:38

alwinuzz schreef op maandag 12 december 2011 @ 20:58:
Het hangt ook af van wat je wilt bereiken. Snelheidswinst als programma draait is één ding, maar je kan ook je resources zippen om de downloadgrootte te verkleinen.
Je kan ook de bestanden samenvoegen en dit resultaat zippen ;) Maar je hebt gelijk, je moet per situatie bepalen wat je het beste kan gebruiken.

Er komt een MicroSE Mini Framework, welke op deze (of vergelijkbare) wijze in de Minis verwerkt zullen worden. Dit framework zal dan taalbestanden / settings / controls hebben, welke overeenkomen met het originele framework. (Waarschijnlijk 90% linked classes en een paar nieuwe) uiteindelijk moet dit framework een stuk kleiner zijn dan het gewone framework.
(Met het "gewone framework" bedoel ik natuurlijk het .MSE framework, dit betekend natuurlijk niet dat ik nooit applicaties zal maken die het .MSE Framework op deze wijze zal verwerken. Maar het originele doel hiervan is het Mini Framework)
Knutselwout schreef op maandag 12 december 2011 @ 21:06:
[...]


Als ik jou was dan zou ik maar gaan Googlen want ik merk geen vooruitgang.zo. Van de andere kant verklaart dit wel heeeeeeeeeeeeeeel veel,
Alsjeblieft, hou op.

[Reactie gewijzigd op maandag 12 december 2011 21:46]


Door Tweakers user Battle Bunny, dinsdag 13 december 2011 09:54

Er komt een MicroSE Mini Framework, [...] uiteindelijk moet dit framework een stuk kleiner zijn dan het gewone framework.
Niet lullig bedoelt hoor, maar waarom een kleine versie creeren van een toch al klein "framework"?

Door Tweakers user sanderev66, dinsdag 13 december 2011 11:00

Omdat er enkele functionaliteit exclusief voor Minis gaat worden, en er zullen behoorlijk wat onderdelen niet beschikbaar voor Minis worden.

Alles wat overlapt komt in het gewone framework en wordt in het kleine gelinkt.

[Reactie gewijzigd op dinsdag 13 december 2011 11:01]


Door Tweakers user GOUDSBS, dinsdag 13 december 2011 12:49

Ben wel benieuwd wat nou eigenlijk de eerste mini gaat worden die de functionaliteit laat zien van het mini framework. Wellicht ook een vergelijking met het normale framework, om de verschillen weer te geven tussen deze 2 frameworks.

Door Tweakers user sanderev66, dinsdag 13 december 2011 13:36

Voor de gebruiker zal er in principe weinig verschillen. Behalve dat het Mini Framework verplicht dat instellingen in "Mijn Documenten\MicroSE" worden opgeslagen. Technisch zullen er een aantal extra beveiligingen gaan komen (niet direct)

Door Tweakers user Alex), dinsdag 13 december 2011 14:02

Ik heb het .MSE Framework wel eens bestudeerd, en ik vond het al vrij... Mini. Wat voegt een nieuw Mini-framework dan toe?

En dat Mini Framework: ga je dat delen, al dan niet in binaire vorm? (Hoeft niet eens open source als je dat niet wilt)

Door Tweakers user GOUDSBS, dinsdag 13 december 2011 14:15

OK, voor instellingen is Mijn Documenten is nou niet echt de geschikte map.... %appdata% lijkt mij logischer.......

Maar even terug komen op je framework.... wat kunnen wij verwachten als 'test'/'demo' mini framework app?

Door Tweakers user sanderev66, dinsdag 13 december 2011 14:24

Alex) schreef op dinsdag 13 december 2011 @ 14:02:
Ik heb het .MSE Framework wel eens bestudeerd, en ik vond het al vrij... Mini. Wat voegt een nieuw Mini-framework dan toe?

En dat Mini Framework: ga je dat delen, al dan niet in binaire vorm? (Hoeft niet eens open source als je dat niet wilt)
Dat gaat natuurlijk geleverd krijgen in de minis ;)
GOUDSBS schreef op dinsdag 13 december 2011 @ 14:15:
OK, voor instellingen is Mijn Documenten is nou niet echt de geschikte map.... %appdata% lijkt mij logischer.......
Logischer, maar niet gebruikersvriendelijker ;) Maar dat wordt later nog wel uitgelegd ;)
Maar even terug komen op je framework.... wat kunnen wij verwachten als 'test'/'demo' mini framework app?
Dat zul je wel zien :p

Door Tweakers user alwinuzz, dinsdag 13 december 2011 14:27

Sla je instellingen dan op in ApplicationData ofzo, niet in My Documents :)

Door Tweakers user sanderev66, dinsdag 13 december 2011 14:47

%AppData%\MicroSE wordt al gebruikt voor alle grotere MicroSE programma's. Maar voor Minis zullen instellingen meer document gebaseerd zijn. Zoals je al bij NoteIt kan zien - instellingen voor individuele Notities worden in de notitie zelf opgeslagen, die van het programma gaan naar de AppData. Hierdoor heb je twee plekken waar de instellingen opgeslagen worden, wat voor minis niet wenselijk is.

Minis van Tier 2 (compile tijdens "installatie") en Tier 3 (compile voor uitvoeren) zullen zelfs helemaal document-achtig worden.

(Volgens het Document Application principe)

[Reactie gewijzigd op dinsdag 13 december 2011 14:48]


Door Tweakers user Alex), dinsdag 13 december 2011 14:48

Wat is een Mini nou eigenlijk? Een mini-applicatie?

Door Tweakers user alwinuzz, dinsdag 13 december 2011 14:53

Ik weet niet hoor, klinkt wel heel ingewikkeld voor een post-it programmaatje... Maar leef je vooral uit, ben benieuwd naar het resultaat!

Door Tweakers user ThaStealth, dinsdag 13 december 2011 14:54

Precompiled Minis: these are the most normal working Minis. You download a single exe file from the MicroSE Server and execute it. When you close the program it will not leave any unwanted traces behind.
They can, however, store settings. These settings will be stored using the Mini Framework and saved inside your Documents folder. Which you can manage easily.
Compiled on your PC, these mini's exist of a single Xml file which is compiled by a special and userfriendly compiler. Theere will also be an IDE that uses Microsoft Visual Studio.

Copy-Peest van Sander zijn site,

Hoe moet ik dat 2e puntje zien? Ga je Visual Studio meeleveren, of ga je de mensen verplichten om de express versie te downloaden om die meuk te compileren?

Btw kudos als je een "userfriendly" compiler weet te schrijven... Veel compilers die ik gezien heb kunnen vanalles, maar User friendly zijn ze niet :P, niet dat daar ook maar ENIGE vraag naar is.....

Waarom zet je trouwens op je projecten pagina hoe de meuk van binnen werkt? Leuk voor je dat je je mini LIBRARY dll gebruikt (sorry hoor, is echt geen framework). Maar de eindgebruiker zal het aan zijn kont roesten of het nu via een speciale aanroep naar jouw library is..

Door Tweakers user GOUDSBS, dinsdag 13 december 2011 14:56

Duidelijk! Ik zou bijna zeggen dat een Windows Domein met Exchange en *nix servers gemakkelijker in elkaar steek dan een applicatie van MicroSE.

[Reactie gewijzigd op dinsdag 13 december 2011 14:58]


Door Tweakers user sanderev66, dinsdag 13 december 2011 15:03

Minis zijn origineel als "MicroSE WebDocument" voor MicroSE Unite begonnen. Waarmee je inpricipe interactieve websites zou krijgen welke lokaal op je computer draaien.

Omdat Unite gestopt is, heb ik dit idee naar MicroSE Mini vertaald.

@ThaStealth: Je kan natuurlijk ook de Nederlandse versie van de site bekijken.

[Reactie gewijzigd op dinsdag 13 december 2011 15:08]


Door Tweakers user ThaStealth, dinsdag 13 december 2011 15:13

- Reageer eens inhoudelijk ;)
- Je Nederlandse site is stuk anders had ik het daar wel van gecopy paste
- Hou je eens een keer aan de conventies, Mijn Documenten zijn bedoeld voor de persoonlijke bestanden van de gebruiker (word documenten en meuk), niet voor de settingmeuk van een of ander gammel programma. Het eerste wat iedere gebruiker doet als hij onbekende meuk in mijn documenten ziet is het weggooien, waarna je programma het wss niet meer zal doen...

Door Tweakers user sanderev66, dinsdag 13 december 2011 15:20

Er is een reden waarom ik dat nog niet doe ;)
- Hou je eens een keer aan de conventies, Mijn Documenten zijn bedoeld voor de persoonlijke bestanden van de gebruiker (word documenten en meuk), niet voor de settingmeuk van een of ander gammel programma. Het eerste wat iedere gebruiker doet als hij onbekende meuk in mijn documenten ziet is het weggooien, waarna je programma het wss niet meer zal doen...
De programma's zullen zo gemaakt worden dat je in principe géén settingsfile nodig hebt. En wat je kan instellen wil je zelf goed kunnen verwerken. Dus dit gaat niet zomaar ergens opduiken.
Dus je krijgt bij wijze van spreken gewone documenten waar een overdraagbaar profiel in opgeslagen is.

Dan zal ik nog twee woorden hinten: cloud opslag.

Meer informatie komt op http://mini.microse.nl :) Maar voor nu heb ik al genoeg verklapt over MicroSE Mini :p

[Reactie gewijzigd op dinsdag 13 december 2011 15:22]


Door Tweakers user sanderev66, dinsdag 13 december 2011 15:56

iig heb ik nog aan de hand van dit voorbeeld ^^ een release van QuickSQL gemaakt.

Download:
http://microse.nl/downloads/extern/QuickSQL.exe

LET OP!
Deze is niet officieel ondersteund. En toekomstige releases zullen op de originele wijze zijn.

[Reactie gewijzigd op dinsdag 13 december 2011 16:03]


Door Tweakers user ThaStealth, dinsdag 13 december 2011 16:32

En je release crashed meteen bij mij


Door Tweakers user ThaStealth, dinsdag 13 december 2011 16:38

Standaard "Er is een fout opgetreden in MicroSE QuickSQL en het programm moet worden afsgesloten" box

Door Tweakers user sanderev66, dinsdag 13 december 2011 16:39

Kan je de officiele QuickSQL wel draaien?


Door Tweakers user ThaStealth, dinsdag 13 december 2011 16:46

Je hebt geluk dat mijn PC visual studio heeft,

hier heb je de exception+ stack:

{"Object must be a root directory (\"C:\\\") or a drive letter (\"C\")."}
at System.IO.DriveInfo..ctor(String driveName)
at MicroSE.QuickSQL.ApplicationInformation.get_IsOnUSBDrive()
at MicroSE.QuickSQL.ApplicationInformation.get_SettingsFolder()
at MicroSE.QuickSQL.ApplicationInformation.get_SettingsFile()
at MicroSE.QuickSQL.Program.Load(String[] args)
at MicroSE.QuickSQL.Program.Main(String[] args)

Door Tweakers user sanderev66, dinsdag 13 december 2011 16:48

Ah.. je hebt 'm op een netwerkshare staan :p

Wel jammer dat DriveInfo niet over netwerkshares werken. :(

En ik heb 'm bijgewerkt :p En bedankt voor het melden - Deze bugfix komt ook in de volgende officiële release (die hetzelfde probleem heeft)

Minis gaan uiteindelijk dus op ongeveer deze wijze werken. Je ziet een linkje, je klikt en TADA! Je kan het programma gebruiken :p
Natuurlijk zodra vervelende bugs er uit zijn ;)

[Reactie gewijzigd op dinsdag 13 december 2011 22:02]


Door Tweakers user creator1988, donderdag 15 december 2011 15:26

sanderev66 schreef op dinsdag 13 december 2011 @ 16:48:
Minis gaan uiteindelijk dus op ongeveer deze wijze werken. Je ziet een linkje, je klikt en TADA! Je kan het programma gebruiken :p
Natuurlijk zodra vervelende bugs er uit zijn ;)
Euh. Ooit gehoord van ClickOnce 8)7

Door Tweakers user sanderev66, donderdag 15 december 2011 15:40

Ja, ik vind dat echt vreselijk werken.

Daarbij is het niet echt clickonce gezien je minimaal 2 keer moet klikken (1x om te starten, 1x om te installeren) Mijn oplossing is echt 1 klik :)

Daarbij is mijn oplossing sneller, die clickonce installers zijn langzamer dan zelfs de gewone InnoSetup installers die ik normaal gesproken gebruik. Maar zijn niet zo eenvoudig naar wens aan te passen.

En ten vierde start de clickonce installer het programma niet na installatie, waardoor je alsnog in het start menu naar het programma moet gaan zoeken.

[Reactie gewijzigd op donderdag 15 december 2011 15:50]


Reageren is niet meer mogelijk