1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
13 CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15
16 #include <stdio.h>
17 #include <windows.h>
18 #include <XpsObjectModel.h>
19 #include <XpsPrint.h>
20 #include <prntvpt.h>
21
22 #include "string_.h"
23 #include "gx.h"
24 #include "gserrors.h"
25
26 #undef eprintf1
27 #define eprintf1(str, arg) {}
28 #undef eprintf
29 #define eprintf(str) {}
30 #undef gs_note_error
31 #define gs_note_error(error) return(error)
32
33 typedef HRESULT (CALLBACK* StartXpsPrintJobType)(
34 /* [string][in] */ __RPC__in_string LPCWSTR printerName,
35 /* [string][in] */ __RPC__in_string LPCWSTR jobName,
36 /* [string][in] */ __RPC__in_string LPCWSTR outputFileName,
37 /* [in] */ __RPC__in HANDLE progressEvent,
38 /* [in] */ __RPC__in HANDLE completionEvent,
39 /* [size_is][in] */ __RPC__in_ecount_full(printablePagesOnCount) UINT8 *printablePagesOn,
40 /* [in] */ UINT32 printablePagesOnCount,
41 /* [out] */ __RPC__deref_out_opt IXpsPrintJob **xpsPrintJob,
42 /* [out] */ __RPC__deref_out_opt IXpsPrintJobStream **documentStream,
43 /* [out] */ __RPC__deref_out_opt IXpsPrintJobStream **printTicketStream
44 );
45
gp_xpsprint(char * filename,char * printername,int * result)46 extern "C" int gp_xpsprint(char *filename, char *printername, int *result)
47 {
48 HRESULT hr = S_OK;
49 HANDLE completionEvent = NULL;
50 IXpsPrintJob* job = NULL;
51 IXpsPrintJobStream* jobStream = NULL;
52 IXpsOMObjectFactory* xpsFactory = NULL;
53 IOpcPartUri* partUri = NULL;
54 IXpsOMPackage* package = NULL;
55 IXpsOMPackageWriter* packageWriter = NULL;
56 IXpsOMPage* xpsPage = NULL;
57 IXpsOMFontResource* fontResource = NULL;
58 XPS_JOB_STATUS jobStatus = {};
59 HPTPROVIDER pProvider;
60 HGLOBAL hGlobal = NULL;
61 IStream *pCapabilities;
62 BSTR *pbstrErrorMessage = NULL;
63 int code = 0;
64 StartXpsPrintJobType StartXpsPrintJobPtr = NULL;
65
66 HINSTANCE dllHandle = NULL;
67
68 /*
69 Loading the DLL at run-time makes life easier with the build
70 system (no need to link in the ".lib" file), and allows us to
71 use the same executable on old Windows systems (XP and earlier)
72 without XpsPrint.dll, and those with it (Vista and later).
73 */
74 if (!(dllHandle = LoadLibrary(TEXT("XpsPrint.dll"))))
75 {
76 *result = 0x80029C4A;
77 return -15;
78 }
79
80 StartXpsPrintJobPtr = (StartXpsPrintJobType)GetProcAddress(dllHandle, "StartXpsPrintJob");
81 if (!StartXpsPrintJobPtr)
82 {
83 *result = 0x80029C4A;
84 return -16;
85 }
86
87 if (FAILED(hr = CoInitializeEx(0, COINIT_MULTITHREADED)))
88 {
89 *result = hr;
90 code = -1;
91 }
92
93 if (SUCCEEDED(hr))
94 {
95 completionEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
96 if (!completionEvent)
97 {
98 *result = hr;
99 code = -2;
100 }
101 }
102
103 /* Need code for PrintTIcket here */
104
105 if (SUCCEEDED(hr))
106 {
107 WCHAR MBStr[64];
108
109 code = MultiByteToWideChar(CP_ACP, 0, printername, -1, MBStr, 64);
110 if (code != 0) {
111 if (FAILED(hr = StartXpsPrintJobPtr(
112 (LPCWSTR)MBStr,
113 NULL,
114 NULL,
115 NULL,
116 completionEvent,
117 NULL,
118 0,
119 &job,
120 &jobStream,
121 NULL
122 )))
123 {
124 *result = hr;
125 code = -4;
126 }
127 } else {
128 *result = 0;
129 code = -3;
130 hr = -1;
131 }
132 }
133
134 if (SUCCEEDED(hr))
135 {
136 if (FAILED(hr = CoCreateInstance(
137 __uuidof(XpsOMObjectFactory),
138 NULL,
139 CLSCTX_INPROC_SERVER,
140 __uuidof(IXpsOMObjectFactory),
141 reinterpret_cast<void**>(&xpsFactory)
142 )
143 )
144 )
145 {
146 *result = hr;
147 code = -5;
148 }
149 }
150
151 if (SUCCEEDED(hr))
152 {
153 WCHAR MBStr[MAX_PATH];
154
155 code = MultiByteToWideChar(CP_ACP, 0, filename, -1, MBStr, MAX_PATH);
156 if (code != 0) {
157 if (FAILED(hr = xpsFactory->CreatePackageFromFile((LPCWSTR)MBStr, false, &package))){
158 *result = hr;
159 code = -7;
160 }
161 } else {
162 hr = -1;
163 *result = 0;
164 code = -6;
165 }
166 }
167 if (SUCCEEDED(hr))
168 {
169 if (FAILED(hr = package->WriteToStream(jobStream, FALSE))) {
170 *result = hr;
171 code = -8;
172 }
173 }
174
175 if (SUCCEEDED(hr))
176 {
177 if (FAILED(hr = jobStream->Close()))
178 {
179 *result = hr;
180 code = -9;
181 }
182 }
183 else
184 {
185 // Only cancel the job if we succeeded in creating one in the first place.
186 if (job)
187 {
188 // Tell the XPS Print API that we're giving up. Don't overwrite hr with the return from
189 // this function.
190 job->Cancel();
191 }
192 }
193
194
195 if (SUCCEEDED(hr))
196 {
197 if (WaitForSingleObject(completionEvent, INFINITE) != WAIT_OBJECT_0)
198 {
199 *result = hr = HRESULT_FROM_WIN32(GetLastError());
200 code = -10;
201 }
202 }
203
204 if (SUCCEEDED(hr))
205 {
206 if (FAILED(hr = job->GetJobStatus(&jobStatus)))
207 {
208 *result = hr;
209 code = -11;
210 }
211 }
212
213 if (SUCCEEDED(hr))
214 {
215 switch (jobStatus.completion)
216 {
217 case XPS_JOB_COMPLETED:
218 break;
219 case XPS_JOB_CANCELLED:
220 hr = E_FAIL;
221 code = -12;
222 break;
223 case XPS_JOB_FAILED:
224 hr = E_FAIL;
225 *result = jobStatus.jobStatus;
226 code = -13;
227 break;
228 default:
229 hr = E_UNEXPECTED;
230 code = -14;
231 break;
232 }
233 }
234
235 if (fontResource)
236 {
237 fontResource->Release();
238 fontResource = NULL;
239 }
240
241 if (xpsPage)
242 {
243 xpsPage->Release();
244 xpsPage = NULL;
245 }
246
247 if (packageWriter)
248 {
249 packageWriter->Release();
250 packageWriter = NULL;
251 }
252
253 if (partUri)
254 {
255 partUri->Release();
256 partUri = NULL;
257 }
258
259 if (xpsFactory)
260 {
261 xpsFactory->Release();
262 xpsFactory = NULL;
263 }
264
265 if (jobStream)
266 {
267 jobStream->Release();
268 jobStream = NULL;
269 }
270
271 if (job)
272 {
273 job->Release();
274 job = NULL;
275 }
276
277 if (completionEvent)
278 {
279 CloseHandle(completionEvent);
280 completionEvent = NULL;
281 }
282
283 (void)FreeLibrary(dllHandle);
284 CoUninitialize();
285
286 return code;
287 }
288