Laden...

Forenbeiträge von Andreas.May Ingesamt 915 Beiträge

25.06.2008 - 09:22 Uhr

Hrm?

Die Klasse AssemblyActivator<T, I> ist für die Plugins.
Die Klasse Serializer<T> ist für alle möglichen objecte bzw. Klassen.

Das Serialisieren als solches ist dir dann überlassen. Aber könnte z.B. wie folgt aussehen.


static public T LoadObject<T>(string providerName, Company company) where T : Helper.Serializer<T>
    {
      if ((string.IsNullOrEmpty(providerName) || company == null))
      {
        return null;
      }
      string Xml = ReadString(providerName + "/Company/" + company.Caption + '/' + typeof(T).ToString() );
      if (string.IsNullOrEmpty(Xml))
        return null;
      return Helper.Serializer<T>.LoadFromString(Xml);
    }

    static public void SaveObject<T>(string providerName, Company company, T objectToSave) where T : Helper.Serializer<T>
    {
      if ((string.IsNullOrEmpty(providerName) || company == null))
        return;
      string Xml = string.Empty;
      if (objectToSave != null)
      {
        Xml = objectToSave.SaveToString();
      }
      WriteString(providerName + "/Company/" + company.Caption + "/" + typeof(T).ToString(), Xml);
#if DEBUG
      string Xml2 = ReadString(providerName + "/Company/" + company.Caption + '/' + typeof(T).ToString());
      System.Diagnostics.Debug.Assert(Xml2 == Xml);
#endif
    }

Company und providerName sind nur beispiele da ich den Code aus einer ERP Anbindung heraus verwendet habe und das ganze in eine XDB als Formatvorlagen Serialisiere. Kannst hier ja stattdessen andere übergabeparameter einfügen wie den Pfad und diese bei den Methoden ReadString und WriteString die nichts anderes als Streams ein und auslesen implementieren oder eben über AssemblyActivator<T, I> eine Klasse aus einer anderen Assembly oder dessen Resource usw.

Statt über expliziete Typennamen wird das ganze eben generisch abgehandelt. IXmlSerializable zu implementieren ist auch eine Möglichkeit aber bei jeder gewünschten Klasse diese zu implementieren ist aufwändiger.

Du kannst natürlich auch Schnittstellen oder Reflection und andere Wege versuchen. Ich habe dir defintiv einen Weg aufgezeigt wie man das ganze Simpel lösen kann.

Und das ist beweiten einfacher als:


            Object objectToSerialize = null;
            string path = Application.StartupPath;
            string[] pluginFiles = Directory.GetFiles(path, "*.DLL");
            for (int i = 0; i < pluginFiles.Length; i++)
            {
                string args = pluginFiles[i].ToUpper().Substring(
                    pluginFiles[i].ToUpper().LastIndexOf("\\") + 1,
                    pluginFiles[i].ToUpper().IndexOf(".DLL") -
                    pluginFiles[i].ToUpper().LastIndexOf("\\") - 1);

                Type ObjType = null;
                try
                {
                    // load it
                    Assembly ass = null;
                    ass = Assembly.Load(args);
                    Type[] types = ass.GetTypes();
                    String assType = types[0].ToString().Substring(0, types[0].ToString().LastIndexOf('.'));
                    if (ass != null)
                        ObjType = ass.GetType(assType + ".Plugin", false, true);
                }
                catch (Exception ex) { }
                try
                {
                    if (ObjType != null)
                        objectToSerialize = Activator.CreateInstance(ObjType);
                }
                catch (Exception ex) { }
            }

            ((ACPlugin)objectToSerialize).ReadXml(reader);

24.06.2008 - 10:39 Uhr

Hrm, um das ganze etwas zu vereinfachen kann man auch folgendes angehen.


[Serializable()]
public class Serializer<T>
	{
		public string SaveToString()
		{
			try
			{
				XmlSerializer serializer = new XmlSerializer(typeof(T));
				using (StringWriter writer = new StringWriter())
				{
					serializer.Serialize(writer, this);
					return writer.ToString();
				}
			}
			catch (Exception ex)
			{
				System.Diagnostics.Debug.Fail("Beim erstellen eines XML Strings: " + ex.Message);
				throw;
			}
		}

		public void Save(string fileName)
		{
			try
			{
				XmlSerializer serializer = new XmlSerializer(typeof(T));
				using (TextWriter writer = new StreamWriter(fileName))
				{
					serializer.Serialize(writer, this);
					writer.Flush();
				}
			}
			catch (Exception ex)
			{
				System.Diagnostics.Debug.Fail("Fehler beim Speichern der " + fileName + ex.Message);
				throw;
			}
		}

		static public T LoadFromString(string xmlString)
		{
			try
			{
				XmlSerializer serializer = new XmlSerializer(typeof(T));
				using (StringReader reader = new StringReader(xmlString))
				{
					T o = (T)serializer.Deserialize(reader);
					return o;
				}
			}
			catch (Exception ex)
			{
				System.Diagnostics.Debug.Fail("Fehler beim lesen von " + xmlString + ex.Message);
				throw;
			}
		}

		static public T Load(string fileName)
		{
			try
			{
				XmlSerializer serializer = new XmlSerializer(typeof(T));
				using (TextReader reader = new StreamReader(fileName))
				{
					T o = (T)serializer.Deserialize(reader);
					return o;
				}
			}
			catch (Exception ex)
			{
				System.Diagnostics.Debug.Fail("Fehler beim Laden der " + fileName + ex.Message);
				throw;
			}
		}
		#endregion
	}


  public enum AssemblyLocation
  {
    Gac, // Gloabl Assembly Cache
    AbsolutePath // Der Pfad ist in AssemblyName komplett angegeben
  }

  public class AssemblyActivator<T, I> : Helper.Serializer<T>
  {
    private AssemblyLocation _Location;
    private string _AssemblyName;
    private string _ClassName;

    public AssemblyLocation Location
    {
      get{return _Location;}
      set{_Location = value;}
    }
   
    public string AssemblyName
    {
      get{return _AssemblyName;}
      set{_AssemblyName = value;}
    }
   
    public string ClassName
    {
      get{return _ClassName;}
      set{_ClassName = value;}
    }

    internal I CreateObject(string assemblyPath)
    {
      Assembly a = null;

      try
      {
        if (Location != AssemblyLocation.Gac)
        {
          a = Assembly.LoadFrom(AssemblyPath);
        }
        else
        {
          a = Assembly.Load(AssemblyPath);
        }
      }
      catch (FileNotFoundException ex)
      {
	System.Diagnostics.Debug.Fail("Fehler: " + ex.Message);
        return default(I);
      }
      Type ClassType = a.GetType(ClassName);
       if (ClassType == null) return default(I);

      return (I)Activator.CreateInstance(ClassType);
    }
  }

