1 //
2 // Class for creating OLE automation controllers.
3 //
4 // CreateObject() creates an automation object
5 // Invoke() will call a property or method of the automation object.
6 // GetProperty() returns a property
7 // SetProperty() changes a property
8 // Method() invokes a method
9 //
10 // For example, the following VB code will control Microsoft Word:
11 //
12 //    Private Sub Form_Load()
13 //    Dim wb As Object
14 //    Set wb = CreateObject("Word.Basic")
15 //    wb.AppShow
16 //    wb.FileNewDefault
17 //    wb.Insert "This is a test"
18 //    wb.FileSaveAs "c:\sample.doc)"
19 //    End Sub
20 //
21 // A C++ automation controller that does the same can be written as follows:
22 // the helper functions:
23 //
24 //   Void FormLoad ()
25 //   {
26 //       COleAutomationControl Aut;
27 //       Aut.CreateObject("Word.Basic");
28 //       Aut.Method ("AppShow");
29 //       Aut.Method ("FileNewDefault");
30 //       Aut.Method ("Insert", "s", (LPOLESTR) OLESTR ("This is a test"));
31 //       Aut.Method ("FileSaveAs", "s", OLESTR ("c:\\sample.doc"));
32 //   }
33 //
34 //
35 
36 #include "stdafx.h"
37 #include <stdarg.h>
38 #include "oleaut.h"
39 
40 #ifdef _DEBUG
41 #define new DEBUG_NEW
42 #undef THIS_FILE
43 static char THIS_FILE[] = __FILE__;
44 #endif
45 
46 
47 static bool CountArgsInFormat (LPCTSTR Format, UINT* nArgs);
48 static LPCTSTR GetNextVarType (LPCTSTR Format, VARTYPE* pVarType);
49 
50 
COleAutomationControl()51 COleAutomationControl::COleAutomationControl ()
52 {
53 	m_pDispatch = NULL;
54 	m_hResult = NOERROR;
55 	m_nErrArg = 0;
56 	VariantInit (&m_VariantResult);
57 }
58 
~COleAutomationControl()59 COleAutomationControl::~COleAutomationControl ()
60 {
61 	DeleteObject ();
62 }
63 
DeleteObject()64 void COleAutomationControl::DeleteObject ()
65 {
66 	if (m_pDispatch)
67 	{
68 		m_pDispatch->Release ();
69 		m_pDispatch = NULL;
70 	}
71 }
72 
73 // Creates an instance of the Automation object and
74 // obtains its IDispatch interface.
75 //
76 // Parameters:
77 // ProgId	  ProgID of Automation object
78 //
CreateObject(char * ProgId)79 bool COleAutomationControl::CreateObject (char* ProgId)
80 {
81 	CLSID ClsId;			// CLSID of automation object
82 	LPUNKNOWN pUnknown = NULL;	// IUnknown of automation object
83 
84 	// Retrieve CLSID from the progID that the user specified
85 	LPOLESTR OleProgId = TO_OLE_STR (ProgId);
86 	m_hResult = CLSIDFromProgID (OleProgId, &ClsId);
87 	if (FAILED (m_hResult))
88 		goto error;
89 
90 	// Create an instance of the automation object and ask for the
91 	// IDispatch interface
92 	m_hResult = CoCreateInstance (ClsId, NULL, CLSCTX_SERVER,
93 			       IID_IUnknown, (void**) &pUnknown);
94 	if (FAILED (m_hResult))
95 		goto error;
96 
97 	m_hResult = pUnknown->QueryInterface (IID_IDispatch, (void**) &m_pDispatch);
98 	if (FAILED (m_hResult))
99 		goto error;
100 
101 	pUnknown->Release ();
102 	return true;
103 
104 error:
105 	if (pUnknown)
106 		pUnknown->Release ();
107 	if (m_pDispatch)
108 		m_pDispatch->Release ();
109 	return false;
110 }
111 
112 // Return the dispatch id of a named service
113 // This id can be used in subsequent calls to GetProperty (), SetProperty () and
114 // Method (). This is the preferred method when performance is important.
115 //
GetDispatchId(char * Name)116 DISPID COleAutomationControl::GetDispatchId (char* Name)
117 {
118 	DISPID DispatchId;
119 
120 	ASSERT (m_pDispatch);
121 
122 	// Get DISPID of property/method
123 	LPOLESTR OleName = TO_OLE_STR (Name);
124 	m_hResult = m_pDispatch->GetIDsOfNames (IID_NULL, &OleName, 1,
125 						LOCALE_USER_DEFAULT, &DispatchId);
126 	if (FAILED (m_hResult))
127 		return NULL;
128 	return DispatchId;
129 }
130 
131 //  The following functions use these parameters:
132 //
133 // Parameters:
134 //
135 //  Name      Name of property or method.
136 //
137 //  Format    Format string that describes the variable list of parameters that
138 //	      follows. The format string can contain the following characters.
139 //	      & = mark the following format character as VT_BYREF
140 //	      B = VT_BOOL
141 //	      i = VT_I2
142 //	      I = VT_I4
143 //	      r = VT_R2
144 //	      R = VT_R4
145 //	      c = VT_CY
146 //	      s = VT_BSTR (string pointer can be passed,
147 //			BSTR will be allocated by this function).
148 //	      e = VT_ERROR
149 //	      d = VT_DATE
150 //	      v = VT_VARIANT. Use this to pass data types that are not described
151 //			in the format string. (For example SafeArrays).
152 //	      D = VT_DISPATCH
153 //	      U = VT_UNKNOWN
154 //
155 //  ...       Arguments of the property or method.
156 //	      Arguments are described by Format.
157 //
158 
GetProperty(char * Name)159 bool COleAutomationControl::GetProperty (char* Name)
160 {
161 	return Invoke (DISPATCH_PROPERTYGET, Name, NULL, NULL);
162 }
163 
GetProperty(DISPID DispatchId)164 bool COleAutomationControl::GetProperty (DISPID DispatchId)
165 {
166 	return Invoke (DISPATCH_PROPERTYGET, DispatchId, NULL, NULL);
167 }
168 
PutProperty(char * Name,LPCTSTR Format,...)169 bool COleAutomationControl::PutProperty (char* Name, LPCTSTR Format, ...)
170 {
171 	va_list ArgList;
172 
173 	va_start (ArgList, Format);
174 	bool bRet = Invoke (DISPATCH_PROPERTYPUT, Name, Format, ArgList);
175 	va_end (ArgList);
176 	return bRet;
177 }
178 
PutProperty(DISPID DispatchId,LPCTSTR Format,...)179 bool COleAutomationControl::PutProperty (DISPID DispatchId, LPCTSTR Format, ...)
180 {
181 	va_list ArgList;
182 
183 	va_start (ArgList, Format);
184 	bool bRet = Invoke (DISPATCH_PROPERTYPUT, DispatchId, Format, ArgList);
185 	va_end (ArgList);
186 	return bRet;
187 }
188 
Method(char * Name,LPCTSTR Format,...)189 bool COleAutomationControl::Method (char* Name, LPCTSTR Format, ...)
190 {
191 	va_list ArgList;
192 
193 	va_start (ArgList, Format);
194 	bool bRet = Invoke (DISPATCH_METHOD, Name, Format, ArgList);
195 	va_end (ArgList);
196 	return bRet;
197 }
198 
Method(DISPID DispatchId,LPCTSTR Format,...)199 bool COleAutomationControl::Method (DISPID DispatchId, LPCTSTR Format, ...)
200 {
201 	va_list ArgList;
202 
203 	va_start (ArgList, Format);
204 	bool bRet = Invoke (DISPATCH_METHOD, DispatchId, Format, ArgList);
205 	va_end (ArgList);
206 	return bRet;
207 }
208 
Invoke(WORD Flags,char * Name,LPCTSTR Format,va_list ArgList)209 bool COleAutomationControl::Invoke (WORD Flags, char* Name,
210 				    LPCTSTR Format, va_list ArgList)
211 {
212 	DISPID DispatchId = GetDispatchId (Name);
213 	if (! DispatchId)
214 		return false;
215 	return Invoke (Flags, DispatchId, Format, ArgList);
216 }
217 
Invoke(WORD Flags,DISPID DispatchId,LPCTSTR Format,va_list ArgList)218 bool COleAutomationControl::Invoke (WORD Flags, DISPID DispatchId,
219 				    LPCTSTR Format, va_list ArgList)
220 {
221 	UINT ArgCount = 0;
222 	VARIANTARG* ArgVector = NULL;
223 
224 	ASSERT (m_pDispatch);
225 
226 	DISPPARAMS DispatchParams;
227 	memset (&DispatchParams, 0, sizeof (DispatchParams));
228 
229 	// Determine number of arguments
230 	if (Format)
231 		CountArgsInFormat (Format, &ArgCount);
232 
233 	// Property puts have a named argument that represents the value that
234 	// the property is being assigned.
235 	DISPID DispIdNamed = DISPID_PROPERTYPUT;
236 	if (Flags & DISPATCH_PROPERTYPUT)
237 	{
238 		if (ArgCount == 0)
239 		{
240 			m_hResult = ResultFromScode (E_INVALIDARG);
241 			return false;
242 		}
243 		DispatchParams.cNamedArgs = 1;
244 		DispatchParams.rgdispidNamedArgs = &DispIdNamed;
245 	}
246 
247 	if (ArgCount)
248 	{
249 		// Allocate memory for all VARIANTARG parameters
250 		ArgVector = (VARIANTARG*) CoTaskMemAlloc (
251 				ArgCount * sizeof (VARIANTARG));
252 		if (! ArgVector)
253 		{
254 			m_hResult = ResultFromScode (E_OUTOFMEMORY);
255 			return false;
256 		}
257 		memset (ArgVector, 0, sizeof (VARIANTARG) * ArgCount);
258 
259 		// Get ready to walk vararg list
260 		LPCTSTR s = Format;
261 
262 		VARIANTARG *p = ArgVector + ArgCount - 1;  // Params go in opposite order
263 
264 		for (;;)
265 		{
266 			VariantInit (p);
267 			if (! (s = GetNextVarType (s, &p->vt)))
268 				break;
269 
270 			if (p < ArgVector)
271 			{
272 				m_hResult = ResultFromScode (E_INVALIDARG);
273 				goto Cleanup;
274 			}
275 			switch (p->vt)
276 			{
277 			    case VT_I2:
278 				V_I2 (p) = va_arg (ArgList, short);
279 				break;
280 			    case VT_I4:
281 				V_I4 (p) = va_arg (ArgList, long);
282 				break;
283 			    case VT_R4:
284 				V_R4 (p) = va_arg (ArgList, float);
285 				break;
286 			    case VT_DATE:
287 			    case VT_R8:
288 				V_R8 (p) = va_arg (ArgList, double);
289 				break;
290 			    case VT_CY:
291 				V_CY (p) = va_arg (ArgList, CY);
292 				break;
293 			    case VT_BSTR:
294 				V_BSTR (p) = SysAllocString (va_arg (ArgList,
295 								     OLECHAR*));
296 				if (! p->bstrVal)
297 				{
298 					m_hResult = ResultFromScode (E_OUTOFMEMORY);
299 					p->vt = VT_EMPTY;
300 					goto Cleanup;
301 				}
302 				break;
303 			    case VT_DISPATCH:
304 				V_DISPATCH (p) = va_arg (ArgList, LPDISPATCH);
305 				break;
306 			    case VT_ERROR:
307 				V_ERROR (p) = va_arg (ArgList, SCODE);
308 				break;
309 			    case VT_BOOL:
310 				V_BOOL (p) = va_arg (ArgList, BOOL) ? -1 : 0;
311 				break;
312 			    case VT_VARIANT:
313 				*p = va_arg (ArgList, VARIANTARG);
314 				break;
315 			    case VT_UNKNOWN:
316 				V_UNKNOWN (p) = va_arg (ArgList, LPUNKNOWN);
317 				break;
318 
319 			    case VT_I2 | VT_BYREF:
320 				V_I2REF (p) = va_arg (ArgList, short*);
321 				break;
322 			    case VT_I4 | VT_BYREF:
323 				V_I4REF (p) = va_arg (ArgList, long*);
324 				break;
325 			    case VT_R4 | VT_BYREF:
326 				V_R4REF (p) = va_arg (ArgList, float*);
327 				break;
328 			    case VT_R8 | VT_BYREF:
329 				V_R8REF (p) = va_arg (ArgList, double*);
330 				break;
331 			    case VT_DATE | VT_BYREF:
332 				V_DATEREF (p) = va_arg (ArgList, DATE*);
333 				break;
334 			    case VT_CY | VT_BYREF:
335 				V_CYREF (p) = va_arg (ArgList, CY*);
336 				break;
337 			    case VT_BSTR | VT_BYREF:
338 				V_BSTRREF (p) = va_arg (ArgList, BSTR*);
339 				break;
340 			    case VT_DISPATCH | VT_BYREF:
341 				V_DISPATCHREF (p) = va_arg (ArgList, LPDISPATCH*);
342 				break;
343 			    case VT_ERROR | VT_BYREF:
344 				V_ERRORREF (p) = va_arg (ArgList, SCODE*);
345 				break;
346 			    case VT_BOOL | VT_BYREF:
347 				{
348 					BOOL* pBool = va_arg (ArgList, BOOL*);
349 
350 					*pBool = 0;
351 					V_BOOLREF (p) = (VARIANT_BOOL*) pBool;
352 				}
353 				break;
354 			    case VT_VARIANT | VT_BYREF:
355 				V_VARIANTREF (p) = va_arg (ArgList, VARIANTARG*);
356 				break;
357 			    case VT_UNKNOWN | VT_BYREF:
358 				V_UNKNOWNREF (p) = va_arg (ArgList, LPUNKNOWN*);
359 				break;
360 
361 			    default:
362 				{
363 					m_hResult = ResultFromScode (E_INVALIDARG);
364 					goto Cleanup;
365 				}
366 				break;
367 			}
368 
369 			--p;	// Get ready to fill next argument
370 		}
371 	}
372 
373 	DispatchParams.cArgs = ArgCount;
374 	DispatchParams.rgvarg = ArgVector;
375 
376 	// Initialize return variant, in case caller forgot. Caller can pass
377 	// NULL if return value is not expected.
378 	VariantInit (&m_VariantResult);
379 
380 	// Make the call
381 	m_hResult = m_pDispatch->Invoke (DispatchId, IID_NULL, LOCALE_USER_DEFAULT,
382 					 Flags, &DispatchParams, &m_VariantResult,
383 					 &m_ExceptionInfo, &m_nErrArg);
384 
385     Cleanup:
386 	// Cleanup any arguments that need cleanup
387 	if (ArgCount)
388 	{
389 		VARIANTARG* p = ArgVector;
390 
391 		while (ArgCount--)
392 		{
393 			switch (p->vt)
394 			{
395 			    case VT_BSTR:
396 				VariantClear (p);
397 				break;
398 			}
399 			++p;
400 		}
401 		CoTaskMemFree (ArgVector);
402 	}
403 
404 	return FAILED (m_hResult) ? false : true;
405 }
406 
407 #define CASE_SCODE(sc)  \
408 	case sc: \
409 	lstrcpy((char*)ErrName, (char*)#sc); \
410 	break;
411 
ErrDiag()412 void COleAutomationControl::ErrDiag ()
413 {
414 	char ErrName[200];
415 
416 	SCODE sc = GetScode (m_hResult);
417 	switch (sc)
418 	{
419 	    // SCODE's defined in SCODE.H
420 	    CASE_SCODE (S_OK)
421 	    CASE_SCODE (S_FALSE)
422 	    CASE_SCODE (E_UNEXPECTED)
423 	    CASE_SCODE (E_OUTOFMEMORY)
424 	    CASE_SCODE (E_INVALIDARG)
425 	    CASE_SCODE (E_NOINTERFACE)
426 	    CASE_SCODE (E_POINTER)
427 	    CASE_SCODE (E_HANDLE)
428 	    CASE_SCODE (E_ABORT)
429 	    CASE_SCODE (E_FAIL)
430 	    CASE_SCODE (E_ACCESSDENIED)
431 
432 	    // SCODE's defined in OLE2.H
433 	    CASE_SCODE (OLE_E_OLEVERB)
434 	    CASE_SCODE (OLE_E_ADVF)
435 	    CASE_SCODE (OLE_E_ENUM_NOMORE)
436 	    CASE_SCODE (OLE_E_ADVISENOTSUPPORTED)
437 	    CASE_SCODE (OLE_E_NOCONNECTION)
438 	    CASE_SCODE (OLE_E_NOTRUNNING)
439 	    CASE_SCODE (OLE_E_NOCACHE)
440 	    CASE_SCODE (OLE_E_BLANK)
441 	    CASE_SCODE (OLE_E_CLASSDIFF)
442 	    CASE_SCODE (OLE_E_CANT_GETMONIKER)
443 	    CASE_SCODE (OLE_E_CANT_BINDTOSOURCE)
444 	    CASE_SCODE (OLE_E_STATIC)
445 	    CASE_SCODE (OLE_E_PROMPTSAVECANCELLED)
446 	    CASE_SCODE (OLE_E_INVALIDRECT)
447 	    CASE_SCODE (OLE_E_WRONGCOMPOBJ)
448 	    CASE_SCODE (OLE_E_INVALIDHWND)
449 	    CASE_SCODE (OLE_E_NOT_INPLACEACTIVE)
450 	    CASE_SCODE (OLE_E_CANTCONVERT)
451 	    CASE_SCODE (OLE_E_NOSTORAGE)
452 
453 	    CASE_SCODE (DV_E_FORMATETC)
454 	    CASE_SCODE (DV_E_DVTARGETDEVICE)
455 	    CASE_SCODE (DV_E_STGMEDIUM)
456 	    CASE_SCODE (DV_E_STATDATA)
457 	    CASE_SCODE (DV_E_LINDEX)
458 	    CASE_SCODE (DV_E_TYMED)
459 	    CASE_SCODE (DV_E_CLIPFORMAT)
460 	    CASE_SCODE (DV_E_DVASPECT)
461 	    CASE_SCODE (DV_E_DVTARGETDEVICE_SIZE)
462 	    CASE_SCODE (DV_E_NOIVIEWOBJECT)
463 
464 	    CASE_SCODE (OLE_S_USEREG)
465 	    CASE_SCODE (OLE_S_STATIC)
466 	    CASE_SCODE (OLE_S_MAC_CLIPFORMAT)
467 
468 	    CASE_SCODE (CONVERT10_E_OLESTREAM_GET)
469 	    CASE_SCODE (CONVERT10_E_OLESTREAM_PUT)
470 	    CASE_SCODE (CONVERT10_E_OLESTREAM_FMT)
471 	    CASE_SCODE (CONVERT10_E_OLESTREAM_BITMAP_TO_DIB)
472 	    CASE_SCODE (CONVERT10_E_STG_FMT)
473 	    CASE_SCODE (CONVERT10_E_STG_NO_STD_STREAM)
474 	    CASE_SCODE (CONVERT10_E_STG_DIB_TO_BITMAP)
475 	    CASE_SCODE (CONVERT10_S_NO_PRESENTATION)
476 
477 	    CASE_SCODE (CLIPBRD_E_CANT_OPEN)
478 	    CASE_SCODE (CLIPBRD_E_CANT_EMPTY)
479 	    CASE_SCODE (CLIPBRD_E_CANT_SET)
480 	    CASE_SCODE (CLIPBRD_E_BAD_DATA)
481 	    CASE_SCODE (CLIPBRD_E_CANT_CLOSE)
482 
483 	    CASE_SCODE (DRAGDROP_E_NOTREGISTERED)
484 	    CASE_SCODE (DRAGDROP_E_ALREADYREGISTERED)
485 	    CASE_SCODE (DRAGDROP_E_INVALIDHWND)
486 	    CASE_SCODE (DRAGDROP_S_DROP)
487 	    CASE_SCODE (DRAGDROP_S_CANCEL)
488 	    CASE_SCODE (DRAGDROP_S_USEDEFAULTCURSORS)
489 
490 	    CASE_SCODE (OLEOBJ_E_NOVERBS)
491 	    CASE_SCODE (OLEOBJ_E_INVALIDVERB)
492 	    CASE_SCODE (OLEOBJ_S_INVALIDVERB)
493 	    CASE_SCODE (OLEOBJ_S_CANNOT_DOVERB_NOW)
494 	    CASE_SCODE (OLEOBJ_S_INVALIDHWND)
495 	    CASE_SCODE (INPLACE_E_NOTUNDOABLE)
496 	    CASE_SCODE (INPLACE_E_NOTOOLSPACE)
497 	    CASE_SCODE (INPLACE_S_TRUNCATED)
498 
499 	    // SCODE's defined in COMPOBJ.H
500 	    CASE_SCODE (CO_E_NOTINITIALIZED)
501 	    CASE_SCODE (CO_E_ALREADYINITIALIZED)
502 	    CASE_SCODE (CO_E_CANTDETERMINECLASS)
503 	    CASE_SCODE (CO_E_CLASSSTRING)
504 	    CASE_SCODE (CO_E_IIDSTRING)
505 	    CASE_SCODE (CO_E_APPNOTFOUND)
506 	    CASE_SCODE (CO_E_APPSINGLEUSE)
507 	    CASE_SCODE (CO_E_ERRORINAPP)
508 	    CASE_SCODE (CO_E_DLLNOTFOUND)
509 	    CASE_SCODE (CO_E_ERRORINDLL)
510 	    CASE_SCODE (CO_E_WRONGOSFORAPP)
511 	    CASE_SCODE (CO_E_OBJNOTREG)
512 	    CASE_SCODE (CO_E_OBJISREG)
513 	    CASE_SCODE (CO_E_OBJNOTCONNECTED)
514 	    CASE_SCODE (CO_E_APPDIDNTREG)
515 	    CASE_SCODE (CLASS_E_NOAGGREGATION)
516 	    CASE_SCODE (CLASS_E_CLASSNOTAVAILABLE)
517 	    CASE_SCODE (REGDB_E_READREGDB)
518 	    CASE_SCODE (REGDB_E_WRITEREGDB)
519 	    CASE_SCODE (REGDB_E_KEYMISSING)
520 	    CASE_SCODE (REGDB_E_INVALIDVALUE)
521 	    CASE_SCODE (REGDB_E_CLASSNOTREG)
522 	    CASE_SCODE (REGDB_E_IIDNOTREG)
523 	    CASE_SCODE (RPC_E_CALL_REJECTED)
524 	    CASE_SCODE (RPC_E_CALL_CANCELED)
525 	    CASE_SCODE (RPC_E_CANTPOST_INSENDCALL)
526 	    CASE_SCODE (RPC_E_CANTCALLOUT_INASYNCCALL)
527 	    CASE_SCODE (RPC_E_CANTCALLOUT_INEXTERNALCALL)
528 	    CASE_SCODE (RPC_E_CONNECTION_TERMINATED)
529 	    CASE_SCODE (RPC_E_SERVER_DIED)
530 	    CASE_SCODE (RPC_E_CLIENT_DIED)
531 	    CASE_SCODE (RPC_E_INVALID_DATAPACKET)
532 	    CASE_SCODE (RPC_E_CANTTRANSMIT_CALL)
533 	    CASE_SCODE (RPC_E_CLIENT_CANTMARSHAL_DATA)
534 	    CASE_SCODE (RPC_E_CLIENT_CANTUNMARSHAL_DATA)
535 	    CASE_SCODE (RPC_E_SERVER_CANTMARSHAL_DATA)
536 	    CASE_SCODE (RPC_E_SERVER_CANTUNMARSHAL_DATA)
537 	    CASE_SCODE (RPC_E_INVALID_DATA)
538 	    CASE_SCODE (RPC_E_INVALID_PARAMETER)
539 	    CASE_SCODE (RPC_E_CANTCALLOUT_AGAIN)
540 	    CASE_SCODE (RPC_E_UNEXPECTED)
541 
542 	    // SCODE's defined in DVOBJ.H
543 	    CASE_SCODE (DATA_S_SAMEFORMATETC)
544 	    CASE_SCODE (VIEW_E_DRAW)
545 	    CASE_SCODE (VIEW_S_ALREADY_FROZEN)
546 	    CASE_SCODE (CACHE_E_NOCACHE_UPDATED)
547 	    CASE_SCODE (CACHE_S_FORMATETC_NOTSUPPORTED)
548 	    CASE_SCODE (CACHE_S_SAMECACHE)
549 	    CASE_SCODE (CACHE_S_SOMECACHES_NOTUPDATED)
550 
551 	    // SCODE's defined in STORAGE.H
552 	    CASE_SCODE (STG_E_INVALIDFUNCTION)
553 	    CASE_SCODE (STG_E_FILENOTFOUND)
554 	    CASE_SCODE (STG_E_PATHNOTFOUND)
555 	    CASE_SCODE (STG_E_TOOMANYOPENFILES)
556 	    CASE_SCODE (STG_E_ACCESSDENIED)
557 	    CASE_SCODE (STG_E_INVALIDHANDLE)
558 	    CASE_SCODE (STG_E_INSUFFICIENTMEMORY)
559 	    CASE_SCODE (STG_E_INVALIDPOINTER)
560 	    CASE_SCODE (STG_E_NOMOREFILES)
561 	    CASE_SCODE (STG_E_DISKISWRITEPROTECTED)
562 	    CASE_SCODE (STG_E_SEEKERROR)
563 	    CASE_SCODE (STG_E_WRITEFAULT)
564 	    CASE_SCODE (STG_E_READFAULT)
565 	    CASE_SCODE (STG_E_SHAREVIOLATION)
566 	    CASE_SCODE (STG_E_LOCKVIOLATION)
567 	    CASE_SCODE (STG_E_FILEALREADYEXISTS)
568 	    CASE_SCODE (STG_E_INVALIDPARAMETER)
569 	    CASE_SCODE (STG_E_MEDIUMFULL)
570 	    CASE_SCODE (STG_E_ABNORMALAPIEXIT)
571 	    CASE_SCODE (STG_E_INVALIDHEADER)
572 	    CASE_SCODE (STG_E_INVALIDNAME)
573 	    CASE_SCODE (STG_E_UNKNOWN)
574 	    CASE_SCODE (STG_E_UNIMPLEMENTEDFUNCTION)
575 	    CASE_SCODE (STG_E_INVALIDFLAG)
576 	    CASE_SCODE (STG_E_INUSE)
577 	    CASE_SCODE (STG_E_NOTCURRENT)
578 	    CASE_SCODE (STG_E_REVERTED)
579 	    CASE_SCODE (STG_E_CANTSAVE)
580 	    CASE_SCODE (STG_E_OLDFORMAT)
581 	    CASE_SCODE (STG_E_OLDDLL)
582 	    CASE_SCODE (STG_E_SHAREREQUIRED)
583 	    CASE_SCODE (STG_E_NOTFILEBASEDSTORAGE)
584 	    CASE_SCODE (STG_E_EXTANTMARSHALLINGS)
585 	    CASE_SCODE (STG_S_CONVERTED)
586 
587 	    // SCODE's defined in STORAGE.H
588 	    CASE_SCODE (MK_E_CONNECTMANUALLY)
589 	    CASE_SCODE (MK_E_EXCEEDEDDEADLINE)
590 	    CASE_SCODE (MK_E_NEEDGENERIC)
591 	    CASE_SCODE (MK_E_UNAVAILABLE)
592 	    CASE_SCODE (MK_E_SYNTAX)
593 	    CASE_SCODE (MK_E_NOOBJECT)
594 	    CASE_SCODE (MK_E_INVALIDEXTENSION)
595 	    CASE_SCODE (MK_E_INTERMEDIATEINTERFACENOTSUPPORTED)
596 	    CASE_SCODE (MK_E_NOTBINDABLE)
597 	    CASE_SCODE (MK_E_NOTBOUND)
598 	    CASE_SCODE (MK_E_CANTOPENFILE)
599 	    CASE_SCODE (MK_E_MUSTBOTHERUSER)
600 	    CASE_SCODE (MK_E_NOINVERSE)
601 	    CASE_SCODE (MK_E_NOSTORAGE)
602 	    CASE_SCODE (MK_E_NOPREFIX)
603 	    CASE_SCODE (MK_S_REDUCED_TO_SELF)
604 	    CASE_SCODE (MK_S_ME)
605 	    CASE_SCODE (MK_S_HIM)
606 	    CASE_SCODE (MK_S_US)
607 	    CASE_SCODE (MK_S_MONIKERALREADYREGISTERED)
608 
609 	    // SCODE's defined in DISPATCH.H
610 	    CASE_SCODE (DISP_E_UNKNOWNINTERFACE)
611 	    CASE_SCODE (DISP_E_MEMBERNOTFOUND)
612 	    CASE_SCODE (DISP_E_PARAMNOTFOUND)
613 	    CASE_SCODE (DISP_E_TYPEMISMATCH)
614 	    CASE_SCODE (DISP_E_UNKNOWNNAME)
615 	    CASE_SCODE (DISP_E_NONAMEDARGS)
616 	    CASE_SCODE (DISP_E_BADVARTYPE)
617 	    CASE_SCODE (DISP_E_EXCEPTION)
618 	    CASE_SCODE (DISP_E_OVERFLOW)
619 	    CASE_SCODE (DISP_E_BADINDEX)
620 	    CASE_SCODE (DISP_E_UNKNOWNLCID)
621 	    CASE_SCODE (DISP_E_ARRAYISLOCKED)
622 	    CASE_SCODE (DISP_E_BADPARAMCOUNT)
623 	    CASE_SCODE (DISP_E_PARAMNOTOPTIONAL)
624 	    CASE_SCODE (DISP_E_BADCALLEE)
625 	    CASE_SCODE (DISP_E_NOTACOLLECTION)
626 
627 	    CASE_SCODE (TYPE_E_BUFFERTOOSMALL)
628 	    CASE_SCODE (TYPE_E_INVDATAREAD)
629 	    CASE_SCODE (TYPE_E_UNSUPFORMAT)
630 	    CASE_SCODE (TYPE_E_REGISTRYACCESS)
631 	    CASE_SCODE (TYPE_E_LIBNOTREGISTERED)
632 	    CASE_SCODE (TYPE_E_UNDEFINEDTYPE)
633 	    CASE_SCODE (TYPE_E_QUALIFIEDNAMEDISALLOWED)
634 	    CASE_SCODE (TYPE_E_INVALIDSTATE)
635 	    CASE_SCODE (TYPE_E_WRONGTYPEKIND)
636 	    CASE_SCODE (TYPE_E_ELEMENTNOTFOUND)
637 	    CASE_SCODE (TYPE_E_AMBIGUOUSNAME)
638 	    CASE_SCODE (TYPE_E_NAMECONFLICT)
639 	    CASE_SCODE (TYPE_E_UNKNOWNLCID)
640 	    CASE_SCODE (TYPE_E_DLLFUNCTIONNOTFOUND)
641 	    CASE_SCODE (TYPE_E_BADMODULEKIND)
642 	    CASE_SCODE (TYPE_E_SIZETOOBIG)
643 	    CASE_SCODE (TYPE_E_DUPLICATEID)
644 	    CASE_SCODE (TYPE_E_TYPEMISMATCH)
645 	    CASE_SCODE (TYPE_E_OUTOFBOUNDS)
646 	    CASE_SCODE (TYPE_E_IOERROR)
647 	    CASE_SCODE (TYPE_E_CANTCREATETMPFILE)
648 	    CASE_SCODE (TYPE_E_CANTLOADLIBRARY)
649 	    CASE_SCODE (TYPE_E_INCONSISTENTPROPFUNCS)
650 	    CASE_SCODE (TYPE_E_CIRCULARTYPE)
651 
652 	    default:
653 		lstrcpy (ErrName, "UNKNOWN SCODE");
654 	}
655 
656 	char Buf[256];
657 	sprintf (Buf, "An OLE error occurred:\r\nCode = %s\r\nResult = %lx.",
658 		 (char*) ErrName, m_hResult);
659 	MessageBox (NULL, Buf, "OLE Error", MB_OK);
660 }
661 
662 
CountArgsInFormat(LPCTSTR Format,UINT * pArgCount)663 static bool CountArgsInFormat (LPCTSTR Format, UINT* pArgCount)
664 {
665 	*pArgCount = 0;
666 
667 	if (! Format)
668 		return true;
669 
670 	while (*Format)
671 	{
672 		if (*Format == '&')
673 			Format++;
674 
675 		switch (*Format)
676 		{
677 		    case 'b':
678 		    case 'i':
679 		    case 'I':
680 		    case 'r':
681 		    case 'R':
682 		    case 'c':
683 		    case 's':
684 		    case 'e':
685 		    case 'd':
686 		    case 'v':
687 		    case 'D':
688 		    case 'U':
689 			++ (*pArgCount);
690 			Format++;
691 			break;
692 		    case '\0':
693 		    default:
694 			return false;
695 		}
696 	}
697 	return true;
698 }
699 
GetNextVarType(LPCTSTR Format,VARTYPE * pVarType)700 static LPCTSTR GetNextVarType (LPCTSTR Format, VARTYPE* pVarType)
701 {
702 	*pVarType = 0;
703 	if (*Format == '&')
704 	{
705 		*pVarType = VT_BYREF;
706 		Format++;
707 		if (!*Format)
708 			return NULL;
709 	}
710 	switch (*Format)
711 	{
712 	    case 'b':
713 		*pVarType |= VT_BOOL;
714 		break;
715 	    case 'i':
716 		*pVarType |= VT_I2;
717 		break;
718 	    case 'I':
719 		*pVarType |= VT_I4;
720 		break;
721 	    case 'r':
722 		*pVarType |= VT_R4;
723 		break;
724 	    case 'R':
725 		*pVarType |= VT_R8;
726 		break;
727 	    case 'c':
728 		*pVarType |= VT_CY;
729 		break;
730 	    case 's':
731 		*pVarType |= VT_BSTR;
732 		break;
733 	    case 'e':
734 		*pVarType |= VT_ERROR;
735 		break;
736 	    case 'd':
737 		*pVarType |= VT_DATE;
738 		break;
739 	    case 'v':
740 		*pVarType |= VT_VARIANT;
741 		break;
742 	    case 'U':
743 		*pVarType |= VT_UNKNOWN;
744 		break;
745 	    case 'D':
746 		*pVarType |= VT_DISPATCH;
747 		break;
748 	    case '\0':
749 		return NULL;	// End of Format string
750 	    default:
751 		return NULL;
752 	}
753 	return ++Format;
754 }
755 
756 #ifndef UNICODE
ConvertToAnsi(OLECHAR * sUnicode)757 char* ConvertToAnsi (OLECHAR* sUnicode)
758 {
759 	static char BufAscii[MAX_OLE_STR];
760 	return ConvertToAnsiBuf (sUnicode, BufAscii);
761 }
762 
ConvertToAnsiBuf(OLECHAR * sUnicode,char * BufAscii)763 char* ConvertToAnsiBuf (OLECHAR* sUnicode, char* BufAscii)
764 {
765 	WideCharToMultiByte (CP_ACP, 0, sUnicode, -1, BufAscii, MAX_OLE_STR, NULL, NULL);
766 	return BufAscii;
767 }
768 
ConvertToUnicode(char * sAscii)769 OLECHAR* ConvertToUnicode (char* sAscii)
770 {
771 	static OLECHAR BufUnicode[MAX_OLE_STR];
772 	return ConvertToUnicodeBuf (sAscii, BufUnicode);
773 }
774 
ConvertToUnicodeBuf(char * sAscii,OLECHAR * BufUnicode)775 OLECHAR* ConvertToUnicodeBuf (char* sAscii, OLECHAR* BufUnicode)
776 {
777 	MultiByteToWideChar (CP_ACP, 0, sAscii, -1, BufUnicode, MAX_OLE_STR);
778 	return BufUnicode;
779 }
780 #endif
781 
782