makegwparse.py
29.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
"""Utilities for makegw - Parse a header file to build an interface
This module contains the core code for parsing a header file describing a
COM interface, and building it into an "Interface" structure.
Each Interface has methods, and each method has arguments.
Each argument knows how to use Py_BuildValue or Py_ParseTuple to
exchange itself with Python.
See the @win32com.makegw@ module for information in building a COM
interface
"""
import re
import traceback
class error_not_found(Exception):
def __init__(self, msg="The requested item could not be found"):
super(error_not_found, self).__init__(msg)
class error_not_supported(Exception):
def __init__(self, msg="The required functionality is not supported"):
super(error_not_supported, self).__init__(msg)
VERBOSE=0
DEBUG=0
## NOTE : For interfaces as params to work correctly, you must
## make sure any PythonCOM extensions which expose the interface are loaded
## before generating.
class ArgFormatter:
"""An instance for a specific type of argument. Knows how to convert itself"""
def __init__(self, arg, builtinIndirection, declaredIndirection = 0):
#print 'init:', arg.name, builtinIndirection, declaredIndirection, arg.indirectionLevel
self.arg = arg
self.builtinIndirection = builtinIndirection
self.declaredIndirection = declaredIndirection
self.gatewayMode = 0
def _IndirectPrefix(self, indirectionFrom, indirectionTo):
"""Given the indirection level I was declared at (0=Normal, 1=*, 2=**)
return a string prefix so I can pass to a function with the
required indirection (where the default is the indirection of the method's param.
eg, assuming my arg has indirection level of 2, if this function was passed 1
it would return "&", so that a variable declared with indirection of 1
can be prefixed with this to turn it into the indirection level required of 2
"""
dif = indirectionFrom - indirectionTo
if dif==0:
return ""
elif dif==-1:
return "&"
elif dif==1:
return "*"
else:
return "?? (%d)" % (dif,)
raise error_not_supported("Can't indirect this far - please fix me :-)")
def GetIndirectedArgName(self, indirectFrom, indirectionTo):
#print 'get:',self.arg.name, indirectFrom,self._GetDeclaredIndirection() + self.builtinIndirection, indirectionTo, self.arg.indirectionLevel
if indirectFrom is None:
### ACK! this does not account for [in][out] variables.
### when this method is called, we need to know which
indirectFrom = self._GetDeclaredIndirection() + self.builtinIndirection
return self._IndirectPrefix(indirectFrom, indirectionTo) + self.arg.name
def GetBuildValueArg(self):
"Get the argument to be passes to Py_BuildValue"
return self.arg.name
def GetParseTupleArg(self):
"Get the argument to be passed to PyArg_ParseTuple"
if self.gatewayMode:
# use whatever they were declared with
return self.GetIndirectedArgName(None, 1)
# local declarations have just their builtin indirection
return self.GetIndirectedArgName(self.builtinIndirection, 1)
def GetInterfaceCppObjectInfo(self):
"""Provide information about the C++ object used.
Simple variables (such as integers) can declare their type (eg an integer)
and use it as the target of both PyArg_ParseTuple and the COM function itself.
More complex types require a PyObject * declared as the target of PyArg_ParseTuple,
then some conversion routine to the C++ object which is actually passed to COM.
This method provides the name, and optionally the type of that C++ variable.
If the type if provided, the caller will likely generate a variable declaration.
The name must always be returned.
Result is a tuple of (variableName, [DeclareType|None|""])
"""
# the first return element is the variable to be passed as
# an argument to an interface method. the variable was
# declared with only its builtin indirection level. when
# we pass it, we'll need to pass in whatever amount of
# indirection was applied (plus the builtin amount)
# the second return element is the variable declaration; it
# should simply be builtin indirection
return self.GetIndirectedArgName(self.builtinIndirection, self.arg.indirectionLevel + self.builtinIndirection), \
"%s %s" % (self.GetUnconstType(), self.arg.name)
def GetInterfaceArgCleanup(self):
"Return cleanup code for C++ args passed to the interface method."
if DEBUG:
return "/* GetInterfaceArgCleanup output goes here: %s */\n" % self.arg.name
else:
return ""
def GetInterfaceArgCleanupGIL(self):
"""Return cleanup code for C++ args passed to the interface
method that must be executed with the GIL held"""
if DEBUG:
return "/* GetInterfaceArgCleanup (GIL held) output goes here: %s */\n" % self.arg.name
else:
return ""
def GetUnconstType(self):
return self.arg.unc_type
def SetGatewayMode(self):
self.gatewayMode = 1
def _GetDeclaredIndirection(self):
return self.arg.indirectionLevel
print 'declared:', self.arg.name, self.gatewayMode
if self.gatewayMode:
return self.arg.indirectionLevel
else:
return self.declaredIndirection
def DeclareParseArgTupleInputConverter(self):
"Declare the variable used as the PyArg_ParseTuple param for a gateway"
# Only declare it??
#if self.arg.indirectionLevel==0:
# return "\t%s %s;\n" % (self.arg.type, self.arg.name)
#else:
if DEBUG:
return "/* Declare ParseArgTupleInputConverter goes here: %s */\n" % self.arg.name
else:
return ""
def GetParsePostCode(self):
"Get a string of C++ code to be executed after (ie, to finalise) the PyArg_ParseTuple conversion"
if DEBUG:
return "/* GetParsePostCode code goes here: %s */\n" % self.arg.name
else:
return ""
def GetBuildForInterfacePreCode(self):
"Get a string of C++ code to be executed before (ie, to initialise) the Py_BuildValue conversion for Interfaces"
if DEBUG:
return "/* GetBuildForInterfacePreCode goes here: %s */\n" % self.arg.name
else:
return ""
def GetBuildForGatewayPreCode(self):
"Get a string of C++ code to be executed before (ie, to initialise) the Py_BuildValue conversion for Gateways"
s = self.GetBuildForInterfacePreCode() # Usually the same
if DEBUG:
if s[:4] == "/* G":
s = "/* GetBuildForGatewayPreCode goes here: %s */\n" % self.arg.name
return s
def GetBuildForInterfacePostCode(self):
"Get a string of C++ code to be executed after (ie, to finalise) the Py_BuildValue conversion for Interfaces"
if DEBUG:
return "/* GetBuildForInterfacePostCode goes here: %s */\n" % self.arg.name
return ""
def GetBuildForGatewayPostCode(self):
"Get a string of C++ code to be executed after (ie, to finalise) the Py_BuildValue conversion for Gateways"
s = self.GetBuildForInterfacePostCode() # Usually the same
if DEBUG:
if s[:4] == "/* G":
s = "/* GetBuildForGatewayPostCode goes here: %s */\n" % self.arg.name
return s
def GetAutoduckString(self):
return '// @pyparm %s|%s||Description for %s' % (self._GetPythonTypeDesc(), self.arg.name, self.arg.name)
def _GetPythonTypeDesc(self):
"Returns a string with the description of the type. Used for doco purposes"
return None
def NeedUSES_CONVERSION(self):
"Determines if this arg forces a USES_CONVERSION macro"
return 0
# Special formatter for floats since they're smaller than Python floats.
class ArgFormatterFloat(ArgFormatter):
def GetFormatChar(self):
return "f"
def DeclareParseArgTupleInputConverter(self):
# Declare a double variable
return "\tdouble dbl%s;\n" % self.arg.name
def GetParseTupleArg(self):
return "&dbl" + self.arg.name
def _GetPythonTypeDesc(self):
return "float"
def GetBuildValueArg(self):
return "&dbl" + self.arg.name
def GetBuildForInterfacePreCode(self):
return "\tdbl" + self.arg.name + " = " + self.arg.name + ";\n"
def GetBuildForGatewayPreCode(self):
return "\tdbl%s = " % self.arg.name + self._IndirectPrefix( \
self._GetDeclaredIndirection(),
0) + self.arg.name + ";\n"
def GetParsePostCode(self):
s = "\t"
if self.gatewayMode:
s = s + self._IndirectPrefix(
self._GetDeclaredIndirection(),
0)
s = s + self.arg.name
s = s + " = (float)dbl%s;\n" % self.arg.name
return s
# Special formatter for Shorts because they're
# a different size than Python ints!
class ArgFormatterShort(ArgFormatter):
def GetFormatChar(self):
return "i"
def DeclareParseArgTupleInputConverter(self):
# Declare a double variable
return "\tINT i%s;\n" % self.arg.name
def GetParseTupleArg(self):
return "&i" + self.arg.name
def _GetPythonTypeDesc(self):
return "int"
def GetBuildValueArg(self):
return "&i" + self.arg.name
def GetBuildForInterfacePreCode(self):
return "\ti" + self.arg.name + " = " + self.arg.name + ";\n"
def GetBuildForGatewayPreCode(self):
return "\ti%s = " % self.arg.name + self._IndirectPrefix( \
self._GetDeclaredIndirection(),
0) + self.arg.name + ";\n"
def GetParsePostCode(self):
s = "\t"
if self.gatewayMode:
s = s + self._IndirectPrefix(
self._GetDeclaredIndirection(),
0)
s = s + self.arg.name
s = s + " = i%s;\n" % self.arg.name
return s
# for types which are 64bits on AMD64 - eg, HWND
class ArgFormatterLONG_PTR(ArgFormatter):
def GetFormatChar(self):
return "O"
def DeclareParseArgTupleInputConverter(self):
# Declare a PyObject variable
return "\tPyObject *ob%s;\n" % self.arg.name
def GetParseTupleArg(self):
return "&ob"+self.arg.name
def _GetPythonTypeDesc(self):
return "int/long"
def GetBuildValueArg(self):
return "ob" + self.arg.name
def GetBuildForInterfacePostCode(self):
return "\tPy_XDECREF(ob%s);\n" % self.arg.name
def DeclareParseArgTupleInputConverter(self):
# Declare a PyObject variable
return "\tPyObject *ob%s;\n" % self.arg.name
def GetParsePostCode(self):
return "\tif (bPythonIsHappy && !PyWinLong_AsULONG_PTR(ob%s, (ULONG_PTR *)%s)) bPythonIsHappy = FALSE;\n" % (self.arg.name, self.GetIndirectedArgName(None, 2))
def GetBuildForInterfacePreCode(self):
notdirected = self.GetIndirectedArgName(None, 1)
return "\tob%s = PyWinObject_FromULONG_PTR(%s);\n" % \
(self.arg.name, notdirected)
def GetBuildForGatewayPostCode(self):
return "\tPy_XDECREF(ob%s);\n" % self.arg.name
class ArgFormatterPythonCOM(ArgFormatter):
"""An arg formatter for types exposed in the PythonCOM module"""
def GetFormatChar(self):
return "O"
#def GetInterfaceCppObjectInfo(self):
# return ArgFormatter.GetInterfaceCppObjectInfo(self)[0], \
# "%s %s%s" % (self.arg.unc_type, "*" * self._GetDeclaredIndirection(), self.arg.name)
def DeclareParseArgTupleInputConverter(self):
# Declare a PyObject variable
return "\tPyObject *ob%s;\n" % self.arg.name
def GetParseTupleArg(self):
return "&ob"+self.arg.name
def _GetPythonTypeDesc(self):
return "<o Py%s>" % self.arg.type
def GetBuildValueArg(self):
return "ob" + self.arg.name
def GetBuildForInterfacePostCode(self):
return "\tPy_XDECREF(ob%s);\n" % self.arg.name
def DeclareParseArgTupleInputConverter(self):
# Declare a PyObject variable
return "\tPyObject *ob%s;\n" % self.arg.name
class ArgFormatterBSTR(ArgFormatterPythonCOM):
def _GetPythonTypeDesc(self):
return "<o unicode>"
def GetParsePostCode(self):
return "\tif (bPythonIsHappy && !PyWinObject_AsBstr(ob%s, %s)) bPythonIsHappy = FALSE;\n" % (self.arg.name, self.GetIndirectedArgName(None, 2))
def GetBuildForInterfacePreCode(self):
notdirected = self.GetIndirectedArgName(None, 1)
return "\tob%s = MakeBstrToObj(%s);\n" % \
(self.arg.name, notdirected)
def GetBuildForInterfacePostCode(self):
return "\tSysFreeString(%s);\n" % (self.arg.name,) + \
ArgFormatterPythonCOM.GetBuildForInterfacePostCode(self)
def GetBuildForGatewayPostCode(self):
return "\tPy_XDECREF(ob%s);\n" % self.arg.name
class ArgFormatterOLECHAR(ArgFormatterPythonCOM):
def _GetPythonTypeDesc(self):
return "<o unicode>"
def GetUnconstType(self):
if self.arg.type[:3]=="LPC":
return self.arg.type[:2] + self.arg.type[3:]
else:
return self.arg.unc_type
def GetParsePostCode(self):
return "\tif (bPythonIsHappy && !PyWinObject_AsBstr(ob%s, %s)) bPythonIsHappy = FALSE;\n" % (self.arg.name, self.GetIndirectedArgName(None, 2))
def GetInterfaceArgCleanup(self):
return "\tSysFreeString(%s);\n" % self.GetIndirectedArgName(None, 1)
def GetBuildForInterfacePreCode(self):
# the variable was declared with just its builtin indirection
notdirected = self.GetIndirectedArgName(self.builtinIndirection, 1)
return "\tob%s = MakeOLECHARToObj(%s);\n" % \
(self.arg.name, notdirected)
def GetBuildForInterfacePostCode(self):
# memory returned into an OLECHAR should be freed
return "\tCoTaskMemFree(%s);\n" % (self.arg.name,) + \
ArgFormatterPythonCOM.GetBuildForInterfacePostCode(self)
def GetBuildForGatewayPostCode(self):
return "\tPy_XDECREF(ob%s);\n" % self.arg.name
class ArgFormatterTCHAR(ArgFormatterPythonCOM):
def _GetPythonTypeDesc(self):
return "string/<o unicode>"
def GetUnconstType(self):
if self.arg.type[:3]=="LPC":
return self.arg.type[:2] + self.arg.type[3:]
else:
return self.arg.unc_type
def GetParsePostCode(self):
return "\tif (bPythonIsHappy && !PyWinObject_AsTCHAR(ob%s, %s)) bPythonIsHappy = FALSE;\n" % (self.arg.name, self.GetIndirectedArgName(None, 2))
def GetInterfaceArgCleanup(self):
return "\tPyWinObject_FreeTCHAR(%s);\n" % self.GetIndirectedArgName(None, 1)
def GetBuildForInterfacePreCode(self):
# the variable was declared with just its builtin indirection
notdirected = self.GetIndirectedArgName(self.builtinIndirection, 1)
return "\tob%s = PyWinObject_FromTCHAR(%s);\n" % \
(self.arg.name, notdirected)
def GetBuildForInterfacePostCode(self):
return "// ??? - TCHAR post code\n"
def GetBuildForGatewayPostCode(self):
return "\tPy_XDECREF(ob%s);\n" % self.arg.name
class ArgFormatterIID(ArgFormatterPythonCOM):
def _GetPythonTypeDesc(self):
return "<o PyIID>"
def GetParsePostCode(self):
return "\tif (!PyWinObject_AsIID(ob%s, &%s)) bPythonIsHappy = FALSE;\n" % (self.arg.name, self.arg.name)
def GetBuildForInterfacePreCode(self):
# notdirected = self.GetIndirectedArgName(self.arg.indirectionLevel, 0)
notdirected = self.GetIndirectedArgName(None, 0)
return "\tob%s = PyWinObject_FromIID(%s);\n" % (self.arg.name, notdirected)
def GetInterfaceCppObjectInfo(self):
return self.arg.name, "IID %s" % (self.arg.name)
class ArgFormatterTime(ArgFormatterPythonCOM):
def __init__(self, arg, builtinIndirection, declaredIndirection = 0):
# we don't want to declare LPSYSTEMTIME / LPFILETIME objects
if arg.indirectionLevel == 0 and arg.unc_type[:2] == "LP":
arg.unc_type = arg.unc_type[2:]
# reduce the builtin and increment the declaration
arg.indirectionLevel = arg.indirectionLevel + 1
builtinIndirection = 0
ArgFormatterPythonCOM.__init__(self, arg, builtinIndirection, declaredIndirection)
def _GetPythonTypeDesc(self):
return "<o PyTime>"
def GetParsePostCode(self):
# variable was declared with only the builtinIndirection
### NOTE: this is an [in] ... so use only builtin
return '\tif (!PyTime_Check(ob%s)) {\n\t\tPyErr_SetString(PyExc_TypeError, "The argument must be a PyTime object");\n\t\tbPythonIsHappy = FALSE;\n\t}\n\tif (!((PyTime *)ob%s)->GetTime(%s)) bPythonIsHappy = FALSE;\n' % (self.arg.name, self.arg.name, self.GetIndirectedArgName(self.builtinIndirection, 1))
def GetBuildForInterfacePreCode(self):
### use just the builtinIndirection again...
notdirected = self.GetIndirectedArgName(self.builtinIndirection,0)
return "\tob%s = new PyTime(%s);\n" % (self.arg.name, notdirected)
def GetBuildForInterfacePostCode(self):
### hack to determine if we need to free stuff
ret = ''
if self.builtinIndirection + self.arg.indirectionLevel > 1:
# memory returned into an OLECHAR should be freed
ret = "\tCoTaskMemFree(%s);\n" % self.arg.name
return ret + ArgFormatterPythonCOM.GetBuildForInterfacePostCode(self)
class ArgFormatterSTATSTG(ArgFormatterPythonCOM):
def _GetPythonTypeDesc(self):
return "<o STATSTG>"
def GetParsePostCode(self):
return '\tif (!PyCom_PyObjectAsSTATSTG(ob%s, %s, 0/*flags*/)) bPythonIsHappy = FALSE;\n' % (self.arg.name, self.GetIndirectedArgName(None, 1))
def GetBuildForInterfacePreCode(self):
notdirected = self.GetIndirectedArgName(None, 1)
return "\tob%s = PyCom_PyObjectFromSTATSTG(%s);\n\t// STATSTG doco says our responsibility to free\n\tif ((%s).pwcsName) CoTaskMemFree((%s).pwcsName);\n" % (self.arg.name, self.GetIndirectedArgName(None, 1),notdirected,notdirected)
class ArgFormatterGeneric(ArgFormatterPythonCOM):
def _GetPythonTypeDesc(self):
return "<o %s>" % self.arg.type
def GetParsePostCode(self):
return '\tif (!PyObject_As%s(ob%s, &%s) bPythonIsHappy = FALSE;\n' % (self.arg.type, self.arg.name, self.GetIndirectedArgName(None, 1))
def GetInterfaceArgCleanup(self):
return '\tPyObject_Free%s(%s);\n' % (self.arg.type, self.arg.name)
def GetBuildForInterfacePreCode(self):
notdirected = self.GetIndirectedArgName(None, 1)
return "\tob%s = PyObject_From%s(%s);\n" % (self.arg.name, self.arg.type, self.GetIndirectedArgName(None, 1))
class ArgFormatterIDLIST(ArgFormatterPythonCOM):
def _GetPythonTypeDesc(self):
return "<o PyIDL>"
def GetParsePostCode(self):
return '\tif (bPythonIsHappy && !PyObject_AsPIDL(ob%s, &%s)) bPythonIsHappy = FALSE;\n' % (self.arg.name, self.GetIndirectedArgName(None, 1))
def GetInterfaceArgCleanup(self):
return '\tPyObject_FreePIDL(%s);\n' % (self.arg.name,)
def GetBuildForInterfacePreCode(self):
notdirected = self.GetIndirectedArgName(None, 1)
return "\tob%s = PyObject_FromPIDL(%s);\n" % (self.arg.name, self.GetIndirectedArgName(None, 1))
class ArgFormatterHANDLE(ArgFormatterPythonCOM):
def _GetPythonTypeDesc(self):
return "<o PyHANDLE>"
def GetParsePostCode(self):
return '\tif (!PyWinObject_AsHANDLE(ob%s, &%s, FALSE) bPythonIsHappy = FALSE;\n' % (self.arg.name, self.GetIndirectedArgName(None, 1))
def GetBuildForInterfacePreCode(self):
notdirected = self.GetIndirectedArgName(None, 1)
return "\tob%s = PyWinObject_FromHANDLE(%s);\n" % (self.arg.name, self.GetIndirectedArgName(None, 0))
class ArgFormatterLARGE_INTEGER(ArgFormatterPythonCOM):
def GetKeyName(self):
return "LARGE_INTEGER"
def _GetPythonTypeDesc(self):
return "<o %s>" % self.GetKeyName()
def GetParsePostCode(self):
return '\tif (!PyWinObject_As%s(ob%s, %s)) bPythonIsHappy = FALSE;\n' % (self.GetKeyName(), self.arg.name, self.GetIndirectedArgName(None, 1))
def GetBuildForInterfacePreCode(self):
notdirected = self.GetIndirectedArgName(None, 0)
return "\tob%s = PyWinObject_From%s(%s);\n" % (self.arg.name, self.GetKeyName(), notdirected)
class ArgFormatterULARGE_INTEGER(ArgFormatterLARGE_INTEGER):
def GetKeyName(self):
return "ULARGE_INTEGER"
class ArgFormatterInterface(ArgFormatterPythonCOM):
def GetInterfaceCppObjectInfo(self):
return self.GetIndirectedArgName(1, self.arg.indirectionLevel), \
"%s * %s" % (self.GetUnconstType(), self.arg.name)
def GetParsePostCode(self):
# This gets called for out params in gateway mode
if self.gatewayMode:
sArg = self.GetIndirectedArgName(None, 2)
else:
# vs. in params for interface mode.
sArg = self.GetIndirectedArgName(1, 2)
return "\tif (bPythonIsHappy && !PyCom_InterfaceFromPyInstanceOrObject(ob%s, IID_%s, (void **)%s, TRUE /* bNoneOK */))\n\t\t bPythonIsHappy = FALSE;\n" % (self.arg.name, self.arg.type, sArg)
def GetBuildForInterfacePreCode(self):
return "\tob%s = PyCom_PyObjectFromIUnknown(%s, IID_%s, FALSE);\n" % (self.arg.name, self.arg.name, self.arg.type)
def GetBuildForGatewayPreCode(self):
sPrefix = self._IndirectPrefix(self._GetDeclaredIndirection(), 1)
return "\tob%s = PyCom_PyObjectFromIUnknown(%s%s, IID_%s, TRUE);\n" % (self.arg.name, sPrefix, self.arg.name, self.arg.type)
def GetInterfaceArgCleanup(self):
return "\tif (%s) %s->Release();\n" % (self.arg.name, self.arg.name)
class ArgFormatterVARIANT(ArgFormatterPythonCOM):
def GetParsePostCode(self):
return "\tif ( !PyCom_VariantFromPyObject(ob%s, %s) )\n\t\tbPythonIsHappy = FALSE;\n" % (self.arg.name, self.GetIndirectedArgName(None, 1))
def GetBuildForGatewayPreCode(self):
notdirected = self.GetIndirectedArgName(None, 1)
return "\tob%s = PyCom_PyObjectFromVariant(%s);\n" % (self.arg.name, notdirected)
def GetBuildForGatewayPostCode(self):
return "\tPy_XDECREF(ob%s);\n" % self.arg.name
# Key : , Python Type Description, ParseTuple format char
ConvertSimpleTypes = {"BOOL":("BOOL", "int", "i"),
"UINT":("UINT", "int", "i"),
"BYTE": ("BYTE", "int", "i"),
"INT": ("INT", "int", "i"),
"DWORD": ("DWORD", "int", "l"),
"HRESULT":("HRESULT", "int", "l"),
"ULONG": ("ULONG", "int", "l"),
"LONG": ("LONG", "int", "l"),
"int": ("int", "int", "i"),
"long": ("long", "int", "l"),
"DISPID": ("DISPID", "long", "l"),
"APPBREAKFLAGS": ("int", "int", "i"),
"BREAKRESUMEACTION": ("int", "int", "i"),
"ERRORRESUMEACTION": ("int", "int", "i"),
"BREAKREASON": ("int", "int", "i"),
"BREAKPOINT_STATE": ("int", "int", "i"),
"BREAKRESUME_ACTION": ("int", "int", "i"),
"SOURCE_TEXT_ATTR": ("int", "int", "i"),
"TEXT_DOC_ATTR": ("int", "int", "i"),
"QUERYOPTION": ("int", "int", "i"),
"PARSEACTION": ("int", "int", "i"),
}
class ArgFormatterSimple(ArgFormatter):
"""An arg formatter for simple integer etc types"""
def GetFormatChar(self):
return ConvertSimpleTypes[self.arg.type][2]
def _GetPythonTypeDesc(self):
return ConvertSimpleTypes[self.arg.type][1]
AllConverters = {"const OLECHAR": (ArgFormatterOLECHAR, 0, 1),
"WCHAR": (ArgFormatterOLECHAR, 0, 1),
"OLECHAR": (ArgFormatterOLECHAR, 0, 1),
"LPCOLESTR": (ArgFormatterOLECHAR, 1, 1),
"LPOLESTR": (ArgFormatterOLECHAR, 1, 1),
"LPCWSTR": (ArgFormatterOLECHAR, 1, 1),
"LPWSTR": (ArgFormatterOLECHAR, 1, 1),
"LPCSTR": (ArgFormatterOLECHAR, 1, 1),
"LPTSTR": (ArgFormatterTCHAR, 1, 1),
"LPCTSTR": (ArgFormatterTCHAR, 1, 1),
"HANDLE": (ArgFormatterHANDLE, 0),
"BSTR": (ArgFormatterBSTR, 1, 0),
"const IID": (ArgFormatterIID, 0),
"CLSID": (ArgFormatterIID, 0),
"IID": (ArgFormatterIID, 0),
"GUID": (ArgFormatterIID, 0),
"const GUID": (ArgFormatterIID, 0),
"const IID": (ArgFormatterIID, 0),
"REFCLSID": (ArgFormatterIID, 0),
"REFIID": (ArgFormatterIID, 0),
"REFGUID": (ArgFormatterIID, 0),
"const FILETIME": (ArgFormatterTime, 0),
"const SYSTEMTIME":(ArgFormatterTime, 0),
"const LPSYSTEMTIME":(ArgFormatterTime, 1, 1),
"LPSYSTEMTIME": (ArgFormatterTime, 1, 1),
"FILETIME": (ArgFormatterTime, 0),
"SYSTEMTIME": (ArgFormatterTime, 0),
"STATSTG": (ArgFormatterSTATSTG, 0),
"LARGE_INTEGER": (ArgFormatterLARGE_INTEGER, 0),
"ULARGE_INTEGER": (ArgFormatterULARGE_INTEGER, 0),
"VARIANT": (ArgFormatterVARIANT, 0),
"float": (ArgFormatterFloat, 0),
"single": (ArgFormatterFloat, 0),
"short": (ArgFormatterShort, 0),
"WORD": (ArgFormatterShort, 0),
"VARIANT_BOOL": (ArgFormatterShort, 0),
"HWND": (ArgFormatterLONG_PTR, 1),
"HMENU": (ArgFormatterLONG_PTR, 1),
"HOLEMENU": (ArgFormatterLONG_PTR, 1),
"HICON": (ArgFormatterLONG_PTR, 1),
"HDC": (ArgFormatterLONG_PTR, 1),
"LPARAM": (ArgFormatterLONG_PTR, 1),
"WPARAM": (ArgFormatterLONG_PTR, 1),
"LRESULT": (ArgFormatterLONG_PTR, 1),
"UINT": (ArgFormatterShort, 0),
"SVSIF": (ArgFormatterShort, 0),
"Control": (ArgFormatterInterface, 0, 1),
"DataObject": (ArgFormatterInterface, 0, 1),
"_PropertyBag": (ArgFormatterInterface, 0, 1),
"AsyncProp": (ArgFormatterInterface, 0, 1),
"DataSource": (ArgFormatterInterface, 0, 1),
"DataFormat": (ArgFormatterInterface, 0, 1),
"void **": (ArgFormatterInterface, 2, 2),
"ITEMIDLIST": (ArgFormatterIDLIST, 0, 0),
"LPITEMIDLIST": (ArgFormatterIDLIST, 0, 1),
"LPCITEMIDLIST": (ArgFormatterIDLIST, 0, 1),
"const ITEMIDLIST": (ArgFormatterIDLIST, 0, 1),
}
# Auto-add all the simple types
for key in ConvertSimpleTypes.iterkeys():
AllConverters[key] = ArgFormatterSimple, 0
def make_arg_converter(arg):
try:
clz = AllConverters[arg.type][0]
bin = AllConverters[arg.type][1]
decl = 0
if len(AllConverters[arg.type])>2:
decl = AllConverters[arg.type][2]
return clz(arg,bin, decl)
except KeyError:
if arg.type[0]=="I":
return ArgFormatterInterface(arg, 0, 1)
raise error_not_supported("The type '%s' (%s) is unknown." % (arg.type, arg.name))
#############################################################
#
# The instances that represent the args, methods and interface
class Argument:
"""A representation of an argument to a COM method
This class contains information about a specific argument to a method.
In addition, methods exist so that an argument knows how to convert itself
to/from Python arguments.
"""
# in,out type name [ ]
# -------------- -------- ------------ ------
regex = re.compile(r'/\* \[([^\]]*.*?)] \*/[ \t](.*[* ]+)(\w+)(\[ *])?[\),]')
def __init__(self, good_interface_names):
self.good_interface_names = good_interface_names
self.inout = self.name = self.type = None
self.const = 0
self.arrayDecl = 0
def BuildFromFile(self, file):
"""Parse and build my data from a file
Reads the next line in the file, and matches it as an argument
description. If not a valid argument line, an error_not_found exception
is raised.
"""
line = file.readline()
mo = self.regex.search(line)
if not mo:
raise error_not_found
self.name = mo.group(3)
self.inout = mo.group(1).split('][')
typ = mo.group(2).strip()
self.raw_type = typ
self.indirectionLevel = 0
if mo.group(4): # Has "[ ]" decl
self.arrayDecl = 1
try:
pos = typ.rindex("__RPC_FAR")
self.indirectionLevel = self.indirectionLevel + 1
typ = typ[:pos].strip()
except ValueError:
pass
typ = typ.replace("__RPC_FAR", "")
while 1:
try:
pos = typ.rindex("*")
self.indirectionLevel = self.indirectionLevel + 1
typ = typ[:pos].strip()
except ValueError:
break
self.type = typ
if self.type[:6]=="const ":
self.unc_type = self.type[6:]
else:
self.unc_type = self.type
if VERBOSE:
print " Arg %s of type %s%s (%s)" % (self.name, self.type, "*" * self.indirectionLevel, self.inout)
def HasAttribute(self, typ):
"""Determines if the argument has the specific attribute.
Argument attributes are specified in the header file, such as
"[in][out][retval]" etc. You can pass a specific string (eg "out")
to find if this attribute was specified for the argument
"""
return typ in self.inout
def GetRawDeclaration(self):
ret = "%s %s" % (self.raw_type, self.name)
if self.arrayDecl:
ret = ret + "[]"
return ret
class Method:
"""A representation of a C++ method on a COM interface
This class contains information about a specific method, as well as
a list of all @Argument@s
"""
# options ret type callconv name
# ----------------- -------- -------- --------
regex = re.compile(r'virtual (/\*.*?\*/ )?(.*?) (.*?) (.*?)\(\w?')
def __init__(self, good_interface_names):
self.good_interface_names = good_interface_names
self.name = self.result = self.callconv = None
self.args = []
def BuildFromFile(self, file):
"""Parse and build my data from a file
Reads the next line in the file, and matches it as a method
description. If not a valid method line, an error_not_found exception
is raised.
"""
line = file.readline()
mo = self.regex.search(line)
if not mo:
raise error_not_found
self.name = mo.group(4)
self.result = mo.group(2)
if self.result != "HRESULT":
if self.result=="DWORD": # DWORD is for old old stuff?
print "Warning: Old style interface detected - compilation errors likely!"
else:
print "Method %s - Only HRESULT return types are supported." % self.name
# raise error_not_supported, if VERBOSE:
print " Method %s %s(" % (self.result, self.name)
while 1:
arg = Argument(self.good_interface_names)
try:
arg.BuildFromFile(file)
self.args.append(arg)
except error_not_found:
break
class Interface:
"""A representation of a C++ COM Interface
This class contains information about a specific interface, as well as
a list of all @Method@s
"""
# name base
# -------- --------
regex = re.compile("(interface|) ([^ ]*) : public (.*)$")
def __init__(self, mo):
self.methods = []
self.name = mo.group(2)
self.base = mo.group(3)
if VERBOSE:
print "Interface %s : public %s" % (self.name, self.base)
def BuildMethods(self, file):
"""Build all sub-methods for this interface"""
# skip the next 2 lines.
file.readline();file.readline();
while 1:
try:
method = Method([self.name])
method.BuildFromFile(file)
self.methods.append(method)
except error_not_found:
break
def find_interface(interfaceName, file):
"""Find and return an interface in a file
Given an interface name and file, search for the specified interface.
Upon return, the interface itself has been built,
but not the methods.
"""
interface = None
line = file.readline()
while line:
mo = Interface.regex.search(line)
if mo:
name = mo.group(2)
print name
AllConverters[name] = (ArgFormatterInterface, 0, 1)
if name==interfaceName:
interface = Interface(mo)
interface.BuildMethods(file)
line = file.readline()
if interface:
return interface
raise error_not_found
def parse_interface_info(interfaceName, file):
"""Find, parse and return an interface in a file
Given an interface name and file, search for the specified interface.
Upon return, the interface itself is fully built,
"""
try:
return find_interface(interfaceName, file)
except re.error:
traceback.print_exc()
print "The interface could not be built, as the regular expression failed!"
def test():
f=open("d:\\msdev\\include\\objidl.h")
try:
parse_interface_info("IPersistStream", f)
finally:
f.close()
def test_regex(r,text):
res=r.search(text,0)
if res==-1:
print "** Not found"
else:
print "%d\n%s\n%s\n%s\n%s" % (res, r.group(1), r.group(2), r.group(3), r.group(4))