Beispiel Aufrufe:



  public class Provider : Helper.AssemblyActivator<Provider,IBinding>
  {
    public IBinding CreateBinding()
    {
      return base.CreateObject(<Pfad>);
    }
   // usw...
  }

  public class Company : Helper.Serializer<Company>
  {
   // usw...
  }

Damit kannst du dann deine Plugins laden und innerhalb der Plugins z.B. deine Klassen serialisieren. Den AssemblyActivator kannst statt den Klassennamen auch alternativ eine IPlugin Schnittstelle verwenden nach der innerhalb der Assembly gesucht wird - finde den Klassennamen nur nen Tick besser aus den einfachen Grund da man hier z.B. ein XML File verwende kann um das ladenen der Plugins von aussen her zu konfigurieren.

24.06.2008 - 09:58 Uhr

Hallo Community,

seid längeren benutze ich eigentlich um z.B. auf aktive COM Objekte zuzugreifen Marshal.GetActiveObject, vor einigen Tagen erhielt ich von einen Kollegen den Hinweis das es unter Windows Vista damit zu Problemen kommen könnte. Daher empfahl er mir lieber Marshal.BindToMoniker zu verwenden.

Leider ist mir auch trotzt durchlesen der MSDN Info nicht ganz klar worin nun der Unterschied liegen soll wenn es überhaupt einen gibt?

Danke im Voraus.

23.06.2008 - 19:59 Uhr

Hrm, "manche" Schnittstellen bieten ein SafeReleaseCom object an das genau dafür da ist. Ansonsten hast kaum eine Chance ausser mal zu schauen was die Marshal sonst noch so bietet.

23.06.2008 - 14:08 Uhr

Na ja, du kannst dir ja alle Prozesse auflisten, davon die ThreadId's holen und schauen welche ThreadId mit der gesuchten übereinstimmt. Somit findest du den zugehörigen Prozess heraus.

20.06.2008 - 12:50 Uhr

Hrm, denke auch das dich einfach am besten mal mit ihr in Ruhe unterhältst und die Punkte die dir Wichtig sind, ansprechen solltest.

Muss zugeben, kann aus keinen Erfahrungen zurückgreifen.
Aber ich denke du wirst dich danach zumindest besser fühlen wenn du weist woran du wirklich bist. Assi hat es zwar ziemlich scharf formuliert, aber es bringt dir auf Dauer auch nichts wenn du im ungewissen vor dich her dümpelst, denn davon wird man denke ich auch nicht wirklich Glücklich.

19.06.2008 - 14:51 Uhr

Hrm, ein anderer Weg über WIN API wäre hier mal zu schauen was beim überschreiben der WndPRoc möglich ist.

Siehe hierzu mal in der MSDN nach den folgenden WindowsNachrichten:

**CTLCOLORSCROLLBAR **= 0x0137
**CTLCOLORSTATIC **= 0x0138

Denke dennoch das mit JAck30lena's beispiel bei CodeProject glücklicher wirst. Mach nen UserControl draus und verbinde diese als Komponente die auf jedes X-Beliebige Control legen kannst. Mach dann nen Subclassing auf die Controls und schau mal nach den WindowsNachrichten. Wenn eine Scroulbar instanziert / angelegt wird - vertausche dann den Zeiger von der Original oder lösche diesen und verwende dann deine Scroulbar. So könntest via Drag&Drop im Designer dann deine Scroulbar auf alle Controls verwenden.

Würde zwar einmalig einen riesen Aufwand bedeuten aber könntest diese dann immer weider verwenden.

19.06.2008 - 00:26 Uhr

Hrm, knapp 1-2 Jahre würde ich grob schätzen.

17.06.2008 - 10:33 Uhr

Hrm, mal ganz ehrlich - ich denke die meisten haben irgendwann mal für nen bisschen Bares die ein oder andere Arbeit in der Jugend erledigt.

Als ich so 13-16 Jahre alt war, habe ich häufig durch einen Familiären Kontakt für Richter, Polizisten und Anwälte Computerkurse kleinere Anfängerkurse für den Umgang mit dem PC gehalten und kleine Homepages gebastelt und bekam dafür auch immer etwas Taschengeld.

Denke solange die Arbeit nicht einen gewissen Rahmen sprengt ist das sicherlich kein Problem 🙂

13.06.2008 - 15:41 Uhr

Ohman.. habs gefunden.

VS 2008 -> VisualStudio.DTE.9.0...
Hatte im Hintergrund nur VS2005 noch laufen...

13.06.2008 - 14:27 Uhr

Hallo Comminity,
ich habe folgendes, zurzeit Programmiere ich ein AddIn für MS Outlook, dafür verwende ich von einem Fremdanbieter einen AddIn Wrapper. Das ganze klappt auch wunderbar, nur habe ich folgendes Problem. Wenn das AddIn Regestriert wurde, kann ich nicht einfach Outlook als externes Startprojekt angeben (Start-Debug->External Programm) und in meinen Code rein zu debuggen. Das ganze funktioniert allerdings wenn ich mich an den Prozess anfüge (Attach To Process).

Nun hatte ich gedacht ich mache mir das ganze einfach indem ich einfach ein Windowsprogramm schreibe das über Proccess Outlook startet. Und via WMI mir ein Event sendet wenn Outlook wirklich da ist. Dann wollte ich mit einfach die Assembly reinladen von dem Outlook AddIn (Assembly.LoadFrom) und dann VS Studio einfach in den Prozess von Outlook einklinken.

