|
Hi,
we developed a .NET-UserControl and embedded it into a C++-application as an ActiveX via interop. It is placed at an MFC CView-derived class. The problem is that the ActiveX has drawing problems: it is not refreshed quite often, for example when a modal dialog is opened by clicking on a button on the CView and then closed. When you hide the main window and then show it, the ActiveX will be properly displayed again. Thus, it seems like the typical invalidate-problem, the control doesn't get WM_PAINT.
Some tests revealed that the child-controls of the UserControl are actually not redrawn. I overrode the UserControl's OnPaint() to draw a rectangle - after opening the modal dialog and then closing it, the rectangle is still visible on the screen. But the other child windows are not.
Do you have any idea what could be the cause of this strange behavior?
Greetings,
Steven
|
|
|
|
|
Hi!
I want the coding to insert an image in Word document on a button click using c# in Windows Application..
|
|
|
|
|
|
Hi,
Just guide me through this:
I created a Crystal Report File and a Dataset File (design mode not code).
I want to fill crystal report with data from a database like i do to a Datagridview (have store_procedures for that).
Ok, what i see is that here dataset works like a suit, and as to fit/match my data from database, right?!
Dont i have to do anything else to the dataset fields i add in report design?
nelsonpaixao@yahoo.com.br
trying to help & get help
|
|
|
|
|
Workflow should be like this:
at design time
- add the dataset as a source for the report
- add desired fields to the report
at run time
- populate the dataset
- run the report and show preview (or print or save if that's what you want).
There are several good tutorials on msdn like this one: Tutorial: Connecting to ADO.NET DataSets[^]
The need to optimize rises from a bad design
|
|
|
|
|
My problem is as follows. I'm using a delegate in C# as a callback function for the unmanaged dll. When the delegate returns I get the following error.
Debug Error!
Module:
File: i386\chkesp.c
Line: 42
The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
When I run my C# code in a debugger the delegate gets called and everything looks great until the the function returns then I get the above error. I can even ignore it and continue but then I get the error again each time the callback function is used.
The function prototype in the C++ dll looks like...
DllImpExp int PcDllInit(const char PcDllPwd[64], int AutoDeleteFlag,
int LogFlag,
void (PcMsgCb)(PC_MSG_TYPE PcMsgType,
const char MsgTgt[MAX_PCDLL_STRING_LEN],
int Verbosity,
const char Msg[512]));
My Dllimport in the C# app is...
[DllImport("Dll.dll", CallingConvention = CallingConvention.Cdecl)]
static extern Int32 PcDllInit(char[] PcDllPwd,
Int32 AutoDeleteFlag,
Int32 LogFlag,
CallBackDelegate PcMsgCb);
And finally the delegate being used as a callback function
delegate void CallBackDelegate(PC_MSG_TYPE PcMsgType,
char[] MsgTgt,
int Verbosity,
char[] Msg);
I feel like the problem might be the signature's of either my delegate or in the DllImport but i'm at a loss here. Any help on this would be great. Thanks in advance and let me know if you need any other information from me.
|
|
|
|
|
Your native function takes 7 parameters - your DllImport shows 4 parameters...
Also, char is Unicode in C#, but a single byte in C++.
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Mark Salsbery wrote: Your native function takes 7 parameters - your DllImport shows 4 parameters...
So the native function takes 4 parameters but the 4th parameter is a pointer to a function which is used for callbacks. The callback function takes 4 parameters as well.
Mark Salsbery wrote: Also, char is Unicode in C#, but a single byte in C++.
Do you know how I can make the C# char be a single byte char as it is in C++? Marshaling perhaps?
Thanks for your help.
|
|
|
|
|
jamesmurphy78 wrote: So the native function takes 4 parameters but the 4th parameter is a pointer to a function which is used for callbacks. The callback function takes 4 parameters as well.
Wow - I read right through those parenthesis Sorry about that!
I'm not sure how to marshal those fixed-length char arrays you're passing by value.
Is there a reason you're doing it that way? That's unconventional - typically
you'd just pass a char * - it's more efficient than making a copy of an array
on the stack (passing by value).
I'm also wondering why you're using char ayway....it's kind of obsolete these days,
especially if you're going to interop with .NET assemblies.
Do you have control over the C++ function or are you stuck with an existing function that
was written that way?
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
The dll is not my code but I could put in a request that they be changed to a char*. If I was able to get that change put in I then pass in a String from the C# side? Or would you recommend using a String on the C++ side instead of a char?
|
|
|
|
|
A const char * would be easiest since you can easily marshal a String
using [MarshalAs(UnmanagedType.LPStr)].
I'm just not sure how to do it the way it is now - byval char arrays of a fixed length.
I think it can be done making a structure with a fixed length array but it would be messy.
There might be an easier way....I'm going to ask some C# MVPs.... I'll be back.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
How are you currently calling PcDllInit() from your c# code?
What are you passing as the char[] parameter - a string?
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Mark Salsbery wrote: How are you currently calling PcDllInit() from your c# code?
What are you passing as the char[] parameter - a string?
Below is my Main method that makes the call to PcDllInit.
static void Main(string[] args)
{
char[] pwd = new char[64];
pwd = "xxxxxx".ToCharArray();
Int32 AutoDeleteFlag = 1;
Int32 LogFlag = 1;
cbd = new CallBackDelegate(PcDllCbMsg);
try
{
PcDllInit(pwd, AutoDeleteFlag, LogFlag, cbd);
}
Thanks
|
|
|
|
|
Cool, thanks.
That's definitely a problem since the C++ side is expecting an
array of 64 bytes passed, but C# is passing 128 bytes.
I've got a couple fellow MVPs firing solutions at me here...
I'll be back...
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
So from what i've been reading it looks like I need to use a String on the C# side and marshal them to be a char[] with the given size. I implemented that following an example from the msdn http://msdn.microsoft.com/en-us/library/aa288468.aspx#pinvoke_example2[^]. I followed it but when I compile I get the following error.
Error 1 Error emitting 'System.Runtime.InteropServices.MarshalAsAttribute' attribute -- 'Specified unmanaged type is only valid on fields.' C:\views\QaView\In-Sight_FW_QA\Qa\Apps\QaUtils.NET\ProductConfigAPI\ProdConfigAPI.cs 43 36 ProductConfigAPI
Here Is the what the code looks like now after implementing the marshaling.
The Callback Delegate:
delegate void CallBackDelegate(PC_MSG_TYPE PcMsgType,
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] String MsgTgt,
int Verbosity,
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=512)] String Msg);
DllImport:
[DllImport("ProdConfigAppDll.dll", CallingConvention = CallingConvention.Cdecl)]
static extern Int32 PcDllInit([MarshalAs(UnmanagedType.ByValTStr, SizeConst=64)]
String PcDllPwd,
Int32 AutoDeleteFlag,
Int32 LogFlag,
CallBackDelegate PcMsgCb);
And the call to PcDllInit:
Int32 AutoDeleteFlag = 1;
Int32 LogFlag = 1;
String password = "xxxxxx";
cbd = new CallBackDelegate(PcDllCbMsg);
try
{
PcDllInit(password, AutoDeleteFlag, LogFlag, cbd);
}
Any Ideas about this compile error, or if this is even a solution to my problem? It looks to me like I've followed the example given in the msdn.
Thanks
|
|
|
|
|
MarshalAs(UnmanagedType.ByValTStr can only be used on members of a structure.
Ok, ignoring the callback stuff at the moment, I tried this:
[DllImport("DLL.dll", CallingConvention = CallingConvention.Cdecl)]
static extern Int32 PcDllInit([MarshalAs(UnmanagedType.LPStr)] StringBuilder PcDllPwd,
Int32 AutoDeleteFlag,
Int32 LogFlag);
...
String password = "xxxxx";
PcDllInit(password, AutoDeleteFlag, LogFlag);
That fixes the stack corruption calling the native code.
The delegate strings should be marshaled as UnmanagedType.LPStr as well
I believe. If that doesn't work, try using StringBuilders instead of Strings
in the elegate params.
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Awesome, thanks that seems to have fixed it. I did have to convert all String's to the StringBuilder class too. However now there's a new issue when the callback delegate returns. I'm getting an AccessViolationException. Reading up on this exception the msdn says this is thrown when a pointer has a bad value. Any idea's?
And thanks again for helping me through that other issue.
|
|
|
|
|
jamesmurphy78 wrote: I'm getting an AccessViolationException
Yeah I was just going to send you what should be the final fix.
Delegates should be called using __stdcall...
On the C++ side:
DllImpExp int PcDllInit(const char PcDllPwd[64], int AutoDeleteFlag,
int LogFlag,
void (<code>__stdcall</code> PcMsgCb)(PC_MSG_TYPE PcMsgType,
const char MsgTgt[MAX_PCDLL_STRING_LEN],
int Verbosity,
const char Msg[512]));
I tested with Strings, not StringBuilders and it seemed to work well.
You can get rid of the "SizeConst =" on the C# side marshaling, since the size can't
be enforced anyway (only array pointers are being passed). Having them there,
however, does document the max string sizes I guess.
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Fantastic Thank you so much for helping me through this. Everything works. I added __stdcall to the dll side and changed everything back to String on the C# side and everything worked out. Thanks again and have a good day!
|
|
|
|
|
Cool! Once I realized arrays aren't EVER passed by value
(pointed out by a fellow MVP) it was fairly straight forward.
Apparently I need to dust off my "C Programming for Idiots" book
You have a great day as well.
Cheers,
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
I need to override GetHashCode based on two Int32s.
Obviously, I can't get unique hash codes as it has to return one Int32.
I'm doing this at the moment, is there a better way to do it?
(m_Lower and m_Upper are both Int32)
public override int GetHashCode()
{
return (((Int64)m_Upper << 32) + m_Lower).GetHashCode();
}
I couldn't find any documentation on how Int64 implements it.
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)Visual Basic is not used by normal people so we're not covering it here. (Uncyclopedia)
|
|
|
|
|
The only strict requirement for the GetHashCode method is that it should always return the same hash code for a given value. So, this is a valid implementation of the method:
public override int GetHashCode() {
return 0;
}
However, that gives bad performance when you use the hash code for example in a dictionary. For good performance, the hash codes should be evenly distributed over the Int32 range of values.
This is how the implementation looks for the Int32 type:
public override int GetHashCode() {
return this;
}
This is how the implementation looks for the Int64 type:
public override int GetHashCode() {
return ((int)this) ^ ((int)(this >> 0x20));
}
As you see, it just throws away the top 12 bits. If you want to use all the bits in the hash code, you can just do an xor of the upper and lower value:
public override int GetHashCode() {
return m_Upper ^ m_Lower;
}
Despite everything, the person most likely to be fooling you next is yourself.
|
|
|
|
|
Thanks Guffa
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)Visual Basic is not used by normal people so we're not covering it here. (Uncyclopedia)
|
|
|
|
|
Guffa wrote: throws away the top 12 bits
Actually, it's just splitting it into 2 ints and xoring them - 0x20 (Hex!)
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)Visual Basic is not used by normal people so we're not covering it here. (Uncyclopedia)
|
|
|
|
|
Yes, you are right. Why didn't I think of that, that is what I would expect it to do...
Despite everything, the person most likely to be fooling you next is yourself.
|
|
|
|