问题
I know how to print an image using PrintDocument. However, i want to print my Image using the default windows print function. Like when you right click an image and click print, the dialog comes up that allows you to set size choose printer etc. Does anyone know how to achieve this in C#? Do i have to use WINAPI ?
Cheers
Edit:
I'm talking about this print dialog.

回答1:
You can launch that dialog with the Process class.
private void button1_Click(object sender, EventArgs e)
{
string fileName = @"C:\Development\myImage.tif";//pass in or whatever you need
var p = new Process();
p.StartInfo.FileName = fileName;
p.StartInfo.Verb = "Print";
p.Start();
}
回答2:
The simple approach with launching a new process using verb "print" is not working on Windows XP at all (it opens Windows Picture and Fax Viewer instead of the Printing Wizard). Also it does not work as intended on Windows 10 (at first run the Default app chooser for images is opened, then the default photo viewer is opened).
The correct approach would be using CLSID_PrintPhotosDropTarget COM object.
My code is in C++ (and ATL) but I hope you could translate it in C#.
I jast pass file names, but AFAIK you can pass picture itself directly without writing it on disk implementing IDataObject
interface.
bool DisplaySystemPrintDialogForImage(const std::vector<CString>& files, HWND hwnd) {
static const CLSID CLSID_PrintPhotosDropTarget ={ 0x60fd46de, 0xf830, 0x4894, { 0xa6, 0x28, 0x6f, 0xa8, 0x1b, 0xc0, 0x19, 0x0d } };
CComPtr<IShellFolder> desktop; // namespace root for parsing the path
HRESULT hr = SHGetDesktopFolder(&desktop);
if (!SUCCEEDED(hr)) {
return false;
}
CComPtr<IShellItem> psi;
CComPtr<IDataObject> pDataObject;
std::vector<LPITEMIDLIST> list;
for (const auto& fileName : files) {
PIDLIST_RELATIVE newPIdL;
hr = desktop->ParseDisplayName(hwnd, nullptr, const_cast<LPWSTR>(static_cast<LPCTSTR>(fileName)), nullptr, &newPIdL, nullptr);
if (SUCCEEDED(hr)) {
list.push_back(newPIdL);
}
}
if (!list.empty()) {
hr = desktop->GetUIObjectOf(hwnd, list.size(), const_cast<LPCITEMIDLIST*>(&list[0]), IID_IDataObject, 0, reinterpret_cast<void**>(&pDataObject));
if (SUCCEEDED(hr)) {
// Create the Photo Printing Wizard drop target.
CComPtr<IDropTarget> spDropTarget;
hr = CoCreateInstance(CLSID_PrintPhotosDropTarget, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&spDropTarget));
if (SUCCEEDED(hr)) {
// Drop the data object onto the drop target.
POINTL pt = { 0 };
DWORD dwEffect = DROPEFFECT_LINK | DROPEFFECT_MOVE | DROPEFFECT_COPY;
spDropTarget->DragEnter(pDataObject, MK_LBUTTON, pt, &dwEffect);
spDropTarget->Drop(pDataObject, MK_LBUTTON, pt, &dwEffect);
return true;
}
}
}
return false;
}
回答3:
This works for me:
internal static class ShellHelper
{
[ComImport]
[Guid("00000122-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDropTarget
{
int DragEnter(
[In] System.Runtime.InteropServices.ComTypes.IDataObject pDataObj,
[In] int grfKeyState,
[In] Point pt,
[In, Out] ref int pdwEffect);
int DragOver(
[In] int grfKeyState,
[In] Point pt,
[In, Out] ref int pdwEffect);
int DragLeave();
int Drop(
[In] System.Runtime.InteropServices.ComTypes.IDataObject pDataObj,
[In] int grfKeyState,
[In] Point pt,
[In, Out] ref int pdwEffect);
}
internal static void PrintPhotosWizard(string p_FileName)
{
IDataObject v_DataObject = new DataObject(DataFormats.FileDrop, new string[] { p_FileName });
MemoryStream v_MemoryStream = new MemoryStream(4);
byte[] v_Buffer = new byte[] { (byte)5, 0, 0, 0 };
v_MemoryStream.Write(v_Buffer, 0, v_Buffer.Length);
v_DataObject.SetData("Preferred DropEffect", v_MemoryStream);
Guid CLSID_PrintPhotosDropTarget = new Guid("60fd46de-f830-4894-a628-6fa81bc0190d");
Type v_DropTargetType = Type.GetTypeFromCLSID(CLSID_PrintPhotosDropTarget, true);
IDropTarget v_DropTarget = (IDropTarget)Activator.CreateInstance(v_DropTargetType);
v_DropTarget.Drop((System.Runtime.InteropServices.ComTypes.IDataObject)v_DataObject, 0, new Point(), 0);
}
}
来源:https://stackoverflow.com/questions/19662130/print-image-using-windows-print-image-dialog