Das einklinken funktioniert soweit, zumindest bekomme ich beim Versuch mich einzuklinken in Outlook den Hinweis das ich mich bereits auf dem Prozess befinde. Leider springt mir der Compiler dennoch auf keinen angelegten Breakpoint. Also, irgendwas läuft schief 🙂

Vielleicht hat ja jemand eine Idee woran es hapert.


		// outlook addin assembly
		Assembly info =	Assembly.LoadFrom(<Pfadname usw.. + *.dll>);
			
			PropertyData propertyData = e.NewEvent.Properties["TargetInstance"];

			if (propertyData != null)
			{
				ManagementBaseObject mbo = propertyData.Value as ManagementBaseObject;

				int id = Convert.ToInt32(mbo["ProcessId"]); // get current process id
				_Watcher.Stop(); // stops the wmi watcher

				EnvDTE80.DTE2 dte = (EnvDTE80.DTE2)Marshal.GetActiveObject("VisualStudio.DTE.8.0");

				EnvDTE.Processes procs = dte.Debugger.LocalProcesses;
				foreach (EnvDTE80.Process2 p in procs)
				{
					if (p.ProcessID == id) // check process id
					{
						p.Attach(); // p.Attach2("Managed"); 
						dte.Debugger.CurrentProcess = p; // attach to Outlook Process
						break;
					}
				}
			}
		}


Danke schon mal.
Gruß
Andi

13.06.2008 - 09:35 Uhr

Na ja, irgendwie habe ich so das Gefühl das es jetzt nur noch besser werden kann.
Die rote Karte ist so ne Sache, denke da hätte man davor auch mal durchgreifen können.

Aber dafür muntert einen SWR3 Morgens mit „Mir sin die wo gwinne welle!“ wieder auf 😉

12.06.2008 - 21:42 Uhr

Huch, der Fehler steckt manchmal im Detail 🙂

12.06.2008 - 16:23 Uhr

Finde das ganze schon okay - selbst wenn man das ein oder andere umschreibt könnte man kaum was verbessern. Irgendwie musst ja 0x41 0x41 zusammenführen zu 0xAA.

Denke das past schon.

12.06.2008 - 16:18 Uhr

Hallo Robert,
hatte leider grade etwas viel zu tun.

Mich verwirrt das BindingSource etwas.
Denn du bindest wie folgt:


his.schneelastzoneRmComboBox.DataSource = schneelastzone.GetSchneelastzonen();

Statt wie folgt:


this.schneelastzoneRmComboBox.DataSource = projectEntityBindingSource;

Dann sollte auch meineBindingSource.EndEdit() ohne weiteres gehen.

Ansonsten ist halt DataBinding immer Default DataSourceUpdateMode.OnValidation also so das änderungen erst dann gebunden werden wenn der Focus sich verändert.
Kannst dir auch das EndEdit() spaaren und es wie folgt erledigen:


this.schneelastzoneRmComboBox..DataBindings.Add("ValueMember", projectEntityBindingSource, "ValueMember", true, DataSourceUpdateMode.OnPropertyChanged);

this.schneelastzoneRmComboBox..DataBindings.Add("Text", projectEntityBindingSource, "DisplayMember", true, DataSourceUpdateMode.OnPropertyChanged);

Das ganze kann man sich auch im VS-Designer zusammenklicken 🙂
Falls es dennoch zu Problemen kommt, bräuchte ich etwas mehr Code.

/PS
DisplayMember und ValueMember entsprechen natürlich dann halt deinen Datenmember.

12.06.2008 - 11:24 Uhr

An was und wie hast du den deine Comboboc gebunden?

12.06.2008 - 11:02 Uhr

Hrm, ich glaube am besten kann das Microsoft selbst erklären 🙂

*Die kleinen Tricks und Kniffe liegen eigentlich immer bei der Namensgebung.
Steht irgendwo hWnd weist du, das hier ein Handle übergeben musst von z.b. einem Steuerelement, einer Form oder eines Controls usw.

*Wenn du Namen wie hwndCallback siehst, weisst du automatisch, ah hier muss der Funktionszeiger zurückgegeben werden.

*Großgeschriebene Namen wie TODO geben meistens an das es sich um eine Struktur oder ein Enum handelt. Wenn man Groß und Kleingeschriebene Namen ließt wie WindowsMessages weis man das es sich in der Regel nur um Enum’s handelt und nicht um Strukturen.

(* Edit: Eine Faustregel ist das ganze nicht!)

Wenn man sich unsicher ist wo man nun die genauen Strukturen oder Enum’s dann herbekommt und unter www.pinvoke.net nichts findet. So kann man anhand des DLL Namen ermitteln wo man genau nachschauen muss. Die user32.dll ist eine Client-DLL von Windows und somit weis man, ah ich muss für nähere Informationen also in der Windows API Dokumentation nachsehen was genau gebraucht wird. Wenn der Name irgendwie komisch sein sollte oder auf pinvoke nicht auffindbar so weis man das es sich evtl. um eine Fremde API handelt die z.B. dafür verwendet wird irgend etwas anzusteuern. Hier hilft dann die Dokumentation des Fremdanbieters weiter, oder der Kollege der vielleicht diese DLL geschrieben hat.

Natürlich kann es auch sein das beim Import einer DLL plötzlich mal „int hwndCallback“ oder gleich „delegate hwndCallback“ da steht, dennoch bleibt es ein Funktionszeiger – die Schreibweise kann somit also variieren genauso wie der Namen. Dennoch denke ich das in der Regel der Importname aus der Doku wie aus pinvoke in der Regel aussagekräftig genug ist um klar werden zu lassen, was man übergeben muss.

12.06.2008 - 10:15 Uhr

Du kannst die Anzeige auch via nen ToolTip relaisieren, wenn jemand über einen Datensatz der nicht komplett dargestellt wird drüber scroult wird einfach der Tooltext eingeblendet der diesen visualisiert.

12.06.2008 - 10:09 Uhr

