|
Yes, but you must make sure that 1) CharSet.Auto is set in the DllImportAttribute and that 2) you use CallingConvention.ThisCall for methods (functions defined on a class). There's many reasons a NotSupportedException could be thrown, so you're just going to have to read those links I gave you before to articles about P/Invoke.
At least having a basic understanding is important to solving your problem.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
|
HI Heath Stewart ~
I have one more question ^.^
If I have implement a MFC dll which is used to show a string on the screen. The dll contain a variable which is stored a string.
Then I write a C# program to invoke the "set" method to set the string variable for the dll.
After a run the C# program, the variable has been updated. However, the string on the screen does not change. I know the dll needs to be refreshed. How to do this?
OnPaint() or using SendMessage() may be used to refresh the screen. But how?
Thank you for answering the questions!
|
|
|
|
|
The C# code shouldn't refresh the screen - the MFC implementation should handle that, which means instead of setting a variable you should call a method (like SetText ); the method implementation should set the variable and invalidate the client region. It's a matter of encapsulation, and this is a much better class design - the class itself should take care of what it manages.
In order to repaint the client region, all you need to do is invalidate it. CWnd::Invalidate would be a logical choice.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
yes, I just use C# program call the method inside the dll.
The method in the dll is set the value of a member variable.
The dll in fact is a screen plugin. The member variable may be a string that is to be shown on the screen.
I would like to change the member variable so that the screen will also be changed to achieve showing a message dynamically.
I can change the member variable but the screen would be change. How can I solve this?
Is the CWnd::Invalidate already existed in the CWnd class?
Or it is needed to be implemented and how to implement it?
|
|
|
|
|
As I said before, if the MFC class encapsulates the string variable, then it should also encapsulate the functionality to update the screen.
If you want to know more about CWnd , look it up on MSDN[^] or ask in the VC++ forum.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Anyone have any ideas on how to access the stored security accounts windows uses for mapping drives automatically ? I'm writting a network drive manager form and I would like to scan the system whent he app starts and store all the shared network drive information, including the username and password used to establish each network drive connection. I've looked at the Network Management API, particularly the NetUseGetInfo but wasn't sure if this was the wrong way to go about it. Any thoughts ?
|
|
|
|
|
You won't be able to get the password, unless storing plain-text passwords is enabled for the domain (and that's the dumbest thing in the world to do unless you have to support client machine 2 decades old or something).
This information isn't exposed in managed API, so you will have to P/Invoke some native API. NetUseGetInfo is as good an API as any - it's what I would've picked having had a lot of experience with the Network Management APIs.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
I'm triing to find in the documentqation what dll the NetGetUseInfo is in do you know ?
|
|
|
|
|
|
Hey Heath,
Thanks again for all your help thus far. I've setup the P/Invoke for NetApi32.dll, but I keep getting the same error so I must have done something wrong....
[DllImport("NetApi32.dll")] private static extern int NetUseGetInfo(string SrvrName,string MappedDrive,int Level,ref structUSE_INFO_2 MapInfo);
[DllImport("NetApi32.dll")] private static extern int NetApiBufferFree(ref structUSE_INFO_2 MapInfo);
[StructLayout(LayoutKind.Sequential)]
private struct structUSE_INFO_2
{
public string sLocal;
public string sRemote;
public string sPassword;
public int iType;
public int iRefCount;
public int iUseCount;
public string sUsername;
public string sDomain;
}
...
....
...
static public string GetMappedDriveUsername(string DriveLetter)
{
string Username=null;
try
{
structUSE_INFO_2 MappInfo = new structUSE_INFO_2();
int Err=NetUseGetInfo(null,DriveLetter.Replace(":",""),2,ref MappInfo);
Username=MappInfo.sUsername;
NetApiBufferFree(ref MappInfo);
}
catch(Exception Err)
{
throw new Exception("GetMappedDriveUsername Error: "+Err.Message);
}
return Username;
}
The error I'm getting is 2250 (This network connection does not exist. ).
I think I'm not seending the mapped drive name correctly, I've tried just the letter, letter with colon, drive description...You said you have alot of experience with these API so I thought you would be able to tell me the NetUseGetInfo 's UseName parameter format.
|
|
|
|
|
You must use CharSet=CharSet.Unicode in your DllImportAttribute , since the strings are declared as LPWSTR (Unicode). The default for the C# and VB.NET compilers is CharSet.Ansi . This makes a big difference. Do use X: as a drive letter (including the colon).
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Oh, and don't forget to set the CharSet field on the StructLayoutAttribute as well.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
ok, now I get an return code of 0, which I'm assuming is the NErr_Success code, with the following code.
[DllImport("NetApi32.dll",CharSet=CharSet.Unicode)] private static extern int NetUseGetInfo(string SrvrName,string MappedDrive,int Level,ref structUSE_INFO_2 MapInfo);
[DllImport("NetApi32.dll",CharSet=CharSet.Unicode)] private static extern int NetApiBufferFree(ref structUSE_INFO_2 MapInfo);
[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)]
private struct structUSE_INFO_2
{
public string sLocal;
public string sRemote;
public string sPassword;
public int iType;
public int iRefCount;
public int iUseCount;
public string sUsername;
public string sDomain;
}
...
...
...
structUSE_INFO_2 MappInfo = new structUSE_INFO_2();
int Err=NetUseGetInfo(null,DriveLetter,2,ref MappInfo);
Username=MappInfo.sUsername;
Err=NetApiBufferFree(ref MappInfo);
However the when I interrogate the structUSE_INFO_2 structure, all the memebers are null . Do I need to set any of the USE_INFO_2 members to a value first ? I didn't see any documentation on it.
|
|
|
|
|
Because the last param is NetUseGetInfo is LPBYTE* , which is a typedef for unsigned char ** . If it was just LPBYTE , your little shortcut of using ref structUSE_INFO_2 would work.
Instead, you have to pass an IntPtr (by the way, it should just be an out param, not a ref , though it doesn't hurt in this case) then use Marshal.PtrToStructure like so:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
internal class GetInfo
{
static void Main(string[] args)
{
if (args.Length != 1)
{
Console.Error.WriteLine("You must specify a drive letter.");
Environment.Exit(1);
}
if (Environment.OSVersion.Platform != PlatformID.Win32NT)
{
Console.Error.WriteLine("Supported only on Windows NT.");
Environment.Exit(2);
}
IntPtr ptr = IntPtr.Zero;
if (0 == NetUseGetInfo(null, args[0], 2, out ptr))
{
UseInfo2 info = (UseInfo2)Marshal.PtrToStructure(ptr,
typeof(UseInfo2));
Console.WriteLine("Username: " + info.username);
Console.WriteLine("Domain: " + info.domainname);
NetApiBufferFree(ptr);
}
else
{
int error = Marshal.GetLastWin32Error();
Console.Error.WriteLine("Error " + error);
Environment.Exit(error);
}
}
[DllImport("netapi32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
public static extern uint NetUseGetInfo
(
string server,
string drive,
uint level,
out IntPtr info
);
[DllImport("netapi32.dll")]
public static extern uint NetApiBufferFree(IntPtr ptr);
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
internal struct UseInfo2
{
public string local;
public string remote;
public string password;
public uint status;
public uint type;
public uint refcount;
public uint usecount;
public string username;
public string domainname;
}
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Awesome, thanks again Heath....
|
|
|
|
|
i want to write my own listview control that i can repaint the columnhead's color.
but i dont know how to do it.
i use Graphics.FillRectangle() in the OnPaint() method but did not get the correct result.
|
|
|
|
|
The ListView class encapsulates the List-View common control. Sticking to pure managed code won't accomplish what you need. You must extend the ListView control, override WndProc , and handle windows messages like you would in VC++.
There are plenty of articles here on CodeProject about this, and you should familiarize yourself with the windows messages and common controls by reading Windows Controls[^].
For one example, see a previous post about defining an event to fire when column widths change: http://www.codeproject.com/script/comments/forums.asp?msg=807702&forumid=1649#xx807702xx[^].
Another good article about handling notification messages for the List-View common control (because that's really what this all comes down to) is http://www.codeproject.com/cs/miscctrl/listviewfilter.asp[^].
In your case, since you're paining, you'll need to handle the NM_CUSTOMDRAW message (for a list-view). This will, once you've handle the right sequence of windows messages, give you an HDC (handle to a device context). You can get a Graphics object from this by using Graphics.FromHdc , but simply overriding the OnPaint method (or handlig the Paint event, which is much slower and a bad idea when done in a derived control) will not work. You must draw to the DC that the list-view is using for the list-view column header.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
I want to know that wich form is running now in my project at design time.
and then, know properties and field that each form have(at runtime).
|
|
|
|
|
Use reflection. Read Discovering Type Information at Runtime[^] in the .NET Framework SDK.
You can also use the ComponentModel to discover type information in a more design-time friendly way. Read about the TypeDescriptor and it's members in the .NET Framework sDK as well.
As far as which form is "running", that's entirely up to your implementation, especially since I have no idea of what you're talking about.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
I'm curious to know and I hope none of you get the wrong idea. I was just wondering if this is possible it doesn't matter if its yahoo or whatever. I just use yahoo as an example. If the window is open and you see your friends names in say billy,bob,sam. Instead of taking and doing a hi pm to each and every one of them. Is there a way in c# to read the names from the other control (yahoo window) and then let you pm then all at one time? If that is too much is there a way to read text from another window into c#? If i have word open would there be a way to tell it read what is on that screen into the text box on my windows form. Just curious.
Win32newb
"Programming is like sex, make one mistake and you have to support it for a long time"
|
|
|
|
|
You would probably need to use Spy++ to capture the handle of each sub-window (input textbox) for each IM window you have open. After that you would need to have your application perform a SendMessage with a WM_SETTEXT message included to apply the text you want each window to have. Make sense?
- Nick Parker My Blog | My Articles
|
|
|
|
|
Yeah i see what your talking about much like is done in c++. The thing is and maybe you can shed some light on the subject. How exactly do you use spy++? I'm kinda new to the programming field so I ask out of lack of knowledge. My understanding with spy is it gives me the (handle if you will) the hex or dword value of the control? I tried running it before but was lost. Is there any kinda free documentation other than the sdk and msdn. I don't mind reading those but sometimes they are too far advanced and I just shake my head and go whatever. Thanks for your information. And also i assume that if i wanted to read in the data from the control it would be ReceiveMessage?
thanks again
Nick Parker wrote:
You would probably need to use Spy++ to capture the handle of each sub-window (input textbox) for each IM window you have open. After that you would need to have your application perform a SendMessage with a WM_SETTEXT message included to apply the text you want each window to have. Make sense?
Win32newb
"Programming is like sex, make one mistake and you have to support it for a long time"
|
|
|
|
|
Open it up and try it. It's a simple-to-use window style and message viewer. It's in your Start menu, under the program group for Visual Studio (whatever version)-<Tools (or something similar).
Just try it out - it's not a difficult program, and there's always the Help menu. It's how we learned.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
You can do this programmatically at runtime, too, instead of using Spy++ as Nick said. You have to P/Invoke FindWindow and/or FindWindowEx , which you can search for windows using their title or class name (better using the class name since it'll never change).
Using this, you can keep calling FindWindow(Ex) using the previous found window as the parent until you get to your child (since the screen name may be in an edit control which may be in a list-box control, which may be hosted in a dialog, etc.), and then call WM_GETTEXT to get their screen name.
There's no truly generic way of doing, this, though. What Nick and I mentioned would be the closest thing to generic as possible, since you could design your recursive window finding algorithm to use heuristics to find screen names; when it does, it knows it's found the right window (that contains the screen names).
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|