According to the following page:
http://msdn.microsoft.com/en-us/library/ms646964(VS.85).aspx
underneath the first graphic, "If the user clicks the OK button, PrintDlg returns TRUE and the PRINTDLG structure to return informmation about the user's selection".
In this case, my custom print dialog is nearly working, but I'm trying to extract the information about printer name, orientation, etc... My understanding is that in order to retrieve the printer name, I need to examine the hDevMode value from the PRINTDLG structure to see the printer name. Is there a function that will allow me to extract that info?
My code is like (where pdlg is my defined instance of the PRINTDLG structure):
bool f = false;
try
{
f = PrintDlg(ref pdlg);
DEVMODE dm = pdlg.hDevMode;
int k = 0;
} catch (Exception ex)
{
// hopefully it doesn't fail
}
If someone has any pearlsof wisdom out there, I would sure appreciate any tips.
The following shows how to extract the printer name and driver. The key is to do a GlobalLock on hDevNames, Marshal.PtrToStructure it into the CLR version of the struct, and then access its content. Remember to GlobalUnlock when done.
You could do something similar with hDevMode, which will get you information about the printer metrics and setup. You can find a C# declaration of the DEVMODE struct here.
using System;
using System.Runtime.InteropServices;
namespace ConsoleApplication3 {
class Program {
// Win32 struct declarations
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]
[System.Runtime.InteropServices.ComVisible(false)]
internal class PRINTDLG {
public Int32 lStructSize;
public IntPtr hwndOwner;
public IntPtr hDevMode;
public IntPtr hDevNames;
public IntPtr hDC = IntPtr.Zero;
public Int32 Flags;
public Int16 FromPage = 0;
public Int16 ToPage = 0;
public Int16 MinPage = 0;
public Int16 MaxPage = 0;
public Int16 Copies = 0;
public IntPtr hInstance = IntPtr.Zero;
public IntPtr lCustData = IntPtr.Zero;
public IntPtr lpfnPrintHook;
public IntPtr lpfnSetupHook = IntPtr.Zero;
public IntPtr lpPrintTemplateName = IntPtr.Zero;
public IntPtr lpSetupTemplateName = IntPtr.Zero;
public IntPtr hPrintTemplate = IntPtr.Zero;
public IntPtr hSetupTemplate = IntPtr.Zero;
}
[StructLayout(LayoutKind.Sequential)]
public class DEVNAMES {
public short wDriverOffset;
public short wDeviceOffset;
public short wOutputOffset;
public short wDefault;
}
// import PrintDlg, GlobalLock and GlobalUnlock
[DllImport("comdlg32.dll", CharSet = CharSet.Auto)]
private static extern bool PrintDlg([In, Out] PRINTDLG lppd);
[DllImport("kernel32.dll")]
private static extern IntPtr GlobalLock(IntPtr hMem);
[DllImport("kernel32.dll")]
private static extern bool GlobalUnlock(IntPtr hMem);
static void Main(string[] args) {
// show the printer dialog box
PRINTDLG pd = new PRINTDLG();
pd.lStructSize = Marshal.SizeOf(pd);
PrintDlg(pd);
// here's the meat -- extract the printer information
// out of pd.hDevNames...
DEVNAMES devNames = new DEVNAMES();
// lock hDevNames into memory and get a pointer to it
IntPtr pDevNames = GlobalLock(pd.hDevNames);
// marshal into a DEVNAME struct
Marshal.PtrToStructure(pDevNames, devNames);
// pull out the device and driver strings; hopefully not much of
// that in DEVMODE
string sDevice = Marshal.PtrToStringUni((IntPtr) (
pDevNames.ToInt32() +
devNames.wDeviceOffset * Marshal.SystemDefaultCharSize));
string sDriver = Marshal.PtrToStringUni((IntPtr) (
pDevNames.ToInt32() +
devNames.wDriverOffset * Marshal.SystemDefaultCharSize));
string sOutput = Marshal.PtrToStringUni((IntPtr) (
pDevNames.ToInt32() +
devNames.wOutputOffset * Marshal.SystemDefaultCharSize));
// done -- release the global memory handle
GlobalUnlock(pd.hDevNames);
}
}
}
Related
I don't have a lot of experience on UWP programming and i built an app does some stuff on Bluetooth. Now i have to cary some info through APIs. But somehow "SendMessage" doesnt work. Here is the code i'm using
public static class ApiComm
{
[DllImport("User32.dll")]
public static extern IntPtr FindWindow(String lpClassName, String lpWindowName);
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, int lParam);
public static string DelphiFormClassName = "TFrmMain";//"wsdk_delphi_api_test";
public static string DelphiFormCaptionName = "Deneme";
private static IntPtr FindDelphiForm(string delphiFormClassName, string delphiFormCaptionName)
{
return FindWindow(delphiFormClassName, delphiFormCaptionName);
}
private static IntPtr FindDelphiForm()
{
return FindDelphiForm(DelphiFormClassName, DelphiFormCaptionName);
}
public static int TextToID(string text)
{
int mu = (text == null ? 0 : text.Length);
int result = 0;
for (int i = 0; i < mu; i++)
result = result + (((i + 1) * 256) + (byte)(text[i]));
return result;
}
private const int WM_COMMAND = 0x0111;
private const int StartFrom = 500;
private static int EventID(RemoteDeviceUpdate anEvent)
{
return StartFrom + (int)anEvent;
}
public static void SendInfo(int remoteID, RemoteDeviceUpdate anEvent)
{
IntPtr wP = FindDelphiForm();
if (wP != null && wP != IntPtr.Zero)
{
int eID = EventID(anEvent);
SendMessage(wP, WM_COMMAND, eID, remoteID);
}
}
public static void SendInfo(string remoteID, RemoteDeviceUpdate anEvent)
{
SendInfo(TextToID(remoteID), anEvent);
}
}
when i try SendInfo with another .net projects, it works just fine but with UWP it doesnt (and it doesnt give any error also)
do i have to add packages or something to my project..
any help would be appreciated, thanks.
Derive from this case, you need check if the API available to Windows Runtime apps.
Apps can p-invoke DLLs deployed with the app package. The DLL will run in the app's context and have the same API access as the app itself. See Win32 and COM APIs for an overview of Win32 API available to Windows Runtime apps.
If you just want to build an app does some stuff on Bluetooth. You can do it all with uwp
Bluetooth api. And this is official document. For RFFCOMM, this is uwp code sample that you could refer.
Hi this is my Function in C++ dll.
I am Trying to use it in My C# Application. Have tried so many things but nothing seems to work for me.
xyz_API LONG __stdcall xyz_Login(char *dwIP,unsigned short dwPort,char *dwUseName,char
*dwPassword,MyDetail dwInfo,char *dwInfo);
* Parameter:
[in]
dwIP
dwpPort
dwUseName
dwPassword
[out]
MyDetail (struct)
This is the Struct :
typedef struct
{
int xyz_id;
int xyz_ch;
int xyz_total;
int my_id;
char my_Info[10];
char m_status;
}MyDetail ,*MyDetail ;
I made a Class for this Struct in my code as:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class MyDetail
{
public int xyz_id;
public int xyz_ch;
public int xyz_total;
public int my_id;
[MarshalAs(UnmanagedType.ByValArray,
ArraySubType = UnmanagedType.LPStr, SizeConst = 10)]
public char[] my_Info;
public sbyte m_status;
}
I am using following line of code to do use it in C# application:
[DllImport("MYC.dll", EntryPoint = "xyz_Login", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int xyz_Login([MarshalAs(UnmanagedType.LPWStr)]string dwIP, ushort dwPort, [MarshalAs(UnmanagedType.LPWStr)] string dwUseName, [MarshalAs(UnmanagedType.LPWStr)] string dwPassword, MyDetail dwmyInfo, [MarshalAs(UnmanagedType.LPWStr)]string dwInfo);
My Form Calling:
MyDetail obj= new MyDetail();`enter code here`
int result = xyz_Login("192.168.1.10", 9001, "admin", "admin", obj, null);
code works perfectly but there is not output. MyDetail object always return null.
Is There a problem in marshalling. thanks in advance
First, the C++ function:
xyz_API LONG __stdcall xyz_Login(char *dwIP,unsigned short dwPort,char *dwUseName,char
*dwPassword,MyDetail dwInfo,char *dwInfo);
The paramter "dwInfo" is a struct type, not a pointer or a reference type, so the parameter is passed by value, so in the function xyz_Login, you are modifying a local copy of the struct, no changes to the struct in C#. So you should change it: MyDetail* dwInfo
Meanwhile, you should change the dllimport in C# to:
[DllImport("MYC.dll", EntryPoint = "xyz_Login", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int xyz_Login(string dwIP, ushort dwPort, string dwUseName, string dwPassword, ref MyDetail dwmyInfo, string dwInfo);
In a PInvoke call, a ref struct is translated into a pointer to the struct; also, char* is ansi, not unicode.
I got this running using following:
Struct As:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class MyDetail
{
public int xyz_id;
public int xyz_ch;
public int xyz_total;
public int my_id;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string my_Info;
public sbyte m_status;
}
DLLImport Statement AS:
[DllImport("MYC.dll", EntryPoint = "NET_DVR_Login")]
public static extern Int32 xyz_Login(string dwIP, UInt16 dwPort, string Name,string dwPassword, IntPtr myDetail, char[] info);
I am doing an application using vb.net.
What I need is access my computer (win 8) from a windows ce device and copy one file to the windows ce device.
I already did that but what I need now is an way to pass the user, password and domain.
I have researched about and found some solutions using System.Security.WindowsImpersonationContext So I think Something similar to that that will work in a windows ce application.
SOrry If you don't get something I have said but I am new on programming and english is not my home language.
Thanks in advance for your help
You could use the MapDrive method of the Network class from the SDF. Since it's pretty straightforward, the source for that method is as follows (I leave it to you to get it to VB):
public static void MapDrive(IntPtr hwnd, string netRes, string shareName, string userName, string password)
{
NETRESOURCE NetRes = new NETRESOURCE();
NetRes.dwScope = RESOURCE_GLOBALNET | RESOURCE_REMEMBERED;
NetRes.dwType = RESOURCETYPE_DISK;
NetRes.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
NetRes.dwUsage = RESOURCEUSAGE_CONNECTABLE;
NetRes.lpRemoteName = Marshal2.StringToHGlobalUni(netRes);
NetRes.lpLocalName = Marshal2.StringToHGlobalUni(shareName);
NetRes.lpComment = IntPtr.Zero;
NetRes.lpProvider = IntPtr.Zero;
int ret = WNetAddConnection3(hwnd, NetRes, password, userName, 1);
if (ret != 0)
{
throw new System.ComponentModel.Win32Exception(ret, ((NetworkErrors)ret).ToString());
}
}
private class NETRESOURCE
{
public int dwScope;
public int dwType;
public int dwDisplayType;
public int dwUsage;
public IntPtr lpLocalName;
public IntPtr lpRemoteName;
public IntPtr lpComment;
public IntPtr lpProvider;
}
[DllImport("coredll.dll")]
private static extern int WNetAddConnection3(
IntPtr hwndOwner,
NETRESOURCE lpNetResource,
string lpPassword,
string lpUserName,
int dwFlags);
const int RESOURCE_GLOBALNET = 0x00000002;
const int RESOURCE_REMEMBERED = 0x00000003;
const int RESOURCETYPE_DISK = 0x00000001;
const int RESOURCEDISPLAYTYPE_SHARE = 0x00000003;
const int RESOURCEUSAGE_CONNECTABLE = 0x00000001;
I'm trying to work with the Powerbuilder ORCA Api from C#, and I'm having some issues with marshaling. Here is the C header file for the ORCA Api, I'm trying to implement the PBORCA_SccGetConnectProperties function, which requires the pborca_scc struct.
Here are my definitions:
[DllImport(OrcaModule, CharSet = CharSet.Auto)]
internal static extern int PBORCA_SccGetConnectProperties(IntPtr ORCASession,
[MarshalAs(UnmanagedType.LPWStr)] string Workspace,
ref OrcaSccInfo SCCInfo);
public delegate int TextOutDelegate(
[MarshalAs(UnmanagedType.LPWStr)] string data,
int userData);
public delegate void BuildProjectDelegate(
OrcaBuildError BuildError,
IntPtr userData);
[StructLayout(LayoutKind.Sequential)]
public sealed class OrcaSccInfo
{
internal IntPtr Wnd = IntPtr.Zero;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
internal string ProviderName = null;
internal int Capabilities = 0;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
internal string UserID = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 301)]
internal string Project = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 301)]
internal string LocalProjPath = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 301)]
internal string AuxPath = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 301)]
internal string LogFile = null;
internal TextOutDelegate SccMsgHandler = null;
internal BuildProjectDelegate OrcaMsgHandler = null;
internal int lCommentLen = 0;
internal int lAppend = 0;
internal IntPtr CommBlk = IntPtr.Zero;
internal int DeleteTempFiles = 0;
}
When calling the function like so:
ret = Interop.PBORCA_SccGetConnectProperties(session.Handle,
#"D:\PB11-test\test.pbw",
ref scc);
I receive a FatalExecutionEngineError with a message that it could be due to marshaling errors. I've gone over this again and again and can't seem to find where I'm making a mistake with how I'm marshaling the function, the struct, or the delegates.
For the delegate definition, that second parameter should be a uint rather than an int.
public delegate int TextOutDelegate([MarshalAs(UnmanagedType.LPWStr)] string data, uint userData);
The first parameter in the second delegate could possibly be a ref or a pointer.
public delegate void BuildProjectDelegate(ref OrcaBuildError BuildError, IntPtr userData);
And in the class definition you could try [MarshalAs(UnmanagedType.FunctionPtr)] on the delegate members, and in any methods that take delegates.
Is the size of the OrcaSccInfo class coming out the same size in C# as you'd expect it to be in the C++ code? When I put it into Linqpad and get the size I get 2584 for Auto charset, 1320 with Ansi charset and 1316 when I set Pack=1 on 64-bit and 1300 on 32-bit.
Have you tried replacing the strings with StringBuilders, particularly in the Dllimport declaration itself?
And is it possible that your delegates are being disposed of before they're being used?
Passing a delegate to unmanaged code doesn't create a reference that the garbage collector can see so unless you hold on to a reference to the delegate in your own code it'll be disposed of earlier than you expect.
I have an example of winapi code:
struct CommunicationInfo {
long internalMsg;
const TCHAR * srcModuleName;
void * info;
};
...
const TCHAR* szText = _T("Hello from my plugin!\n(test message)");
CommunicationInfo ci = { 0x0401, cszMyPlugin, (void *) szText };
::SendMessage( hNppWnd, 0x111, (WPARAM) _T("NppExec.dll"), (LPARAM) &ci );
I want make the same call from .net and i wrote such wrapper:
[StructLayout(LayoutKind.Sequential)]
public struct CommunicationInfo
{
public Int64 internalMsg;
[MarshalAs(UnmanagedType.LPWStr)]
public StringBuilder srcModuleName;
[MarshalAs(UnmanagedType.LPWStr)]
public StringBuilder data;
};
...
[DllImport("user32")]
public static extern IntPtr SendMessage(IntPtr hWnd,
NppMsg Msg, IntPtr wParam,
[MarshalAs(UnmanagedType.Struct)] CommunicationInfo communicationInfo);
...
SendMessage(hNppWnd, 0x111,
Marshal.StringToHGlobalUni("NppExec.dll"),
new CommunicationInfo
{
data = new StringBuilder("test test"),
internalMsg = 0x0401,
srcModuleName = new StringBuilder("ModuleName")
});
But this code doesn't work. Where did I make a mistake ?
"long" field in CommunicationInfo struct is 32-bit in WinAPI, I believe. So try defining "internalMsg" as System.Int32 in C#
To be sure, try calling printf("%d\n", sizeof(CommunicationInfo)) in C/C++ to know the actual size. If it is (4 + 4 + 4) on a 32-bit system, then the C# struct must also be of 12 byte size.
The "char*" pointer must also be the pointer to unmanaged memory, so the StringBuilder just won't do.
See this PInvoke error when marshalling struct with a string in it for the marshalling sample
As Viktor points out, C/C++ long is 32 bits in size so needs to be matched with C# int. On top of that, the passing of the struct is not handled correctly. In addition the call to StringToHGlobalUni leaks since you never call FreeHGlobal.
I'd probably handle the marshalling something like this:
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct CommunicationInfo
{
public int internalMsg;
public string srcModuleName;
public string data;
};
....
[DllImport("user32")]
public static extern IntPtr SendMessage(
IntPtr hWnd,
uint Msg,
[MarshalAs(UnmanagedType.LPWStr)] string wParam,
ref CommunicationInfo communicationInfo
);
....
CommunicationInfo communicationInfo = new CommunicationInfo
{
internalMsg = 0x0401,
srcModuleName = "ModuleName",
data = "test test"
};
SendMessage(hNppWnd, 0x111, "NppExec.dll", ref communicationInfo);