Hrm, das muss so klappen.. ich habe ja deine DLL bzw. Programm nicht, aber habe das z.B so getestet:


			private delegate bool DelegBeep(uint iFreq, uint iDuration);

			[MarshalAs(UnmanagedType.FunctionPtr)]
			private static DelegBeep Beep;

			[DllImport("kernel32.dll")]
			private static extern IntPtr LoadLibrary(String dllname);
			[DllImport("kernel32.dll")]
			private static extern IntPtr GetProcAddress(IntPtr hModule, String procName);

			static void Main()
			{
				IntPtr hInst = LoadLibrary("Kernel32.dll");
				IntPtr hFunc = GetProcAddress(hInst, "Beep");
				Beep = Marshal.GetDelegateForFunctionPointer(hFunc, typeof(DelegBeep)) as DelegBeep;
				Beep(250, 250);
			}

Bist dir daher sicher das M12 wirklich in deinem Header drinne steht unter public?



public:
    void (*M12)();


Ansonsten schau dir das Project mal genauer an, das sollte das ganze besser aufzeigen. Es muss gehen, irgendwas stimmt da noch nicht - kann auch sein das ich wiedermal blind bin und es einfach nicht sehe 🙂

12.06.2008 - 09:32 Uhr

Hrm, die harte Methode wäre den WindowsStyle zu verändern, siehe dazu WIN API GetWindowLong und SetWindowLong.

Eine weitere Möglichkeit wäre eine neue Kalsse zu erstellen von dem gewünschten Control abzuleiten und über SetStyles z.B. die Zeichenroutine selbst in die Hand zu nehmen - das kann man z.B. dann über System.Windows.Forms.VisualStyles lösen.

Wieder ein anderer Weg wäre die WndProc zu überschreiben und via WIN API BeginPaint und EndPaint im der WM_PAINT Methode ebenso das Zeichenverhallten zu verändern - hier wird etwas anders gezeichnet, siehe dazu MSDN.

Dann kann man auch noch den Weg ohne die Zeichenroutine zu beinflussen gehen indem man vom gewünschten Control ableitet und via SetStyles das Mouseverhallten beeinflusst. So das unter umständen einfach der Cursor nicht mehr gesetzt werden darf und kann (da muss man etwas herumexperimentieren).

Aber egal welche Möglichkeiten verwenden möchtest, das Problem daran ist, es kostet einfach Zeit und Geduld und manipuliert eigentlich das Standardverhallten.

Würde wahrscheinlich eher dann ein eigenes Control dafür schreiben.

11.06.2008 - 18:03 Uhr

Phuuu... das müsste ich mir dann auch erstmal in aller Ruhe ansehen. Vielleicht findet derweil jemand anderes fix eine Lösung dafür.

Denke der Link könnte dir aber helfen selbst auf eine Lösung zu kommen.

11.06.2008 - 13:30 Uhr

Hrm, du wolltest also bei 0xAA das AA? also ca. wie folgt oder habe ich das falsch verstanden?


		[STAThread]
		static void Main(string[] args)
		{
			byte[] bytes = new byte[] { 0xAA, 0x48, 0x41, 0x4c, 0x4c, 0x4f };
			string[] hex = BytesToHex(bytes);

			StringBuilder sb = new StringBuilder(hex.Length);
			for (int i = 0; i < hex.Length; ++i)
			{
				sb.Append(HexToAsc(hex[i]));
			}

			// AAHALLO
			string mystring = sb.ToString();
		}

		private static uint mostSignificantBitPosition(uint n)
		{
			uint pos = 0;
			uint tmp;
			tmp = n >> 16;
			if (tmp != 0) { n = tmp; pos = pos + 16; }
			tmp = n >> 8;
			if (tmp != 0) { n = tmp; pos = pos + 8; }
			tmp = n >> 4;
			if (tmp != 0) { n = tmp; pos = pos + 4; }
			tmp = n >> 2;
			if (tmp != 0) { n = tmp; pos = pos + 2; }
			tmp = n >> 1;
			if (tmp != 0) { n = tmp; pos = pos + 1; }
			return pos + n - 1;
		}

		public static string HexToAsc(string str)
		{
			string[] hex = str.Split();
			string result = null;
			for (int i = 0; i < hex.Length; ++i)
			{
				uint n = Convert.ToUInt16(hex[i], 16);

				if (mostSignificantBitPosition(n)% 7 == 0)
				{
					result += hex[i].ToString();
				}
				else
					result += (char)n ;
			}
			return result;
		}

		public static string[] BytesToHex(byte[] bytes)
		{
			List<string> hex = new List<string>();
			for (int i = 0; i < bytes.Length; ++i)
			{
				hex.Add(bytes[i].ToString("X2"));
			}

			return hex.ToArray();
		}

LINK

@KenshinX
Jup, darüber bin ich auch schon gestolpert 😉

10.06.2008 - 17:36 Uhr

Hrm, hab irgenwie 5Mrd statt 5 mio gelesen...
4Bytes passt in dem Fall und mit int usw. haut alles hin.. irgendwie nicht mein Tag Heute.

Tjor, sehe den Fehler dann auch nicht.

10.06.2008 - 17:19 Uhr

statt
byte[] bytes = new byte[4];

sind es in anderen Games
byte[] bytes = new byte[8];

Auch wenn der "richtige" Wert angezeigt wird.

10.06.2008 - 17:00 Uhr

Ich glaube kaum das Photoshop via Entropie die Daten immer wieder neu visualisiert.
Zumindest wäre das ziemlich komplex auf dauer, für einfache Pinseleien die der Benutzer macht würde ich das ganze noch nachvollziehen können. Aber wenn Effekte rückgängig gemacht werden sollen, kann der Effekt als solches ja nicht nochmals in umkehrvor verwendet werden.

Angenommen der Effekt Weichzeichnen wird verwendet, so kann ich diesen Effekt nicht als umkehrfunktion (Starkzeichnen) Verwenden und das Bild sieht wieder aus wie zuvor.

Das Wort "immer" hätte ich allerdings weglassen sollen - es kommt wirklich darauf an, da stimme ich dir zu.

10.06.2008 - 14:39 Uhr

Da es sich um Anno 1602 handelt ists ja kein Ding zu Antworten 😉

Bist du dir sicher das die Adresse des Funktionszeigers (0x560264) stimmt?
Ansonsten, hast du überprüft ob der Stack wirklich nur 4 bytes groß ist? - 1.000.000 (2 Dwords) 8 Bytes in den meisten Games...

