|
every c#'s object like a pointer in c++. But How can i get a pointer point to pointer (**) in c#?
I just work on a undo/redo engine in my c# application.
For example, there is two type of object to be edit in application
class A
{
string aa;
}
class B
{
int bb;
}
The edit operation change the many objects of type A or type B.
I hope to build a stack of object to store the string aa and int bb. Two objects to be cloned, one before the edit operation, another after it.
If the only way to change a memeber of a object is xx.yy = zz, i find it impossible to do the undo. Because i have to know the parent object (A or B) and which type of it (A or B) and judge in code whether to use aa or bb.
I doubt whether reflection ability in c# can help me.
But in c++ style, it is very easy to use object*. something like
*orgin = cloneBefore
or
*orgin = cloneAfter
Do i make some mistake? Please give me some suggestion!!
or any undo/redo engine written by c# or java in the world?
|
|
|
|
|
|
I think you can get the same behavior by simply creating a class to hold your object reference. You would declare instances of that rather than object*, and then you'll be able to look inside your class and change the reference.
|
|
|
|
|
Yes, I think what you said is what i really want to do.
I need to bypass class A to access item aa in such an engine. But don't know whether c# permit it or not.
class A
{
string aa;
}
A someA;
someA.aa = "...";
In function calling, we can use "ref" keyword to have the object reference.
something like:
CallingFunc(ref someA.aa);
But i dont know how to store the object reference. "ref" seems only be used in calling parameters.
like:
store[i] = ref someA.aa ?
Can you show me some simple demo?
Thanks!!
|
|
|
|
|
You'd need to write a class like:
class ObjectReference
{
public object reference; // this could be a property if you wanted...
}
Then, whenever you create something that needs to be undo-able, you wrap it in one of these objects and store the reference to ObjectReference.
Note that this is going to make your code pretty ugly, as you'll have to cast from object to the real type whenever you use an object.
|
|
|
|
|
You should look into using the Command Pattern[^] to create a undo/redo framework.
|
|
|
|
|
Hi all,
I desperately need a hint guiding me the right direction...
I want to retrieve the NCM information using SystemParametersInfo. Well, to define the function call is rather easy, and the structure itself does not make lots of problems, too:
[StructLayout(LayoutKind.Sequential)]
public class NONCLIENTMETRICS
{
public int cbSize;
public int iBorderWidth;
public int iScrollWidth;
public int iScrollHeight;
public int iCaptionWidth;
public int iCaptionHeight;
public LOGFONT lfntCaptionFont;
public int iSMCaptionWidth;
public int iSMCaptionHeight;
public LOGFONT lfntSMCaptionFont;
public int iMenuWidth;
public int iMenuHeight;
public LOGFONT lfntMenuFont;
public LOGFONT lfntStatusFont;
public LOGFONT lfntMessageFont;
public NONCLIENTMETRICS()
{
cbSize = 340;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct LOGFONT
{
public int lfHeight;
public int lfWidth;
public int lfEscapement;
public int lfOrientation;
public int lfWeight;
public byte lfItalic;
public byte lfUnderline;
public byte lfStrikeOut;
public byte lfCharSet;
public byte lfOutPrecision;
public byte lfClipPrecision;
public byte lfQuality;
public byte lfPitchAndFamily;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst=32)]
public string lfFaceName;
public static LOGFONT Empty
{
get
{... }
}
}
[DllImport("User32.dll"]
public static extern bool SystemParametersInfo(int Action, int Param, NONCLIENTMETRICS Param, int WinIni);
The call is
NONCLIENTMETRICS ncm = new NONCLIENTMETRICS();
bool b = SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, ncm, 0);
And now I'm getting confused:
b is true, that means the call succeeded, but ncm has not been touched. Is there anything wrong with the structure layout?? At the end I tried all combinations, instead of a class I declared NCM as a structure and used ref, I tried the IntPtr version... nothing didn't help. And I know that it works since MS does similar to build the SystemInformation members (Menufont is contained in NCM, too).
Somewhere I'm blocked. Can anybody help??
Thanks and bye
Matze
|
|
|
|
|
Matze wrote:
public NONCLIENTMETRICS()
{
cbSize = 340;
}
arrrg! Replace with
cbSize = Marshal.SizeOf(this);
Matze wrote:
DllImport("User32.dll"]
public static extern bool SystemParametersInfo(int Action, int Param, NONCLIENTMETRICS Param, int WinIni);
The call is
NONCLIENTMETRICS ncm = new NONCLIENTMETRICS();
bool b = SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, ncm, 0);
The declaration and method calls doesnt match! Why are you passing ncm.cbSize. Some functions however need to be called twice. 1st to find out what size parameter they need, 2nd the actuall call. this mite be the case. See if values from other paramters change during the call.
Hope this helps
DBHelper - SQL Stored Procedure Wrapper & Typed DataSet Generator for .NET low popularity, please visit
|
|
|
|
|
Hi leppie,
thanks for the answer!
leppie wrote:
bool b = SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, ncm, 0);
The declaration and method calls doesnt match! Why are you passing ncm.cbSize. Some functions however need to be called twice. 1st to find out what size parameter they need, 2nd the actuall call. this mite be the case. See if values from other paramters change during the call.
Hmm, the documentation states that for the GETNONCLIENTMAETRICS action the size of NCM must be told as second parameter, that's why I passed it (and so does MS, as one can see in the Decompiler;)). Actually, when I pass anything else than 340 (==Marshall..;)) the function returns false. No values are changed, unfortunately
leppie wrote:
public NONCLIENTMETRICS()
{
cbSize = 340;
}
arrrg! Replace with
cbSize = Marshal.SizeOf(this);
Yepp, of course I did this, but I thought a number is more informative in the message
|
|
|
|
|
Replace the DllImport declaration with :
[DllImport("User32.dll")]
public static extern bool SystemParametersInfo(int Action,
int Param,
IntPtr lpParam,
int WinIni);
And replace the method call with :
const int SPI_GETNONCLIENTMETRICS = 41;
NONCLIENTMETRICS ncm = new NONCLIENTMETRICS();
int size = ncm.cbSize = Marshal.SizeOf(typeof(NONCLIENTMETRICS));
IntPtr pncmetrics = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(ncm, pncmetrics, true);
bool b = SystemParametersInfo(SPI_GETNONCLIENTMETRICS, size, pncmetrics, 0);
Marshal.PtrToStructure(pncmetrics,ncm);
Marshal.FreeHGlobal(pncmetrics);
The .NET 1.0 marshaller has some troubles when it comes to marshalling LPStruct. Hopefully, this will be fixed in 1.1 (may be someone using the Everett beta could tell us whether it is fixed or not).
|
|
|
|
|
Hi Rod,
thanks a lot, that sounds feasible. Will give you immediate feedback today evening when I'm back from the customer..
Bye
Matze
|
|
|
|
|
Oh whow, you are my hero - it works!! Yipppieeeehh!!! You made my day, no, my month;) How for heavens sake did find that out???
Thanks and bye
Matze
|
|
|
|
|
|
Option 2:
- Change the
NONCLIENTMETRICS to a struct (NB: You'll have to remove the constructor.) - Change the declaration to:
[DllImport("User32.dll")]
public static extern bool SystemParametersInfo(int Action,
int uiParam, ref NONCLIENTMETRICS pvParam, int WinIni); - Change the call to:
NONCLIENTMETRICS ncm = new NONCLIENTMETRICS();
ncm.cbSize = Marshal.SizeOf(ncm);
bool b = SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
ncm.cbSize, ref ncm, 0);
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
|
|
|
|
|
Hi Richard,
this was my very first try, before I changed NCM to a class (and before I read any documentation;)). The call succeeds, too, but NCM remains at its initial state...
Referring to leppie I would prefer this method, too, since it's much more NET like. Does this call succeed on your machine?
Thanks and bye
Matze
|
|
|
|
|
Here's the code I used, and the output on my XP Pro machine:
using System;
using System.Runtime.InteropServices;
class App
{
[StructLayout(LayoutKind.Sequential)]
public struct LOGFONT
{
public int lfHeight;
public int lfWidth;
public int lfEscapement;
public int lfOrientation;
public int lfWeight;
public byte lfItalic;
public byte lfUnderline;
public byte lfStrikeOut;
public byte lfCharSet;
public byte lfOutPrecision;
public byte lfClipPrecision;
public byte lfQuality;
public byte lfPitchAndFamily;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
public string lfFaceName;
}
[StructLayout(LayoutKind.Sequential)]
public struct NONCLIENTMETRICS
{
public int cbSize;
public int iBorderWidth;
public int iScrollWidth;
public int iScrollHeight;
public int iCaptionWidth;
public int iCaptionHeight;
public LOGFONT lfntCaptionFont;
public int iSMCaptionWidth;
public int iSMCaptionHeight;
public LOGFONT lfntSMCaptionFont;
public int iMenuWidth;
public int iMenuHeight;
public LOGFONT lfntMenuFont;
public LOGFONT lfntStatusFont;
public LOGFONT lfntMessageFont;
}
[DllImport("User32.dll")]
public static extern bool SystemParametersInfo(
int Action, int uiParam,
ref NONCLIENTMETRICS pvParam, int WinIni);
static void Main()
{
const int SPI_GETNONCLIENTMETRICS = 41;
try
{
NONCLIENTMETRICS ncm = new NONCLIENTMETRICS();
ncm.cbSize = Marshal.SizeOf(ncm);
bool b = SystemParametersInfo(
SPI_GETNONCLIENTMETRICS,
ncm.cbSize, ref ncm, 0);
if (b)
{
Console.WriteLine("Border Width: {0}",
ncm.iBorderWidth);
Console.WriteLine("Scroll Width: {0}",
ncm.iScrollWidth);
Console.WriteLine("Caption Font: {0}",
ncm.lfntCaptionFont.lfFaceName);
}
else
Console.WriteLine("Failed");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
} Output:
Border Width: 1
Scroll Width: 17
Caption Font: Trebuchet MS
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
|
|
|
|
|
Hi Richard,
sorry for answering much too late, had the dog tapdancing on my desk...
I tried your code on my two XP machines, and the strange thing is:
- it did not work on the machine with XP freshly installed
- it worked on the machine I have upgraded from W2K
?!?!? Looks like MS alive;)
If I have the time to explore this and find the reason I'll let you know waht happens here; in the meantime I use Stephane's hint, this works on both machines.
Thanks a lot again for your effort, have a nice christmas!
Bye
Matze
|
|
|
|
|
|
I have one too! MYrc on SF
I suggest you use the excellenct Thresher lib for the protocol implementation!
Hope this helps
PS: This have been done too many times.
Shock The Dark Mage wrote:
The VS.NET Debugger raise an exception saying that I can't modify an control(Crownwood.Magic.Controls.TabControl) created in another thread.
Had similar problem. You need to invoke the method that creates new tabs instead of calling it directly!
DBHelper - SQL Stored Procedure Wrapper & Typed DataSet Generator for .NET low popularity, please visit
|
|
|
|
|
Can't help you directly - but since you are using the dotnet magic library you could always ask the author - He is a nice man I've worked with him and in the end if he says no then you will be no worse off
Stupidity dies.
The end of future offspring.
Evolution wins.
- A Darwin Awards Haiku
|
|
|
|
|
Shock The Dark Mage wrote:
The VS.NET Debugger raise an exception saying that I can't modify an control(Crownwood.Magic.Controls.TabControl) created in another thread.
I had this problem in my app but I figured out how to fix it.
If you want to modify a control or add a control to a form in other thread the exception will be thrown.
My solution is to use the SendMessage function to move the execution process from one thread to the other. Use DllImport to be able to call it in your code.
SendMessage( hHandle, WM_USER + 1, 0, 0 );
hHandle is the window's handle you want to send a message to
WM_USER + 1 is the message that the main form will receive.
In the main thread you must have a form ( whose handle you passed to SendMessage ). Override the WndProc method
public virtual void WndProc( Message* m )
{
if ( m->Msg == WM_USER + 1 )
{
}
}
43 68 65 65 72 73 2c
4d 69 63 68 61 65 6c
|
|
|
|
|
|
Thanks for yours solutions but none worked.
Here the function(in MainForm) that add a new tabpage in TabControl
<br />
public void AddTabPage(string name, TabType type)<br />
{<br />
Crownwood.Magic.Controls.TabPage addedtab = new Crownwood.Magic.Controls.TabPage(name);<br />
switch(type)<br />
{<br />
case TabType.Status:<br />
TemplateStatusWindow status = new TemplateStatusWindow(this.m_connection);<br />
addedtab.Control = status;<br />
break;<br />
case TabType.Channel:<br />
TemplateChannelForm channel = new TemplateChannelForm(name, this.m_connection);<br />
addedtab.Control = channel;<br />
break;<br />
}<br />
addedtab.Tag = type;<br />
addedtab.Name = "tab"+name;<br />
int index = 0;<br />
if(this.TabChannels.TabPages.Count == 0)<br />
{<br />
this.TabChannels.TabPages.Add(addedtab);<br />
}<br />
else<br />
{<br />
System.Windows.Forms.MessageBox.Show(System.Threading.Thread.CurrentThread.Name.ToString());<br />
index = this.TabChannels.TabPages.Count;<br />
this.TabChannels.TabPages.Insert(index, addedtab);<br />
}<br />
<br />
}<br />
Here is the function called from IRCParser in IRCConnection
<br />
public void CreateChannelTabPage(string name)<br />
{<br />
m_parent.AddTabPage(name, TabType.Channel);<br />
}<br />
And finnaly, the function that invoke all the chain in the Thread ReceiveThread
<br />
private void cmd331(string[] args)<br />
{<br />
if(args[2].IndexOf("#")>-1 || args[2].IndexOf("&")>-1)<br />
{<br />
string msg = JoinString(args, 3, args.Length);<br />
msg = msg.Replace(":", "");<br />
#if Terminal<br />
connection.Received("*** No topic set in "+args[2]+crlf);<br />
#elif MainForm<br />
connection.ReceiveTo("Status", "*** No topic set in "+args[2]+crlf, Color.Red);<br />
#endif<br />
}<br />
else<br />
{<br />
#if Terminal<br />
connection.Received("*** You have joined "+args[3]+crlf);<br />
#elif MainForm<br />
connection.CreateChannelTabPage(args[3]);<br />
#endif<br />
}<br />
}<br />
Hope this will you help you to help me ^_^
Trully, if there evil in this world, It lies within the heard of mankind
Shock The Dark Mage
shock@romhack.net
Main Project: Aeru IRC - http://www.sf.net/projects/aeruirc
|
|
|
|
|
Shock The Dark Mage wrote:
public void CreateChannelTabPage(string name)
{
m_parent.AddTabPage(name, TabType.Channel);
}
change this to:
public void CreateChannelTabPage(string name)
{
if (m_parent.InvokeRequired)
{
m_parent.Invoke(m_parent.AddTabPage, name, TabType.Channel);
}
else m_parent.AddTabPage(name, TabType.Channel);
}
Now as you can see, you will invoke the method if needed else it will be called directly.
Cheers
DBHelper - SQL Stored Procedure Wrapper & Typed DataSet Generator for .NET popularity better now, thank you
|
|
|
|
|
Thanks leppie. Now it's work. Your code need another thing. You need to declare a delegate because Invoke method require a delegate.
In MainForm:
public delegate void AddingChannelTab();
New create CreateChannelTabPage function.
<br />
public void CreateChannelTabPage(string name)<br />
{<br />
if (m_parent.InvokeRequired) <br />
{ <br />
try<br />
{<br />
m_parent.ChannelToAdd = name;<br />
AeruIRC.MainForm.AddingChannelTab addingchannel = new AeruIRC.MainForm.AddingChannelTab(m_parent.AddTabPage2);<br />
m_parent.Invoke(addingchannel); <br />
}<br />
catch(Exception ex)<br />
{<br />
MessageBox.Show(ex.Message);<br />
}<br />
} <br />
else <br />
m_parent.AddTabPage(name, TabType.Channel);<br />
}<br />
The only problem is invoking the delegate with parameters. But now, I call a function without parameters. But it's work
Trully, if there evil in this world, It lies within the heard of mankind
Shock The Dark Mage
shock@romhack.net
Main Project: Aeru IRC - http://www.sf.net/projects/aeruirc
|
|
|
|
|