|
The only reason to get the start address of a string as an IntPtr would be to marshal it, and the Marshal class does just that, so I told you exactly how to do it in C# (remember, C# is just a language that targets the CLR; it's the .NET Framework that provides the language constructs).
You could also use GCHandle to pin the string in memory so that the garbage collector (GC) doesn't move it around after you've sent the address to unmanaged code (if the GC moves it, the unmanaged code won't know and will access the wrong data):
string s = "Hello, world!";
GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned);
IntPtr ptr = handle.AddrOfPinnedObject();
SomeUnmanagedPInvokedFunction(ptr);
handle.Free(); In most cases you don't need to worry about this, though. Passing a string is actually passing the address of the string, so declaring your P/Invoke signatures correctly aleviates this problem.
Again, read the documentation for interop'ing with unmanaged DLL functions I posted before, and play close attention to the marshaling topics toward the end.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Hi~
I use these code to past string to a C++ window but still doesn't work.
[C#]<br />
string s = "Hello, world!";<br />
GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned);<br />
IntPtr ptr = handle.AddrOfPinnedObject();<br />
PostMessage(hWnd, msg, IntPtr.Zero, ptr);<br />
handle.Free();<br />
<br />
[DllImport="Test.dll", CharSet=CharSet.Auto]<br />
private static extern IntPtr PostMessage(IntPtr hwnd, uint msg, IntPtr wparam, IntPtr lparam);<br />
<br />
<br />
[C++]<br />
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)<br />
{<br />
if (message == WM_TESTING)<br />
{<br />
TCHAR* StringPtr = (TCHAR*)LPARAM;<br />
MessageBox(0,StringPtr,_T("Caption"),MB_OK | MB_INFORMATION);<br />
}<br />
else<br />
{<br />
return DefWindowProc(hWnd, message, wParam, lParam);<br />
}<br />
return 0;<br />
}
The message box in C++ show null string. How can I solve it?
Thanks
|
|
|
|
|
As I said in my first reply, in such a case you can define the last parameter as string instead of an IntPtr . Either passes the address of the variable and in this case you don't need to pin the string if you use SendMessage instead of PostMessage . Besides, you don't need to set DllImportAttribute.CharSet unless you're passing a string.
If you're C++ code was compiled without UNICODE (or _UNICODE , depending on which macros and APIs you're using - always be sure to define both) and get the IntPtr of your managed string - which is always Unicode - the ANSI version of your call to MessageBox won't display the string right. You should've at least seen a single character.
So, just define SendMessage how I showed you in the first place. You really only need PostMessage if you need to return immediately and let the message be processed on the target window's thread. If you use SendMessage , the thread context is switched - blocking your execution - and the message is processed until finished.
If you use PostMessage , then you'll need to pin the string but don't free it right away. Remember, your message may still not be processed. To marshal the string as well as get the IntPtr , use Marshal.StringToHGlobalAuto and when you know your message has bee processed, call Marshal.FreeHGlobal with the IntPtr returned from the previous call. This will make sure your string is marshaled as the correct type (ANSI or Unicode) and copied into global memory.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
In compact framework, there is no Marshal.StringToHGloablAuto method.
Also if I use sendMessage,
[DllImport("User32.dll"), CharSet=CharSet.Auto]<br />
private static extern IntPtr SendMessage (IntPtr Hwnd, uint msg, IntPtr wparam, string lparam)
is that correct?
In C++ side
Is that just Cast the lparam to TCHAR * like this?
TCHAR* stringPtr = (TCHAR*)lparam;<br />
MessageBox(0, stringPtr, _T("Caption"), MB_OK);
Thanks
|
|
|
|
|
ting668 wrote:
In compact framework, there is no Marshal.StringToHGloablAuto method.
Yes, but you never said you were using the .NET CF. How was I to know?
ting668 wrote:
Is that just Cast the lparam to TCHAR * like this?
Yes.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
hi Gurus,
I'm using DataView to display a datagrid. The data source of the dataview is a data table.
The dataview should always be sorted by a specific column in the same order. The user can modify the row data, without the columns unchanged. The data grid (or data view?) is frozen so that the user can't sort the data when clicking on any column header of the datagrid, but it seems one Mission Impossible...
The codes are something like the follows, where
one column of the data table is defined as the "Sort" column of the dataview, and validate the "ApplyDefaultSort" property to be true.
DataTable myTable = createMyTable(); // define MyTable
myTable = refreshMyTable(myTable); // add rows to the table
DataView MyView = new DataView();
MyView.Table = myTable; MyView.RowStateFilter = DataViewRowState.CurrentRows ;
MyView.AllowEdit = true; MyView.ApplyDefaultSort = true;
m_myDataGrid.SetDataBinding(MyView,"");
...
However, now it seems the user gets a full control over sorting of the datagrid.
I'm expecting your help, many thanks in advance~~~
|
|
|
|
|
|
ok
I want to know
how to prevent sorting the order of datagrid items when clicking its column header?
The fact is,
a data view is bound to the datagrid.
a data table is the data view's data source.
so I can't add a DataTableStyle to the datagrid.
Thanks!
|
|
|
|
|
Set the value of datagrid's AllowSorting property to false.
Sreejith Nair
[ My Articles ]
|
|
|
|
|
oh yeah, it works!
Thank you ~~~
|
|
|
|
|
Hello all
i make a MDI form and there is a many forms inside it but when i try to max one form all forms turn max and when i min it all forms turn min can i seprate the form status
Regards
hoho
|
|
|
|
|
Maximizing one MDI form is supposed to maximize all MDI forms, and restoring (not minimizing - that's different) is supposed to restore them all. This has been the behavior since...well...forever.
Open any other MDI application (Adobe Photoshop, older versions of Office programs, the old MFC samples applications, etc.) and you'll see the same behavior.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Here is my problem I wasn't sure if I should put it here or in the C# board ot he GDI+ board
I have a 1 form that has 2 user controls on and both user controls use GDI+ (I need to draw my own custom bitmap).
In user control 1 (ucmain) i use GDI+ to draw my own customized calender(it shows the time of day and has columns for the different conference rooms). This user control so far no problem. In user control 2 (ucappts) I draw the the scheduled appts (with detaled info) this also works. Now how I execute it is as follows: from ucmain I first create the calender bitmap for that day and draw the image and it shows up on the form.Than within ucmain I get all the appts from the db for that day and within ucmain I create ucappt for each appt. from within ucappts, I position where ucappt should go on the image that is created by ucmain ((based on time and conferrence room). Than I add the ucappt controls to ucmain. so far so good this seems to work. ucappts also contains code to deal with mouseup, mousedown, mousemove events in which I am able to move the ucappt around somewhat, this is where my problem lies.
Moving ucappts is where I have my problem, when I move the appt (ucappts) around, the background behind it i.e. the image of the calender does not repaint until after I'll let the mouse up. (the appt (ucappts) acts like a eraser wiping the image of the calender clear and does repaint until after the mouseup event is fired(it than repaints and everything looks ok). Second problem is when I move the appt (ucappts) the ucappts image it shows a double image (1/2 inch apart sometimes more) of the ucappts (i.e. flickers) like it is jumping around. Can some on help me this?
I think with the first problem, I have to somehow call the ucmain OnPaint method from ucappts from within ucappts everytime the mousemove event is fired, any opinions , thoughts.
As far as the second problem I have no Idea? any help would be great
thanks for the help
|
|
|
|
|
Painting and other interaction with the control happens in the same thread (by default), and most likely your painting routines are far too slow to keep up (so you get the appearance on-screen bitmap staying place). While you're moving the control, you're blocking the thread so the painting isn't even performed (the reason the controls move is because they encapsulate the native Windows APIs - and in most cases the Windows Common Controls - which are programmed to paint correctly in a separate thread...which is exactly what you're going to do if you follow this advice.
In our defualt constructor, call the following:
SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.DoubleBuffer | ControlStyles.UserPaint, true); Now you're responsible for all drawing (even the background), but it sounds like you're doing that already. Additionally, the .NET Framework - without any additional code on your part - is performing the paint routine in a separate thread and copying that secondary graphics buffer to the on-screen buffer when it can. This will elliminate the flicker (mostly; terribly inefficient paint routines may still cause flicker so honor the PaintEventArgs.ClipRectangle and only redraw what's necessary) and should provide a more consistent, contiquous painting experience while dragging your windows.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Heath thanks
It still didn't solve my problem, actually it causes more. I understand your points, but i'm still learning and as a result my coding is getting complicated.
I tried your solution but it appears that rather than stopping my flickering, when I have a mousedown event (in ucappts) i now get two seperate imagaes and when I move it around both images wipe out the background image and when the mouseup event fires does not repaint like it did before it. how do get the OnPaint event in ucmain to fire when I'm in ucappts?
thnaks for your insight and help
|
|
|
|
|
bobrad wrote:
my coding is getting complicated
Welcome to the world of development.
The solution I presented to you is the correct way of doing this. When you have rather complex graphics you should use double-buffering (that's debatable, but most would agree) so that you don't tie up the control thread.
When you're moving your control, form, whatever, or minimizing it or even passing your mouse over it (in Windows 2000 and newer, the mouse part isn't exactly true thanks to layered windows) everything in the invalidated ("affected") area is repainted. Efficient drawing routines only repaint what they have to (the invalidated region - not the entire client area). So, your form's OnPaint is already being called. And actually, that's not what even paints the form or most of the other controls in the BCL (base class library). Most controls merely encapsulate the Windows Common Controls (the same controls you see in most other applications and in Windows itself - they're native) and the Window APIs. Native code paints them using the WM_PAINT message, which in turn invokes the OnPaint method (from within WndProc - the window procedure encapsulated in managed code), which in turn fires the Paint event for a control.
The problem you're witnessing is something else. As I mentioned in my first reply, however, once you enable to those ControlStyles to get double-buffering, you're responsible for painting the background as well (the SystemColors class defines static properties to get you these colors).
As to why you're seeing two images, I'm not sure quite what you mean. Perhaps you could post a screenshot somewhere and paste the link here (you can take screenshots using the PrtScn keyboard button, or use Alt+PrtScn to take a screenshot of just the active window; then paste it into some graphics program or even Microsoft Paint (mspaint.exe) and save it).
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
I understand what you are saying but I'm unsure as how to implement what you are saying; Im unsure how to repaint a the background which is in the parent user control (ucmain) when I'm in the child (user control ucappts)
I tried using a delegae to redraw the background, it works somwhat
I tried to post the code here for the two usercontrols but it's too much and looks really ugly. is there a better place to post my code?
thanks for all you help
bob
|
|
|
|
|
You don't need to paint the parent control - that's what I've been trying to say. It gets automatically repainted when anything affects any part of its client area. If that client area includes your control then your control gets the WM_PAINT message (translates to the OnPaint method, which fires the Paint event - which you should handle in your derivative control since it's slower and you have less control) and you should repaint only the area (the PaintEventArgs.ClipRectangle , although with more complex graphics that can be difficult).
If you want examples of owner-drawn controls, just search here at CodeProject. There are dozens - if not hundreds - of examples of just about every type of control you can think of (and good and bad articles, so watch the article rating near the top...and longer articles are usually a sign of more detailed articles that you should take a look at).
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
hi, i've this datagrid. each time i click the row header of the datagrid, i wanna put the value of col1 into a variable. the value in the variable will change everytime i click on different row header. is like using currencymanager to bind the datagrid onto textbox,but instead i wanna bind it into a variable.
Chris
|
|
|
|
|
You don't need data binding for this, nor do I suggest it. If all you're doing is storing the row index (which you shouldn't do; the CurrencyManager manages that) or some value in the one of the row's column, data binding is completely unnecessary.
All you need to do is handle the DataGrid.RowHeaderClick event, get the current mouse position (in screen coordinates) using the static Control.MousePosition property, convert that to client coordinates in reference to the DataGrid (DataGrid.PointToClient ), then pass that to DataGrid.HitTest . That will get you the row index. Using this approach, however, has it's problems. Unless you're binding against a DataView that tracks the sorting and filtering instead, you may have difficulting resolving the right row in the DataSet with the right row in the DataGrid (the row indexes will be out of sync) when the user sorts the data or filters it (if allowed). The method below mitigates this problem.
You could avoid all this, however, knowing that when you click a row it becomes the current row. You then get the current row from the CurrencyManager like so:
CurrencyManager cm = (CurrencyManager)
dataGrid1.BindingContext[dataGrid1.DataSource, dataGrid1.DataMember];
if (cm != null)
{
DataRowView rowView = cm.Current as DataRowView;
if (rowView != null)
myVariable = rowView[0].ToString();
}
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
hi, im able to store it into the variable but only the first row. the value is not changing when i select other row on the datagrid.
Chris
|
|
|
|
|
What does your (relevent) code look like? Just telling me that it doesn't work doesn't help diagnose the problem, but if you post snippets of your code that would help.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
sorry, here is my coding. thanks
SQL = "SELECT * FROM TABLE ORDER";
cmd = new System.Data.OleDb.OleDbCommand (SQL, conn);
adapter = new System.Data.OleDb.OleDbDataAdapter(cmd);
ds = new System.Data.DataSet();
adapter.Fill(ds,"TABLE");
dataGrid1.DataSource = ds;
dataGrid1.DataMember ="TABLE";
CurrencyManager cm = (CurrencyManager)dataGrid1.BindingContext[dataGrid1.DataSource,dataGrid1.DataMember];
string myVariable;
if (cm != null)
{
DataRowView rowView = cm.Current as DataRowView;
if (rowView != null)
{
myVariable = rowView["startDate"].ToString();
}
}
Chris
|
|
|
|
|
sorry there was some typo error..
SQL = "SELECT * FROM TABLE";//<-- without "Order"
cmd = new System.Data.OleDb.OleDbCommand (SQL, conn);
adapter = new System.Data.OleDb.OleDbDataAdapter(cmd);
ds = new System.Data.DataSet();
adapter.Fill(ds,"TABLE");
dataGrid1.DataSource = ds;
dataGrid1.DataMember ="TABLE";
CurrencyManager cm = (CurrencyManager)dataGrid1.BindingContext[dataGrid1.DataSource,dataGrid1.DataMember];
string myVariable;
if (cm != null)
{
DataRowView rowView = cm.Current as DataRowView;
if (rowView != null)
{
myVariable = rowView["startDate"].ToString();
}
}
Chris
|
|
|
|
|
I'm not sure if you're posting just snippets from various methods or if this is your entire method. If the latter is true, then of course it won't work. You need to declare myVariable (and I certainly hope you haven't given it that non-descript name) as a field (so you don't loose it after setting it) and put everything below that in your code snippet in an event handler for DataGrid.RowHeaderClick (which means you'll have to extend DataGrid with your own control since RowHeaderClick is protected), or just handle the Click event, like so:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
public class Form1 : Form
{
private DataGrid dataGrid1;
private Label label1;
private SqlCommand sqlSelectCommand1;
private SqlConnection sqlConnection1;
private SqlDataAdapter sqlDataAdapter1;
private DataView dataView1;
public Form1()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
DataSet ds = new DataSet();
sqlDataAdapter1.Fill(ds);
dataView1 = new DataView(ds.Tables[0]);
dataView1.AllowDelete = false;
dataView1.AllowEdit = false;
dataView1.AllowNew = false;
dataGrid1.DataSource = dataView1;
}
private void InitializeComponent()
{
this.dataGrid1 = new DataGrid();
this.label1 = new Label();
this.sqlSelectCommand1 = new SqlCommand();
this.sqlConnection1 = new SqlConnection();
this.sqlDataAdapter1 = new SqlDataAdapter();
((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).BeginInit();
this.SuspendLayout();
this.dataGrid1.Anchor = ((AnchorStyles)((((AnchorStyles.Top | AnchorStyles.Bottom)
| AnchorStyles.Left)
| AnchorStyles.Right)));
this.dataGrid1.DataMember = "";
this.dataGrid1.HeaderForeColor = System.Drawing.SystemColors.ControlText;
this.dataGrid1.Location = new System.Drawing.Point(8, 8);
this.dataGrid1.Name = "dataGrid1";
this.dataGrid1.Size = new System.Drawing.Size(280, 208);
this.dataGrid1.TabIndex = 0;
this.dataGrid1.Click += new System.EventHandler(this.dataGrid1_Click);
this.label1.Anchor = ((AnchorStyles)(((AnchorStyles.Bottom | AnchorStyles.Left)
| AnchorStyles.Right)));
this.label1.Location = new System.Drawing.Point(8, 224);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(280, 23);
this.label1.TabIndex = 1;
this.sqlSelectCommand1.CommandText = "SELECT ProductID, ProductName, SupplierID, CategoryID, QuantityPerUnit, UnitPrice" +
", UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued, CategoryName FROM [Alp" +
"habetical list of products]";
this.sqlSelectCommand1.Connection = this.sqlConnection1;
this.sqlConnection1.ConnectionString = "workstation id=ALICE;packet size=4096;integrated security=SSPI;data source=\".\";pe" +
"rsist security info=False;initial catalog=Northwind";
this.sqlDataAdapter1.SelectCommand = this.sqlSelectCommand1;
this.sqlDataAdapter1.TableMappings.AddRange(new DataTableMapping[] {
new DataTableMapping("Table", "Alphabetical list of products", new DataColumnMapping[] {
new DataColumnMapping("ProductID", "ProductID"),
new DataColumnMapping("ProductName", "ProductName"),
new DataColumnMapping("SupplierID", "SupplierID"),
new DataColumnMapping("CategoryID", "CategoryID"),
new DataColumnMapping("QuantityPerUnit", "QuantityPerUnit"),
new DataColumnMapping("UnitPrice", "UnitPrice"),
new DataColumnMapping("UnitsInStock", "UnitsInStock"),
new DataColumnMapping("UnitsOnOrder", "UnitsOnOrder"),
new DataColumnMapping("ReorderLevel", "ReorderLevel"),
new DataColumnMapping("Discontinued", "Discontinued"),
new DataColumnMapping("CategoryName", "CategoryName")})});
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(296, 253);
this.Controls.Add(this.label1);
this.Controls.Add(this.dataGrid1);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).EndInit();
this.ResumeLayout(false);
}
static void Main()
{
Application.Run(new Form1());
}
private void dataGrid1_Click(object sender, EventArgs e)
{
CurrencyManager cm = (CurrencyManager)dataGrid1.BindingContext[
dataGrid1.DataSource, dataGrid1.DataMember];
if (cm != null)
{
DataRowView view = cm.Current as DataRowView;
if (view != null)
label1.Text = view[1].ToString();
}
}
}
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|