Ansonsten, schön und sauber - sehe wenn den Fehler nicht 🙂

10.06.2008 - 13:38 Uhr

Hallo Spontifixus,

versuch mal folgendes:


private void sendCommand () {

   msg = new RcppMessage();

   msg.versionReadWrite = 0x31;
   msg.action = 0x00;
   msg.reserved = 0x00;
   msg.clientId = ClientID;
   msg.sessionId = 0;
   msg.command = 0x0019;
   msg.dataType = 0x14;
   msg.num = 0;
   msg.payloadLength = 0;
   msg.payload = new byte[0];

   return ocxDisplay.SendRCP(new object[]{ msg});
}


Bei VARIANT ist halt immer blöd ohne dne zugrundeliegend C++ Code nachzusehen wie das SafeArray schlussendlich ausgelesen wird. Eine Kapselung wie m_rcppCommands= new RcppMessage[] { msg }; kommt mir aber spanisch vor, oder hatte der Hersteller das expleziet verlangt?

Wenn das nicht hinhaut denke ich eher das folgende snoch gemeint sein könnte:


private void sendCommand () {

   msg = new RcppMessage();

   msg.versionReadWrite = 0x31;
   msg.action = 0x00;
   msg.reserved = 0x00;
   msg.clientId = ClientID;
   msg.sessionId = 0;
   msg.command = 0x0019;
   msg.dataType = 0x14;
   msg.num = 0;
   msg.payloadLength = 0;
   msg.payload = new byte[0];

   return ocxDisplay.SendRCP(new object[]{ msg.versionReadWrite, msg.action, msg.reserved, msg.clientId,  msg.sessionId, msg.command, msg.dataType, msg.num, msg.payloadLength, msg.payload });
}


Ich hatte Variant mal für nen BITMAP ohne Headerdateien.. das sah dann so aus 😉


    public static object ConvertToVariantBitmap(Image img)
    {
      byte[] array = null;
      using (MemoryStream stream = new MemoryStream())
      {
        img.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
        stream.Position = 14; // rewind to non header information
        array = new byte[stream.Length - 14]; // remove bm header informations
        stream.Read(array, 0, (int)stream.Length - 14); // read non header informations
      }

      return array;
    }

10.06.2008 - 12:45 Uhr

Ah, da habe ich das falsch verstanden. Da eher Punkt 2.) nur noch etwas ausführlicher gegliedert.

Na würde sagen das folgende Commands dabei ausgeführt werden.
In einer Asgabe sähe das ca. wie folgt aus:

1 SelectCommand GrafischesObj 1 -> Serialize Grafische Ansicht - BubleEvent Bevore
2 SelectCommand GrafischesObj 1 -> Serialize Grafische Ansicht - BubleEvent After
3 SelectCommand GrafischesObj 2 -> Serialitze Grafische Ansicht - BubleEvent 4 Bevore
5 SelectCommand GrafischesObj 2 -> Serialitze Grafische Ansicht - BubleEvent After
6 SelectCommand GrafischesObj 3 -> Serialize Grafische Ansicht - BubleEvent Bevore
7 SelectCommand GrafischesObj 3 -> Serialize Grafische Ansicht - BubleEvent After
8 SelectCommand GrafischesObj 4 -> Serialize Grafische Ansicht - BubleEvent Bevore
9 SelectCommand GrafischesObj 4 -> Serialize Grafische Ansicht - BubleEvent After
10 GroupCommand List<CurrentSelectCommandItems> Array[] {GrafischesObj 1, GrafischesObj 2, GrafischesObj 3 , GrafischesObj 4}; -> Serialize Grafische Ansicht - BubleEvent Bevore
11 GroupCommand List<CurrentSelectCommandItems> Array[] {GrafischesObj 1, GrafischesObj 2, GrafischesObj 3 , GrafischesObj 4}; -> Serialize Grafische Ansicht - BubleEvent After
12 MoveCommand object -> Serialize Grafische Ansicht - BubleEvent Bevore
13 MoveCommand object -> Serialize Grafische Ansicht - BubleEvent After

Soo, was ist passiert.

Zuerst wurde das Grafische object selectiert die Ansicht wurde serialisiert wie sie unselectiert dann wie sie selectiert aussieht - daher BubelEvent Bevore und After Event. Dannach wird sich die Ansicht gemerkt wie sie vor dem gruppieren aussah, dann wie sie nach dem gruppieren aussieht. Zuletzt wird die Ansicht serialisiert bevor die Gruppierung das schlussendlich auch wieder nur irgend ein object hier vom Typ Array ist vor dem verschieben und im anschluss nach dem verschieben aussieht.

Schreib lieber viele Commands als wenige, das zahlt sich später aus. Lieber mal eine Komposition zuviel als zu wenige.

/PS
Sollte alles eigentlich BubbleEvent heissen.. bin zu Faul das nun zu korrigieren 😉

10.06.2008 - 11:33 Uhr

Hrm, das kommt ganz darauf an.

1.) Eine einzelne Liste wäre für Undo / Redo ausreichend also sprich das Makro-Command reicht. Stell dir dazu einfach wieder Adobe Phoroshop vor. GUi Technisch würdest du evtl. 5 mal Move-Command sehen und vielleicht 3 mal ein anderes Command usw. Jedes Command würde einzeln dastehen in einer für den Benutzer ersichtlichen und logischen Reihenfolge.

2.) Wenn du jede Aktion mit einer Liste versiehst bräuchtest (Move-Command) sähe das wie folgt aus. Du hättest eine Liste mit allen Command's also Move-Command und andere Commands die du so hast. Wenn man nun Move-Command anklickt sieht man zwar in einer logischen reihenfolge die einzelnen Move-Commands. Aber man würde nicht mehr sehen wurde zuerst Move-Command ausgeführt oder irgend ein andere Command. Hier hätte der Benutzer selber keine Chance mehr zu verstehen was er rückgängig machen müsste um seine z.B. letzte Aktion rückgängig zu machen.

