Otóż mam dwie formy, Form1 i formę Edytor. Forma Edytor zawiera 5 textboxów, z których pobieram treść i przekazuje do zmiennych Form1. Wszystko ładnie działa. Tylko teraz nie wiem jak rozwiązać mój problem, ponieważ forma Edytuj służy do wczytywania danych dla Form1 i jest uruchamiana buttonem z głównej. Po wczytaniu danych, można zamknąć formę edytuj i pracować na form1 ale to miało działać tak, że włączam program wpisuje dane do formy edytuj, zamykam ją i przy ponownym uruchomieniu programu już nie ma formy edytuj a tylko główna zawierająca zmienne, w których są zawarte dane przekazane z formy edytuj.
Może się wygłupiłem z tym pytaniem ale proszę o jakąś rade i z góry dzięki.
Myślałem o rozłożeniu tego na 2 programy, ale nie wiem jak w tedy przekazywać dane z jednego programu do drugiego.
Po odczytaniu danych od użytkownika, zapisz je np. do pliku (utwórz katalog w %appdata%
i tam umieść swój plik).
Pliki textowe to ostateczność. Chciałbym żeby ten program był łatwy przenoszeniu, bez zbędnych plików tylko sam .exe
jeżeli samo .exe, to chyba musialby ściągać te dane przez np. FTP, ja bym tak kombinował.
Program podczas działania nie może zmieniać swojego pliku exe - jedynie po zakończeniu, poza tym na tym poziomie na którym jesteś takie coś jest niewykonalne. Pozostaje jeszcze rejestr windows, ale musiał byś zadbać jeszcze o jakiś deinstalator który posprząta po sobie gdy user zapragnie wywalić twoją apke
mathiuf mówiąc o przenoszeniu, chyba miał na myśli przenoszenie pomiędzy różnymi maszynami, więc rejestr tutaj nie zda egzaminu.
evensense właśnie o to mi chodzi, żeby mój program był łatwy w przenoszeniu między komputerami. Może macie jakiś pomysł jak to rozwiązać z tym edytorem, ponieważ ta aplikacja ma być elastyczna dla rożnych danych( robię taki mały quiz) .
tak jak wyżej napisane - pliku .exe nie można zmieniać w czasie działania programu.
ja to widzę tak : zrobić tą aplikacje na zasadzie klient-serwer, przy włączaniu sprawdza, czy opcje zostały ustawione, jeżeli tak to je ściąga, jeżeli nie to wprowadzasz nowe.
Poza tym co masz na myśli mówiąc 'elastyczna dla różnych danych' ?
Chodzi o to, że tak jak mówiłem to taki mały quiz, gdzie np ja wprowadzam pytania z programowania i mogę go używać i skopiować na wiele stanowisk, a znowu Jan Kowalski wprowadzi pytania z geografii i skopiuje program na wiele stanowisk.
No to zrób program wczytujący quiz.
A do edytowania / tworzenia jakiś poboczny.
I zrobisz powiedzmy rozszerzenie .qui i otworzysz w programie 1.
Nie wiem co masz przeciwko dodatkowemu plikowi, przenosisz wtedy plik z programem + plik z quizem.
Ja robiłem takie coś ze słownikiem - tylko tam jest 1 program do edycji i otwierania. W sumie też ma funkcje quizu (link jest w moim podpisie).
Tyle że ktoś może sobie edytować. Ale oczywiście możesz zrobić opcje ze jak się wczyta plik to nie można edytować.
Podoba mi się twój pomysł z tym programem pobocznym, tylko mógłbyś mi jeszcze podać jakieś linki albo napisać jak mam się za to zabrać. Pliki są problemem, bo na tym programie mają pracować rożni ludzie i jeden usunie sobie plik txt i klapa program się wyłoży.
Jak usunie, to użytkownik jest dupa i tyle.
Nawet jeśli bedziesz miał dwa programy, jeden do edycji a drugi do obsługi, to i tak musisz skądś pobrać te dane.
Najprościej było by z osobnego pliku. Nie musi mieć rozszerzenia txt. Możesz wymyślić jakiekolwiek inne. Natomiast większość programów nie składa się z jednego pliku. I jeżeli dasz ten program w folderze, to niezaawansowany użytkownik komputera raczej Ci go nie usunie, bo będzie się bał.
Ewentualnie mógłbyś spróbować wsadzić te pytania w ten program (w plik .exe) do otwarcia quizu, ale to już inni eksperci forumowi Ci powiedzą, czy się tak da.
Edit. albo postaw se stronkę, i program do edycji będzie na nią ładował przez FTP (to nie jest trudne, bo w System.Net jest wbudowana obsługa http i ftp) według szablonu pytania powiedzmy do pliku o nazwie "geografia" na serwerze, a plik do obsługi quizu będzie się łączył z Twoją stroną (WebClient) i pobierał z niej pytania. Nawet możesz zrobić tak, że program nazywa się "geografia.exe" -> pobiera dane z pliku o nazwie geografia.txt na serwerze. Nazywa się "dupa.exe" pobiera z dupa.txt
Nawet przypadkowe usuniecie spowodowało by ponowne kopiowanie, a ten program wyglądałby prosto bo byłby plik .exe i txt.Nie tak jak zaawansowane aplikacje albo gra która chcą zainstalować i się boją :)
Czyli pliki są nieuniknione ale warto było próbować.
To z tym plikiem w .exe było by świetnym rozwiązaniem, ale chyba on najpierw musi się gdzieś utworzyć na dysku żeby go potem dodać do programu(to tylko moje przypuszczenia więc jeśli się mylę proszę o sprostowanie). Fajnie by było gdyby się tworzył gdzieś w jakieś uniwersalnej lokalizacji dla windows xp,vista,7
Ok quiz to będą dwa programy: edytor i quiz.
Dane z edytora zapisze do pliku w folderze temp(uniwersalny dla xp i 7)
StreamWriter strumien1 = new StreamWriter(Path.GetTempPath() + "plik.txt");
strumien1.Write("opis");
strumien1.Close();
Ale i tak pojawia się właśnie teraz główny problem z dołączeniem tego powstałego pliku do .exe quizu, bo przecież ten plik będzie raz utworzony na komputerze "matka", a quiz skopiowany na wiele stanowisk.
do modyfikacji exe najlepiej posłużyć się zasobami poniższy temat powinien cie nakierować
http://4programmers.net/Forum/Delphi_Pascal/114333-edycja_zasobow_w_exe_-_jak_to_zrobic
a jak to za wiele istnieją różnego rodzaju bindery, ale antywirusy często źle reagują na aplikacje potraktowane takim programem.
//ups pisałem tego posta w kontekście delphi, nie mam pojęcia czy takie możliwości daje .NET
szopenfx dzięki za naprowadzenie na temat, choć nie z c# to i tak coś mi to dało.
Jak dołączyć plik .txt do projektu, który później jest w .exe napisane jest tutaj:
matihuf napisał(a)
Dane z edytora zapisze do pliku w folderze temp(uniwersalny dla xp i 7)
Super rozwiązanie, ktoś sobie wyczyści tempa i program nie działa. ;]
matihuf napisał(a)
Jak dołączyć plik .txt do projektu, który później jest w .exe napisane jest tutaj:
Czy pytania w Twoim quizie nigdy się nie zmienią?
Teraz mam tak, że program Edytor tworzy plik textowy na dysku c, z którego później program quiz odczytuje dane, ale jak raz dodam ten plik do zasobów to później jego zwartość się nie zmienia, a przecież on miał się zmieniać zależnie od tego z jakiego działu użytkownik wpisze pytania w Edytorze.
Masz może jakiś pomysł jak to zrobić żeby potem był tylko gotowy quiz.exe bez innych plików
Ja bym zrobił tak...Dodałbym Quiz.exe do zasobów projektu Edytor. Następnie wsadzał w ten exek z poziomu aplikacji Edytor pytania i odpowiedzi do quizu.
A Quiz.exe byłby napisany tak, że odczytywałby te dane. Tzn standardowo były by powiedzmy to
"Pytanie 1" - "Odpowiedź 1" "Odpowiedź 2"
Które były zamieniane przez Edytor na
"Najdłuższa rzeka w Ameryce północnej" "Missisipi" "Missouri"
To jest pomysł ale wymaga weryfikacji przez kogoś na tym forum, co się zna - bo ja osobiście nie modyfikowałem jeszcze plików exe z poziomu aplikacji.
PS. że też chce ci się tak męczyć. Osobny plik byłby naprawde najlepszym , bezawaryjnym rozwiązaniem.
Wiem, że osobny plik txt przy .exe jest prostym rozwiązaniem, ale jeśli jest możliwość rozwiązania tego w inny sposób to czemu nie dążyć do poznania tej metody. To jest moje wyzwanie, w którym proszę o Waszą pomoc :)
Dobra.. nudziło mi się.
Rozwiązaniem może być program, który trzyma dane w swoich zasobach i potrafi je sam (z małą pomocą) zmienić. Z małą pomocą dlatego, że jednak te dane trzeba w pliku wykonywalnym przechowywać, a podczas działania programu zmienić się go nie da. Dlatego trzeba napisać dwa programy. Ten drugi oczywiście można umieścić.. gdzie? W zasobach tego pierwszego oczywiście ;). Sam program modyfikujący zasoby będziemy trzymać w zasobach .NET, a dane w zasobach natywnych (bo istnieje do tego kilka prostych, gotowych funkcji, gdzie w przeciwieństwie do zasobów .NET trzeba użyć.. linkera).
Najpierw program modyfikujący zasoby.
Importy z Windows API:
internal class Win32
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr BeginUpdateResource(string pFileName, [MarshalAs(UnmanagedType.Bool)] bool bDeleteExistingResources);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool UpdateResource(IntPtr hUpdate, string lpType, string lpName, ushort wLanguage, IntPtr lpData, uint cbData);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
}
Klasa i metoda do aktualizacji danego zasobu z pliku w podanym pliku wykonywalnym:
public class Win32Resources
{
public static void UpdateResource(string executablePath, string name, string type, byte[] data)
{
var handle = Win32.BeginUpdateResource(executablePath, false);
if (handle == IntPtr.Zero) throw new Win32Exception();
var dataPtr = Marshal.AllocHGlobal(data.Length);
Marshal.Copy(data, 0, dataPtr, data.Length);
try
{
if (!Win32.UpdateResource(handle, type, name, 0x007F, dataPtr, (uint)data.Length))
throw new Win32Exception();
}
catch (Exception)
{
throw;
}
finally
{
Marshal.FreeHGlobal(dataPtr);
}
if (!Win32.EndUpdateResource(handle, false))
throw new Win32Exception();
}
}
I sam program:
using System;
using System.Linq;
using System.IO;
using System.Diagnostics;
using System.Windows.Forms;
namespace ResourcesEmbedder
{
static class Program
{
[STAThread]
static void Main()
{
// todo: jakieś ambitniejsza obsługa błędów czy przekazanie rezultatu aplikacji-host
var arguments = Environment.GetCommandLineArgs();
if (arguments.Length != 6)
Environment.Exit(1);
int hostProcessId;
if (!int.TryParse(arguments[1], out hostProcessId))
Environment.Exit(2);
var hostExecutablePath = arguments[2];
var targetResourceFile = arguments[3];
var targetResourceName = arguments[4];
var targetResourceType = arguments[5];
var hostProcess = Process.GetProcesses().Where(p => p.Id == hostProcessId).FirstOrDefault();
// jest Process.GetProcessById, ale rzuta wyjątkiem, gdy proces nie jest działa,
// a dla nas to żadna wyjątkowa sytuacja nie jest
if (hostProcess != null && !hostProcess.HasExited)
hostProcess.WaitForExit();
byte[] data = null;
try
{
data = File.ReadAllBytes(targetResourceFile);
}
catch (Exception)
{
Environment.Exit(3);
}
try
{
Win32Resources.UpdateResource(hostExecutablePath, targetResourceName, targetResourceType, data);
}
catch (Exception ex)
{
MessageBox.Show("nie udalo sie zaktualizowac zasobow " + ex.Message);
Environment.Exit(4);
}
try
{
File.Delete(targetResourceFile);
}
catch (Exception)
{
// nie udało się z jakiegoś powodu usunąć pliku, ale udało się go umieścić w pliku wykonywalnym
// nie róbcie pustych bloków catch (komentarze się nie liczą ;P)
}
try
{
Process.Start(hostExecutablePath);
}
catch (Exception)
{
Environment.Exit(5);
}
}
}
}
Taki gotowy program wrzucamy do zasobów naszego głównego programu.
Importy:
internal class Win32
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr FindResource(IntPtr hModule, string lpName, string lpType);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LockResource(IntPtr hResData);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint SizeofResource(IntPtr hModule, IntPtr hResInfo);
}
Klasa i metoda do odczytania zasobu:
public class Win32Resources
{
public static byte[] GetResource(string name, string type)
{
var resourceInfoHandle = Win32.FindResource(IntPtr.Zero, name, type);
if (resourceInfoHandle == IntPtr.Zero) throw new Win32Exception();
int resourceSize = (int)Win32.SizeofResource(IntPtr.Zero, resourceInfoHandle);
if (resourceSize == 0) throw new Win32Exception();
var resourceDataHandle = Win32.LoadResource(IntPtr.Zero, resourceInfoHandle);
if (resourceDataHandle == IntPtr.Zero) throw new Win32Exception();
var dataPtr = Win32.LockResource(resourceDataHandle);
if (dataPtr == IntPtr.Zero) throw new Win32Exception();
var data = new byte[resourceSize];
Marshal.Copy(dataPtr, data, 0, resourceSize);
return data;
}
}
Odczytanie zasobu:
var data = Win32Resources.GetResource("TestData", "TestType");
textBoxData.Text = Encoding.Unicode.GetString(data);
I zapisanie zasobu:
try
{
var data = Encoding.Unicode.GetBytes(textBoxData.Text);
var tempFilePath = Path.GetTempFileName();
File.WriteAllBytes(tempFilePath, data);
var process = Process.GetCurrentProcess();
var arguments = process.Id + " \"" + process.MainModule.FileName + "\" \"" + tempFilePath + "\" TestData TestType";
var tempResourceEmbedderPath = Path.Combine(Path.GetTempPath(), "ResourcesEmbedder.exe");
File.WriteAllBytes(tempResourceEmbedderPath, Resources.ResourcesEmbedder);
Process.Start(tempResourceEmbedderPath, arguments);
Application.Exit();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
Powinno działać.
Dzięki ale trochę to skomplikowane, ciężko mi to dopasować pod siebie.
To jest rozwiązanie pod Windows Form? Bo wiele poleceń mi podkreśla, że ich nie zna.
Niektóre rzeczy z winapi, wkleiłeś importy dll'i?
Dałem ci gotowy kod, dałem ci gotową binarkę do zdekompilowania, więcej nie pomogę, bo to byłaby przesada :(.
Error 7 The type or namespace name 'DllImport' could not be found (are you missing a using directive or an assembly reference?) D:\c#\proba1\WindowsFormsApplication1\WindowsFormsApplication1\Form1.cs 39 6 WindowsFormsApplication1
Error 3 The type or namespace name 'MarshalAs' could not be found (are you missing a using directive or an assembly reference?) D:\c#\proba1\WindowsFormsApplication1\WindowsFormsApplication1\Form1.cs 34 72 WindowsFormsApplication1
tego typu błędy
No bez przesady....
using System.Runtime.InteropServices;