Wenn kein UI Pflegst und kein Undo / Redo direkt verwenden möchtest für den Benutzer ersichtlich its, wäre es egal was du machst - hier käme es darauf an was dein Programm den mit der Liste anstellt. Ansonsten rate ich dir lieber zu Punkt 1.) - denn in den meisten Fällen tut's das allemale und selten muss man innerhalb eines Commands eine einzelne Aktion rückgängig machen bzw. wiederherstellen.

Vorallem wenn eh das ganze zu behandelnde Object serialisierst. Denk dran, eine Singleton wird sogut wie immer beim CommandPattern gebraucht, dort hast du dann auch deine Macro-Liste.

10.06.2008 - 10:12 Uhr

Hrm, beim CommandPattern sollten immer alle Daten Redundant gespeichert werden. Spätestens beim Undo/Redo, wenn dir Adobe Photoshop mit den Aktionen vorstellst, dort hast ja ebenso die Möglichkeit zu sagen ich möchte von Aktion 20 alle Rückgängigmachen bis wieder hin zu aktion 15. Und somit macht es Sinn wirklich alle Daten wie bei dir nun End + Startposition zu merken. Der Witz am CommandPattern ist ja das es so erweitenr kannst wie du Lust hast. Du könntest dir statt nur Punkte wie X und Y vom Start wie Endpunkt zu merken das gesammte Object als solches merken z.B. via Serialisierung. Der Vorteil hierbei wäre, selbst wenn du Vorhast zusätzliche Aktionen einzubauen könntest du beim Undo / Redo direkt auf das gewählte Undo / Redo Command hin und herspringen ohne das irgendwelche Berechnungen anfallen oder Commands die dazwischen lagen / liegen wiederholt ausführen musst.

09.06.2008 - 15:37 Uhr

Bei mir ist es eher ein klares nein.
Natürlich erstelle ich gerne wenn ich viel Zeit habe mal ein kleines Probeprojekt um mir etwas genauer anzusehen, nur ist das eher selten der Fall. Was Litaratur angeht so verhällt sich das bei mir sporadisch, lese gerne und relativ viel - nur nicht eben immer ein Programmierbuch.

09.06.2008 - 13:00 Uhr

Hrm, hatte vor kurzen ein ähnliches Project. Habe das über TAPIEx gelöst und war mit deren Anbindung wirklich zufrieden. Das ganze ist allerdings nicht kostenlose.

09.06.2008 - 12:51 Uhr

Hrm, hol dir das Modulhandle mal wie folgt.



        [DllImport("kernel32.dll", CharSet=CharSet.Auto)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("kernel32.dll")]
        private static extern IntPtr GetProcAddress(IntPtr IntPtr_Module, string csProcName);

        [DllImport("kernel32")]
        private static extern IntPtr LoadLibrary(string lpFileName);

        private delegate void myFunctionDelegate();
        private myFunctionDelegate Invoke = MyFunction();

        public void DoIt()
        {
             Invoke();
        }

        private static myFunctionDelegate MyFunction()
        {
            Process proc = Process.GetProcessesByName("CA123A")[0]; // process CA123A.exe
            IntPtr hMod = LoadLibrary(proc.MainModule.FileName); // das module handle in der sich die M12 funktion befindet.
            IntPtr hFunction = GetProcAddress(hMod, "M12"); // M12 nach deinem code die void* Methode im C++ Code

            return Marshal.GetDelegateForFunctionPointer(hFunction, typeof(myFunctionDelegate)) as myFunctionDelegate;
        }


Sorry, wie gesagt mehr als Try & Error kann ich da auch nicht vorschlagen - wenn das nicht geht, gib bescheid.

07.06.2008 - 02:19 Uhr

Hrm, heimgehen ist eine gute Idee.
Und falls nächste Woche langweile aufkommt, im Forum gibt es immer Suchende die sich über des anderen langweile freuen 😮)

07.06.2008 - 02:13 Uhr

Hrm, die Idee ist gut und wirst lachen verwende diese auch Schnueggel. Man kann das ganze weiter treiben indem man hier mit XML arbeitet und von aussen her diese sogar bearbeiten kann und sich bisherige Einstellungen sogar merkt. Nur was ich leider nicht bewerten kann ist dann gleich eine Umsetzung via WPF - habe damit einfach noch keine Erfahrung.

07.06.2008 - 01:59 Uhr

Hrm... ohne WIN API habe ich dir sonst leider keine Idee.

Der andere Weg wäre über einen globalen LowLevelMouse Hook gewesen, hier kann man dann beim MouseMove einfach nen Bild oder Abbild als GostImage zeichnen. Nur ob das Performanter ist als die Lösung von codeProject, bezweifle ich.

Vielleicht kennt jemand ja noch einen reinen .NET Weg - aber ist this.Cursor.Draw() ebenso auf 250px beschränkt?

07.06.2008 - 01:42 Uhr

Das ganze sieht in etwa wie folgt aus.


        [DllImport("kernel32.dll", CharSet=CharSet.Auto)]
        public static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("kernel32.dll")]
        static extern IntPtr GetProcAddress(IntPtr IntPtr_Module, string csProcName);

        private delegate void myFunctionDelegate();
        private myFunctionDelegate Invoke = MyFunction();

        public void DoIt()
        {
       
            Invoke();
        }

        private static myFunctionDelegate MyFunction()
        {
            IntPtr hMod = GetModuleHandle("CA123A.exe"); // das module handle in der sich die M12 funktion befindet.
            IntPtr hFunction = GetProcAddress(hMod, "M12"); // M12 nach deinem code die void* Methode im C++ Code

            return Marshal.GetDelegateForFunctionPointer(hFunction, typeof(myFunctionDelegate)) as myFunctionDelegate;
        }

Wie gesagt bei deinem Problem kann ich nur via Try & Error an den Fall dran gehen eine "dieser Weg funktioniert garantiert" Lösung kann ich dir nicht geben. Wenn das nicht klappt geb bescheid, dann muss ein anderer Lösungsweg gefunden werden. Also keine übergabe via WndProc oder SendMessage - ich würde dir gerne den Unterschied erklären, leider fehlt mir dafür das KnowHow 😮)

06.06.2008 - 17:48 Uhr

Hallo Schnueggel 😉

Auf Codeproject wird man für soetwas immer fündig.

06.06.2008 - 15:05 Uhr

Hrm, es ist Freitag und ich sitze vielleicht auf dem Schlauch aber wo ist das Problem?



List<GeometrischeForm > formList = new List<GeometrischeForm >();

Dreieck[] listDreiecke = formList.FindAll(delegate(GeometrischeForm geoform) { return geoform is Dreieck; });

Quadrat[] listQuadrate = formList.FindAll(delegate(GeometrischeForm geoform) { return geoform is Quadrat; });


06.06.2008 - 14:29 Uhr

@talla

Das bezog sich auch nicht auf den Thread sondern nur auf das von JAck30lena gepostete 🙂

@spongebob

Okay, das hätte ich zu aller erst auch mal versucht klar wird aber durch die Fehlermeldung dass das nicht alles ist. Die reine übergabe des Funktionszeigers reicht ja nicht aus, nun kommt ja der Fehler den Talla und JAck30lena meinten.

Hrm, versuch mal folgendes hol dir den Funktioszeiger nicht über die WndProc sondern direkt aus dem Fremdmodul, das kannst du über die WIN API GetModuleHandle und den Funktionszeiger via GetProcAddress holen.

Wenn das nicht hinhaut kann man noch nen paar andere Schritte angehen.

06.06.2008 - 13:33 Uhr

ja aber reinschreiben in irgendwelche speicherbereiche ist etwas anderes als eine funktion aufzurufen. oder irre ich mich hierbei?

Hrm... sagen wir es so reinschreiben ist relativ - erinnere dich wie ein Trojaner Funktioniert. Da wird das ganze insofern ins absurdum geführt da man hier Code in den Speicherbereich eines fremden Prozesses schreibt. Das geht indem man ja eine DLL in einem fremden Adressraum reinfriemelt und diese dann eine z.B. eine angegebene Funktion ausführt. Der Wichtigste Punkt hierzu ist das Verständniss von Zeigern, diese sind Variablen und Variablen werden auf dem Stack gespeichert und sind somit also relativ.

Wie das geht steht naja fast schon in diesen Thread, nur mehr schreibe ich erstmal dazu nicht rein, nur soviel Trojaner sind nicht zwangsläufig etwas böses sondern eigentlich viel mehr Dirty-Trick Lösungen für vermurkste Programme - daher kenne ich zumindest die Grundlagen 😉

06.06.2008 - 13:12 Uhr

Hrm, sicher bin ich mir auch nicht aber via

     
            IntPtr hMod = LoadLibrary(@"C:\MyLib.dll");
            IntPtr hFunction = GetProcAddress(hMod, "MyFunction");

wie beim ersten Thread (wo es schlussendlich zwar um DLL's als Resourcen geht) wird ja der Funktionszeiger ebenso aus dem entsprechenden Adressraum geladen.

Aber du hast recht Talla die Rahmenbedingungen müssen stimmen, ich weis jetzt nicht wie spongebob an den Funktionszeiger kommt, wenn er aber nicht innerhalb seiner eigenen Prozedur ist so muss er sich über GetProcAddress zutritt verschaffen und kann dazu auch GetModuleHandle verwenden um z.B. von einem bestehenden Programm sich eine Funktion / Methode zu "erklauen".

Müsste um genauere Aussagen dazu machen zu können das ganze Testen, leider fehlt da etwas die Zeit.

Denk nur dran, für den ersten Test, das delegate muss via Invoke aufgerufen werden, genauso müssen die verwendeten Parameter und deren Datentypen genau die selben sie wie für die Funktion auf die der Funktionszeiger zeigt.

06.06.2008 - 12:47 Uhr

Fragen ist ja keine Schande und gebe zu hatte damals grade in diesen Bereich vorallem bei Bitoperatoren wahnsinnige Schwierigkeiten - da Hilft nur Erfahrungen sammeln

06.06.2008 - 12:45 Uhr

Hrm, das hinzufügen funktioniert z.b. über einen ButtonEvent indem dort die Methode LoadControl aufrufst. Um herauszufinden welches dein aktuell angezeigtes UserControl ist findest du über <myPanel>.Controls[] heraus indem nach ILoad (UserControl) suchst. Du kannst es dir auch beim Methodenaufruf von LoadControl global merken - das ist dir überlassen.

Wenn du das ganze allerdings im Designer machen möchtest, kannst du auch ein HauptUserControl erstellen das als Property eine Liste von ChildUserControls vom Typ ILoad beinhaltet zur verfügung stellen und diese zur Laufzeit im Designer hinzufügen. Das Editieren geht so allerdings nicht - möglich ist es aber ganz ehrlich das kostet Zeit und die erklärung dazu würde hier einige Seiten verbrauchen. Sieh dir dazu bei den CodeSnippeds und auf der MSDN Seite alles rund um das Thema Designer Support Laufzeitunterstüzung Komponenten wie den ganzen Schnittstellen an und vorallem die WindowsNachrichten. Da müsstest überall drin rumfummeln damit einen Wizzard als Komponente später zur Laufzeit mit Designersupport zur verfügung hast.

Wenn es als Projekt hier reinstellen möchtest, gebe ich dir gerne weitere Tipps. Nur für eine normale Lösung lohnt sich der Aufwand nicht.

[Edit]
JAck30lena war schneller 😮)

06.06.2008 - 12:29 Uhr

Also Prinzipiel schon...

Siehe dazu am besten MSDN Marshal.GetDelegateForFunctionPointer bzw. diesen Thread da gehts zwar um DLL's in Resourcen der Weg ist aber der selbe zumindets bei dem Codebeispiel von mir. Ansonsten, glaube dieser Thread könnte dir auch enorm weiter helfen.

Es ist nen bissel rumgefrimel dabei, da kommst nicht drum herum.

[Edit] Bin zu blöd die Links richtig reinzukopieren grummel

06.06.2008 - 12:19 Uhr

Hrm, fürchte da musst etwas genauer werden - du redest von einem Funktionszeiger ?
Also zum Beispiel in C++ ein void* ?

06.06.2008 - 11:29 Uhr

Hrm, hatte das bisher wie folgt gemacht:


		[STAThread]
		static void Main(string[] args)
		{
			byte[] bytes = new byte[] { 0x48, 0x41, 0x4c, 0x4c, 0x4f };
			string[] hex = BytesToHex(bytes);

			StringBuilder sb = new StringBuilder(hex.Length);
			for (int i = 0; i < hex.Length; ++i)
				sb.Append(HexToAsc(hex[i]));

			// HALLO
			string mystring = sb.ToString();
		}

		public static string HexToAsc(string str)
		{
			string[] hex = str.Split();
			string result = null;
			for (int i = 0; i < hex.Length; ++i)
				result += (char)Convert.ToUInt16(hex[i], 16);
			return result;
		}

		public static string[] BytesToHex(byte[] bytes)
		{
			List<string> hex = new List<string>();
			for (int i = 0; i < bytes.Length; ++i)
				hex.Add(bytes[i].ToString("X2"));

			return hex.ToArray();
		}

/PS
++i ist nur nen dreher, warum ich das manchmal so tippsle weis ich nicht🙂

06.06.2008 - 10:47 Uhr

Hrm, es gibt auch andere Lösungsansätze dafür.

Erstmal der allgemeine Workaround: Über die Windowsnachricht WM_ERASEBKGND kann man den Hintergrund von (fast) allen Controls beeinflussen. Hierzu ist es wichtig das man sich allerdings auf der richtigenen Ebene befindet zum zeichnen da es sonst zu den genannten schliereneffekten kommt. Der Vorteil über die WindowsNachricht das ganze zu triggern ist, das man nur eine Zentrale stelle für den Aufruf der Zeichenroutine hat und nicht mehrere.


        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case (int)Win32.WindowsMessages.WM_ERASEBKGND:
                    {
                        this.WmPaintBkgnd(ref m);
                        break;
                    }
                default:
                    {
                        base.WndProc(ref m);
                        break;
                    }
        }

        private void WmPaintBkgnd(ref Message m)
        {
            base.WndProc(ref m);

            this.PaintBkgndArea(m.HWnd, m.WParam);
            m.Result = Win32.TRUE;
        }

       private void PaintBkgndArea(IntPtr hWnd, IntPtr hRgn)
        {
            if (this.m_bUseSkinBackColor)
            {
                Win32.RECT rWnd = new Win32.RECT();
                if (Win32.GetClientRect(hWnd, ref rWnd) == 0) // the small but fine difference betweem client area and non client area :-)
                    return;

                Rectangle rClip = new Rectangle(0, 0, rWnd.Width, rWnd.Height);

                if (hRgn == Win32.FALSE) return;

                using (Graphics g = Graphics.FromHdc(hRgn))
                {
                    this.OnClientBkgndAreaPaint(new PaintEventArgs(g, rClip));
                }
            }
        }


        public void ClientBkgnInvalidate()
        {
            IntPtr hdc = Win32.GetDCEx(this.Handle, IntPtr.Zero, (uint)(Win32.DeviceContextValues.ClipChildren
                | Win32.DeviceContextValues.Cache
                | Win32.DeviceContextValues.ClipSiblings));
            this.PaintBkgndArea(this.Handle, hdc);
        }

Natürlich wäre es nun zu komplex jedes Control für das man die Hintergrundfarbe ändern möchte die WndProc zu überschreiben. Hier kann man relativ einfach eine Komponente erstellen die zusätzlich die Schnittstelle IExtenderProvider implementiert (siehe hierzu MSDN). Anhand der Liste der verfügbaren Controls innerhalb der Komponente kann man nun Subclassing betreiben, das geshcieht am einfachsten über NativeWindow.

Z.B. wie folgt:


    public class MySubClass : NativeWindow
    {
        public SkinUtil(IntPtr _hWnd)
        {
            base.AssignHandle(_hWnd);
        }

        protected override void WndProc(ref Message m)
        { 
          ///... siehe code oben
        }
    }

Kannst dir auch mal die UtilitiesLib von mir ansehen. Bzw. die Klassen UtilitiesLib.Skins.Components.SkinForms (Komponente) und die SubClass UtilitiesLib.Skins.SkinUtil. Mache dort nichts anderes.

06.06.2008 - 09:53 Uhr

Tut mir leid hatte gestern nicht mehr reingeschaut.

Aber hast den Fehler ja selbst bemerkt, GUI Elemente von Thread's sollte man via Control.Invoke bzw. Control.BeginInvoke ansprechen, wie es bei der Funktion SwitchButton() passiert 🙂

06.06.2008 - 09:47 Uhr

Ein sauberer Weg wäre tatsächlich die Controls in eine Liste zu packen, doch das reicht nicht aus. Durch eine gemeinsame Schnittstelle werden die jeweiligen Controls sauberer implementiert - das hat den Sinn das nur eindeutige Controls rein geladen werden und nicht "irgendwelche".


    public enum ControlTypes
    {
      None = 0,
      ControlA,
      ControlB
    }

    public interface ILoader
    {
      ControlTypes ControlType { get;}

      void Load(Control parent);
    }

    public class UserControlA : UserControl, ILoader
    {

      #region ILoader Members

      public ControlTypes ControlType
      {
        get { return ControlTypes.ControlA; }
      }

      public new void Load(Control parent)
      {
        this.Parent = parent;
        this.Show();
      }

      #endregion
    }

    public class MyWizzard : Form
    {
      private ILoader[] List = new ILoader[] { new UserControlA() };

      public bool LoadControl(ControlTypes _eControlTypes)
      {
        ILoader iLoad = Array.Find<ILoader>(this.List, delegate(ILoader load)
        { 
          return load.ControlType == _eControlTypes;
        });

        if(iLoad == null) return false;

        iLoad.Load(<MyPanelControl>); // hier halt das Panel
        return true;
      }
    }

Disposen / Close sollte man nach dem gebrauch nicht gleich aufrufen, da man schließlich auch wieder einen Step zurückgehen kann und die bisherigen Einstellungen sollen ja wieder erscheinen.

Meistens nutze ich dafür aber nen TabControl, lege das Ding vertikal und schalte die TabPages dann Step by Step frei. Sieht meistens etwas hübscher aus als einfach nur UserControls.