diff --git a/README b/README index 03cb7184..080d6bcd 100644 --- a/README +++ b/README @@ -9,7 +9,8 @@ http://www.gnupg.org/cvs-access.html . If you use passphrases for your keys, you should get the gpg-agent which comes with the GnuPG unstable version (either CVS HEAD or ftp.gnupg.org/pub/gcrypt/alpha/gnupg/gnupg-1.1.2.tar.gz) and install -the agent from the agent subdirectory. +the agent from the agent subdirectory or use the new +gpgme_set_passphrase_cb() Please subscribe to the gnupg-devel@gnupg.org mailing list if you want to do serious work. diff --git a/complus/Makefile.am b/complus/Makefile.am index 8976cd80..bbae8d59 100644 --- a/complus/Makefile.am +++ b/complus/Makefile.am @@ -1,12 +1,17 @@ ## Process this file with automake to produce Makefile.in +EXTRA_DIST = WINE-LICENSE WINE-AUTHORS + # No need to install this becuase we are cross-compiling anyway. -noinst_PROGRAMS = gpgme +noinst_PROGRAMS = gpgcom INCLUDES = -I$(top_srcdir)/jnlib LDADD = -L ../jnlib -ljnlib -gpgme_SOURCES = main.c main.h - +comheaders = obj_base.h basetsd.h guiddef.h wtypes.h + +gpgcom_SOURCES = main.c main.h \ + $(comheaders) \ + ignupg.c ignupg.h diff --git a/complus/WINE-AUTHORS b/complus/WINE-AUTHORS new file mode 100644 index 00000000..be51ca56 --- /dev/null +++ b/complus/WINE-AUTHORS @@ -0,0 +1,331 @@ +@c This file is processed by GNU's TeXinfo +@c If you modify it or move it to another location, make sure that +@c TeXinfo works (type `make' in directory documentation). + +@c This is a list of the Wine authors and copyright holders. + +Wine is available thanks to the work of: +James Abbatiello, +Michael Abd-El-Malek, +Howard Abrams, +Mark G. Adams, +Bruno Afonso, +Samir Al-Battran, +Guy Albertelli, +Gustavo Junior Alves, +Bob Amstadt, +Dag Asheim, +Jim Aston, +Martin Ayotte, +Viktor Babrian, +Karl Backström, +Bradley Baetz, +Peter Bajusz, +Andre Malafaya Baptista, +Aaron Barnes, +Jean-Claude Batista, +Marcel Baur, +Francis Beaudet, +Tom Bech, +Matthew Becker, +Georg Beyerle, +Ross Biro, +Dennis Björklund, +Zygo Blaxell, +Martin Boehme, +Francois Boisvert, +Pim Bollen, +Uwe Bonnes, +Peter Bortas, +Noel Borthwick, +Erik Bos, +Fons Botman, +Sylvain Bouchard, +Frederic Boulanger, +Justin Bradford, +John Brezak, +Andrew Bulhak, +John Burton, +Jonathan Buzzard, +Jose Marcos López Caravaca, +Eddie Carpenter, +Niels de Carpentier, +Mike Castle, +Ron Cemer, +Gordon Chaffee, +Gael de Chalendar, +Jimen Ching, +Geoff Clare, +Robert 'Admiral' Coeyman, +Richard Cohen, +Jean-Claude Cote, +Stephen Crowley, +Pascal Cuoq, +David A. Cuthbert, +Brian Joseph Czapiga, +Ulrich Czekalla, +Huw D. M. Davies, +Moses DeJong, +Petar Djukic, +Roman Dolejsi, +Frans van Dorsselaer, +Rikhardur Egilsson, +Morten Eriksen, +Chris Faherty, +Carsten Fallesen, +Paul Falstad, +David Faure, +Wesley Filardo, +Claus Fischer, +Olaf Flebbe, +Chad Fraleigh, +Matthew Francis, +Philippe Froidevaux, +Peter Galbavy, +Peter Ganten, +Ramon Garcia, +Jeff Garzik, +Julio Cesar Gazquez, +Klaas van Gend, +Abey George, +Brian Gerst, +Matthew Ghio, +Jody Goldberg, +David Golding, +François Gouget, +Hans de Graaff, +David Grant, +Albert den Haan, +Jess Haas, +Robert W Hall, +Noomen Hamza, +Charles M. Hannum, +Adrian Harvey, +John Harvey, +James Hatheway, +Kalevi J Hautaniemi, +Bill Hawes, +Lars Heete, +Cameron Heide, +Bernd Herd, +Theodore S. Hetke, +Haithem Hmida, +Jochen Hoenicke, +Henning Hoffmann, +Kevin Holbrook, +Nick Holloway, +Onno Hovers, +Jeffrey Hsu, +Peter Hunnisett, +Miguel de Icaza, +Jukka Iivonen, +Kostya Ivanov, +Serge Ivanov, +Lee Jaekil, +Gautam Jain, +Niels Kristian Bech Jensen, +Rajeev Jhangiani, +Bill Jin, +Jeff Johann, +Alexandre Julliard, +Bang Jun-Young, +James Juran, +Achim Kaiser, +Alexander Kanavin, +Jukka Kangas, +Pavel Kankovsky, +Michael Karcher, +Niclas Karlsson, +Jochen Karrer, +Don Kelly, +Andreas Kirschbaum, +Rein Klazes, +Albrecht Kleine, +Dietmar Kling, +Eric Kohl, +Jon Konrath, +Alex Korobka, +Zoltan Kovacs, +Greg Kreider, +Anand Kumria, +Ove Kåven, +Scott A. Laird, +David Lee Lambert, +Stephen Langasek, +Sean Langley, +Dan Langlois, +Alexander Larsson, +David Lassonde, +Stefan Leichter, +Karl Lessard, +Pascal Lessard, +Andrew Lewycky, +John Li, +Weisheng Li, +Xiang Li, +Per Lindström, +Brian Litzinger, +Juergen Lock, +Martin von Loewis, +Michiel van Loon, +Richard A Lough, +Alexander V. Lukyanov, +Jiuming Luo, +Stephane Lussier, +David Luyer, +José Marcos López, +Kenneth MacDonald, +Peter MacDonald, +Pierre Mageau, +William Magro, +Juergen Marquardt, +Ricardo Massaro, +Keith Matthews, +Joerg Mayer, +Michael McCormack, +Jason McMullan, +Caolan McNamara, +Marcus Meissner, +Graham Menhennitt, +David Metcalfe, +Toufic Milan, +Paul Millar, +Bruce Milner, +Steffen Moeller, +Andreas Mohr, +Slava Monich, +James Moody, +Chris Morgan, +Kai Morich, +Richard Mortimer, +Vasudev Mulchandani, +Rick Mutzke, +Philippe De Muyter, +Itai Nahshon, +Jonathan Naylor, +Tim Newsome, +Thuy Nguyen, +Kristian Nielsen, +Damien O'Neill, +Henrik Olsen, +Gerard Patel, +Michael Patra, +Murali Pattathe, +Dimitrie O. Paun, +Bernd Paysan, +Brad Pepers, +Jim Peterson, +Gerald Pfeifer, +Dave Pickles, +Ian Pilcher, +Brian Pirie, +Michael Poole, +Eric Pouech, +Robert Pouliot, +Vahid Pourlotfali, +Chad Powell, +Joseph Pranevich, +Alex Priem, +Paul Quinn, +Pete Ratzlaff, +Ron Record, +Petter Reinholdtsen, +Keith Reynolds, +Slaven Rezic, +John Richardson, +Rick Richardson, +Douglas Ridgway, +Robert Riggs, +Bernhard Rosenkraenzer, +Matthew Robertson, +Pavel Roskin, +Herbert Rosmanith, +Lilia Roumiantseva, +Johannes Ruscheinski, +Adam Sacarny, +Ivan de Saedeleer, +Thomas Sandford, +Constantine Sapuntzakis, +Pablo Saratxaga, +Carl van Schaik, +Daniel Schepler, +Christian Schlaile, +Peter Schlaile, +Ulrich Schmid, +Bernd Schmidt, +Ian Schmidt, +Juergen Schmied, +Ingo Schneider, +Victor Schneider, +John Sheets, +Yngvi Sigurjonsson, +Stephen Simmons, +Jesper Skov, +Rick Sladkey, +William Smith, +Jaroslaw Piotr Sobieszek, +Patrick Spinler, +Sylvain St-Germain, +Gavriel State, +Sheri Steeves, +Norman Stevens, +Dominik Strasser, +Patrik Stridvall, +Vadim Strizhevsky, +Bertho Stultiens, +Abraham Sudhakar, +Charles Suprin, +James Sutherland, +Erik Svendsen, +Tristan Tarrant, +Andrew Taylor, +Joshua Thielen, +Dirk Thierbach, +Jean-Louis Thirot, +Duncan C Thomson, +Adrian Thurston, +Goran Thyni, +Steve Tibbett, +Dmitry Timoshkov, +Jimmy Tirtawangsa, +Jon Tombs, +Linus Torvalds, +Luc Tourangeau, +Jeff Tranter, +Gregory Trubetskoy, +Petri Tuomola, +Sergey Turchanov, +Lionel Ulmer, +Moshe Vainer, +Michael Veksler, +Sven Verdoolaege, +Todd Vierling, +Erez Volk, +Jerome Vouillon, +Duc Vuong, +Ronan Waide, +Martin Walker, +Owen Wang, +Eric Warnke, +Leigh Wedding, +Randy Weems, +Manfred Weichel, +Ulrich Weigand, +Morten Welinder, +Jeremy White, +Len White, +Lawson Whitney, +Jan Willamowius, +Carl Williams, +Eric Williams, +Cliff Wright, +Karl Guenter Wuensch, +Eric Youngdale, +James Youngman, +Nikita V. Youshchenko, +Mikolaj Zalewski, +John Zero, +Yuxi Zhang, +Nathan Zorich, +Luiz Otavio L. Zorzella, +and Per Ångström. diff --git a/complus/WINE-LICENSE b/complus/WINE-LICENSE new file mode 100644 index 00000000..f3478fe1 --- /dev/null +++ b/complus/WINE-LICENSE @@ -0,0 +1,26 @@ +This is the license file as it appeared in the CVS version of +Wine at cvs@rhlx01.fht-esslingen.de:/home/wine as of 2000-12-04 +where only AUTHORS has been renamed to WINE-AUTHORS. It applies +to the header files establishing the COM+ framework + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +Copyright (c) 1993-2000 the Wine project authors (see the file WINE-AUTHORS +for a complete list) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/complus/basetsd.h b/complus/basetsd.h new file mode 100644 index 00000000..866c9b8e --- /dev/null +++ b/complus/basetsd.h @@ -0,0 +1,160 @@ +/* basetsd.h - Compilers that uses ILP32, LP64 or P64 type models + for both Win32 and Win64 are supported by this file. + + Copyright (c) 1993-2000 the Wine project authors (see the file WINE-AUTHORS + for a complete list) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __WINE_BASETSD_H +#define __WINE_BASETSD_H + +#ifdef __cplusplus +extern "C" { +#endif /* defined(__cplusplus) */ + +/* + * Win32 was easy to implement under Unix since most (all?) 32-bit + * Unices uses the same type model (ILP32) as Win32, where int, long + * and pointer are 32-bit. + * + * Win64, however, will cause some problems when implemented under Unix. + * Linux/{Alpha, Sparc64} and most (all?) other 64-bit Unices uses + * the LP64 type model where int is 32-bit and long and pointer are + * 64-bit. Win64 on the other hand uses the P64 (sometimes called LLP64) + * type model where int and long are 32 bit and pointer is 64-bit. + */ + +/* Type model indepent typedefs */ + +typedef char __int8; +typedef unsigned char __uint8; + +typedef short __int16; +typedef unsigned short __uint16; + +typedef int __int32; +typedef unsigned int __uint32; + +typedef long long __int64; +typedef unsigned long long __uint64; + +#if defined(_WIN64) + +typedef __uint32 __ptr32; +typedef void *__ptr64; + +#else /* FIXME: defined(_WIN32) */ + +typedef void *__ptr32; +typedef __uint64 __ptr64; + +#endif + +/* Always signed and 32 bit wide */ + +typedef __int32 LONG32; +typedef __int32 INT32; + +typedef LONG32 *PLONG32; +typedef INT32 *PINT32; + +/* Always unsigned and 32 bit wide */ + +typedef __uint32 ULONG32; +typedef __uint32 DWORD32; +typedef __uint32 UINT32; + +typedef ULONG32 *PULONG32; +typedef DWORD32 *PDWORD32; +typedef UINT32 *PUINT32; + +/* Always signed and 64 bit wide */ + +typedef __int64 LONG64; +typedef __int64 INT64; + +typedef LONG64 *PLONG64; +typedef INT64 *PINT64; + +/* Always unsigned and 64 bit wide */ + +typedef __uint64 ULONG64; +typedef __uint64 DWORD64; +typedef __uint64 UINT64; + +typedef ULONG64 *PULONG64; +typedef DWORD64 *PDWORD64; +typedef UINT64 *PUINT64; + +/* Win32 or Win64 dependent typedef/defines. */ + +#ifdef _WIN64 + +typedef __int64 INT_PTR, *PINT_PTR; +typedef __uint64 UINT_PTR, *PUINT_PTR; + +#define MAXINT_PTR 0x7fffffffffffffff +#define MININT_PTR 0x8000000000000000 +#define MAXUINT_PTR 0xffffffffffffffff + +typedef __int32 HALF_PTR, *PHALF_PTR; +typedef __int32 UHALF_PTR, *PUHALF_PTR; + +#define MAXHALF_PTR 0x7fffffff +#define MINHALF_PTR 0x80000000 +#define MAXUHALF_PTR 0xffffffff + +typedef __int64 LONG_PTR, *PLONG_PTR; +typedef __uint64 ULONG_PTR, *PULONG_PTR; +typedef __uint64 DWORD_PTR, *PDWORD_PTR; + +#else /* FIXME: defined(_WIN32) */ + +typedef __int32 INT_PTR, *PINT_PTR; +typedef __uint32 UINT_PTR, *PUINT_PTR; + +#define MAXINT_PTR 0x7fffffff +#define MININT_PTR 0x80000000 +#define MAXUINT_PTR 0xffffffff + +typedef __int16 HALF_PTR, *PHALF_PTR; +typedef __uint16 UHALF_PTR, *PUHALF_PTR; + +#define MAXUHALF_PTR 0xffff +#define MAXHALF_PTR 0x7fff +#define MINHALF_PTR 0x8000 + +typedef __int32 LONG_PTR, *PLONG_PTR; +typedef __uint32 ULONG_PTR, *PULONG_PTR; +typedef __uint32 DWORD_PTR, *PDWORD_PTR; + +#endif /* defined(_WIN64) || defined(_WIN32) */ + +typedef INT_PTR SSIZE_T, *PSSIZE_T; +typedef UINT_PTR SIZE_T, *PSIZE_T; + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* defined(__cplusplus) */ + +#endif /* !defined(__WINE_BASETSD_H) */ + + + diff --git a/complus/example.c b/complus/example.c new file mode 100644 index 00000000..a7d838d5 --- /dev/null +++ b/complus/example.c @@ -0,0 +1,598 @@ +/* + * Copyright 1999 Marcus Meissner + */ +#include +#include +#include + +#include "winbase.h" +#include "winnls.h" +#include "mmsystem.h" +#include "winerror.h" +#include "debugtools.h" + +#include "initguid.h" +#include "vfw.h" + +DEFAULT_DEBUG_CHANNEL(avifile); + +static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile* iface,REFIID refiid,LPVOID *obj); +static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile* iface); +static ULONG WINAPI IAVIFile_fnRelease(IAVIFile* iface); +static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile*iface,AVIFILEINFOW*afi,LONG size); +static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile*iface,PAVISTREAM*avis,DWORD fccType,LONG lParam); +static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile*iface,PAVISTREAM*avis,AVISTREAMINFOW*asi); +static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG size); +static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG *size); +static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile*iface); +static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile*iface,DWORD fccType,LONG lParam); + +struct ICOM_VTABLE(IAVIFile) iavift = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + IAVIFile_fnQueryInterface, + IAVIFile_fnAddRef, + IAVIFile_fnRelease, + IAVIFile_fnInfo, + IAVIFile_fnGetStream, + IAVIFile_fnCreateStream, + IAVIFile_fnWriteData, + IAVIFile_fnReadData, + IAVIFile_fnEndRecord, + IAVIFile_fnDeleteStream +}; + +static HRESULT WINAPI IAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID *obj); +static ULONG WINAPI IAVIStream_fnAddRef(IAVIStream*iface); +static ULONG WINAPI IAVIStream_fnRelease(IAVIStream* iface); +static HRESULT WINAPI IAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2); +static HRESULT WINAPI IAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size); +static LONG WINAPI IAVIStream_fnFindSample(IAVIStream*iface,LONG pos,LONG flags); +static HRESULT WINAPI IAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG *formatsize); +static HRESULT WINAPI IAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize); +static HRESULT WINAPI IAVIStream_fnRead(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,LONG *bytesread,LONG *samplesread); +static HRESULT WINAPI IAVIStream_fnWrite(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,DWORD flags,LONG *sampwritten,LONG *byteswritten); +static HRESULT WINAPI IAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples); +static HRESULT WINAPI IAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG *lpread); +static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG size); +static HRESULT WINAPI IAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen); + +struct ICOM_VTABLE(IAVIStream) iavist = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + IAVIStream_fnQueryInterface, + IAVIStream_fnAddRef, + IAVIStream_fnRelease, + IAVIStream_fnCreate, + IAVIStream_fnInfo, + IAVIStream_fnFindSample, + IAVIStream_fnReadFormat, + IAVIStream_fnSetFormat, + IAVIStream_fnRead, + IAVIStream_fnWrite, + IAVIStream_fnDelete, + IAVIStream_fnReadData, + IAVIStream_fnWriteData, + IAVIStream_fnSetInfo +}; + +typedef struct IAVIStreamImpl { + /* IUnknown stuff */ + ICOM_VFIELD(IAVIStream); + DWORD ref; + /* IAVIStream stuff */ + LPVOID lpInputFormat; + DWORD inputformatsize; + BOOL iscompressing; + DWORD curframe; + + /* Compressor stuff */ + HIC hic; + LPVOID lpCompressFormat; + ICINFO icinfo; + DWORD compbufsize; + LPVOID compbuffer; + + DWORD decompbufsize; + LPVOID decompbuffer; + LPVOID decompformat; + AVICOMPRESSOPTIONS aco; + + LPVOID lpPrev; /* pointer to decompressed frame later */ + LPVOID lpPrevFormat; /* pointer to decompressed info later */ +} IAVIStreamImpl; + +/*********************************************************************** + * AVIFileInit + */ +void WINAPI +AVIFileInit(void) { + FIXME("(),stub!\n"); +} + +typedef struct IAVIFileImpl { + /* IUnknown stuff */ + ICOM_VFIELD(IAVIFile); + DWORD ref; + /* IAVIFile stuff... */ +} IAVIFileImpl; + +static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile* iface,REFIID refiid,LPVOID *obj) { + ICOM_THIS(IAVIFileImpl,iface); + + TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(refiid),obj); + if ( !memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown)) || + !memcmp(&IID_IAVIFile,refiid,sizeof(IID_IAVIFile)) + ) { + *obj = iface; + return S_OK; + } + return OLE_E_ENUM_NOMORE; +} + +static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile* iface) { + ICOM_THIS(IAVIFileImpl,iface); + + FIXME("(%p)->AddRef()\n",iface); + return ++(This->ref); +} + +static ULONG WINAPI IAVIFile_fnRelease(IAVIFile* iface) { + ICOM_THIS(IAVIFileImpl,iface); + + FIXME("(%p)->Release()\n",iface); + if (!--(This->ref)) { + HeapFree(GetProcessHeap(),0,iface); + return 0; + } + return This->ref; +} + +static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile*iface,AVIFILEINFOW*afi,LONG size) { + FIXME("(%p)->Info(%p,%ld)\n",iface,afi,size); + + /* FIXME: fill out struct? */ + return E_FAIL; +} + +static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile*iface,PAVISTREAM*avis,DWORD fccType,LONG lParam) { + FIXME("(%p)->GetStream(%p,0x%08lx,%ld)\n",iface,avis,fccType,lParam); + /* FIXME: create interface etc. */ + return E_FAIL; +} + +static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile*iface,PAVISTREAM*avis,AVISTREAMINFOW*asi) { + ICOM_THIS(IAVIStreamImpl,iface); + char fcc[5]; + IAVIStreamImpl *istream; + + FIXME("(%p,%p,%p)\n",This,avis,asi); + istream = (IAVIStreamImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IAVIStreamImpl)); + istream->ref = 1; + ICOM_VTBL(istream) = &iavist; + fcc[4]='\0'; + memcpy(fcc,(char*)&(asi->fccType),4); + FIXME("\tfccType '%s'\n",fcc); + memcpy(fcc,(char*)&(asi->fccHandler),4); + FIXME("\tfccHandler '%s'\n",fcc); + FIXME("\tdwFlags 0x%08lx\n",asi->dwFlags); + FIXME("\tdwCaps 0x%08lx\n",asi->dwCaps); + FIXME("\tname '%s'\n",debugstr_w(asi->szName)); + + istream->curframe = 0; + *avis = (PAVISTREAM)istream; + return S_OK; +} + +static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG size) { + FIXME("(%p)->WriteData(0x%08lx,%p,%ld)\n",iface,ckid,lpData,size); + /* FIXME: write data to file */ + return E_FAIL; +} + +static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG *size) { + FIXME("(%p)->ReadData(0x%08lx,%p,%p)\n",iface,ckid,lpData,size); + /* FIXME: read at most size bytes from file */ + return E_FAIL; +} + +static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile*iface) { + FIXME("(%p)->EndRecord()\n",iface); + /* FIXME: end record? */ + return E_FAIL; +} + +static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile*iface,DWORD fccType,LONG lParam) { + FIXME("(%p)->DeleteStream(0x%08lx,%ld)\n",iface,fccType,lParam); + /* FIXME: delete stream? */ + return E_FAIL; +} + +/*********************************************************************** + * AVIFileOpenA + */ +HRESULT WINAPI AVIFileOpenA( + PAVIFILE * ppfile,LPCSTR szFile,UINT uMode,LPCLSID lpHandler +) { + IAVIFileImpl *iavi; + + FIXME("(%p,%s,0x%08lx,%s),stub!\n",ppfile,szFile,(DWORD)uMode,debugstr_guid(lpHandler)); + iavi = (IAVIFileImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IAVIFileImpl)); + iavi->ref = 1; + ICOM_VTBL(iavi) = &iavift; + *ppfile = (LPVOID)iavi; + return S_OK; +} + +static HRESULT WINAPI IAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID *obj) { + ICOM_THIS(IAVIStreamImpl,iface); + + TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(refiid),obj); + if ( !memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown)) || + !memcmp(&IID_IAVIStream,refiid,sizeof(IID_IAVIStream)) + ) { + *obj = This; + return S_OK; + } + /* can return IGetFrame interface too */ + return OLE_E_ENUM_NOMORE; +} + +static ULONG WINAPI IAVIStream_fnAddRef(IAVIStream*iface) { + ICOM_THIS(IAVIStreamImpl,iface); + + FIXME("(%p)->AddRef()\n",iface); + return ++(This->ref); +} + +static ULONG WINAPI IAVIStream_fnRelease(IAVIStream* iface) { + ICOM_THIS(IAVIStreamImpl,iface); + + FIXME("(%p)->Release()\n",iface); + if (!--(This->ref)) { + HeapFree(GetProcessHeap(),0,This); + return 0; + } + return This->ref; +} + +static HRESULT WINAPI IAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2) { + FIXME("(%p)->Create(0x%08lx,0x%08lx)\n",iface,lParam1,lParam2); + return E_FAIL; +} + +static HRESULT WINAPI IAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size) { + FIXME("(%p)->Info(%p,%ld)\n",iface,psi,size); + return E_FAIL; +} + +static LONG WINAPI IAVIStream_fnFindSample(IAVIStream*iface,LONG pos,LONG flags) { + FIXME("(%p)->FindSample(%ld,0x%08lx)\n",iface,pos,flags); + return E_FAIL; +} + +static HRESULT WINAPI IAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG *formatsize) { + FIXME("(%p)->ReadFormat(%ld,%p,%p)\n",iface,pos,format,formatsize); + return E_FAIL; +} + +/*********************************************************************** + * IAVIStream::SetFormat + */ +static HRESULT WINAPI IAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize) { + IAVIStreamImpl *as = (IAVIStreamImpl*)iface; + + FIXME("(%p)->SetFormat(%ld,%p,%ld)\n",iface,pos,format,formatsize); + if (as->lpInputFormat) HeapFree(GetProcessHeap(),0,as->lpInputFormat); + as->inputformatsize = formatsize; + as->lpInputFormat = HeapAlloc(GetProcessHeap(),0,formatsize); + memcpy(as->lpInputFormat,format,formatsize); + if (as->iscompressing) { + int xsize; + /* Set up the Compressor part */ + xsize = ICCompressGetFormatSize(as->hic,as->lpInputFormat); + as->lpCompressFormat = HeapAlloc(GetProcessHeap(),0,xsize); + ICCompressGetFormat(as->hic,as->lpInputFormat,as->lpCompressFormat); + ICCompressBegin(as->hic,as->lpInputFormat,as->lpCompressFormat); + as->compbufsize = ICCompressGetSize(as->hic,as->lpInputFormat,as->lpCompressFormat); + as->compbuffer = HeapAlloc(GetProcessHeap(),0,as->compbufsize); + + /* Set up the Decompressor part (for prev frames?) */ + xsize=ICDecompressGetFormatSize(as->hic,as->lpCompressFormat); + as->decompformat = HeapAlloc(GetProcessHeap(),0,xsize); + ICDecompressGetFormat(as->hic,as->lpCompressFormat,as->decompformat); + as->decompbufsize=((LPBITMAPINFOHEADER)as->decompbuffer)->biSizeImage; + as->decompbuffer = HeapReAlloc(GetProcessHeap(),0,as->decompbuffer,as->decompbufsize); + memset(as->decompbuffer,0xff,as->decompbufsize); + assert(HeapValidate(GetProcessHeap(),0,NULL)); + + ICDecompressGetFormat(as->hic,as->lpCompressFormat,as->decompformat); + ICDecompressBegin(as->hic,as->lpCompressFormat,as->decompformat); + as->lpPrev = as->lpPrevFormat = NULL; + } + return S_OK; +} + +static HRESULT WINAPI IAVIStream_fnRead(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,LONG *bytesread,LONG *samplesread) { + FIXME("(%p)->Read(%ld,%ld,%p,%ld,%p,%p)\n",iface,start,samples,buffer,buffersize,bytesread,samplesread); + return E_FAIL; +} + +static HRESULT WINAPI IAVIStream_fnWrite(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,DWORD flags,LONG *sampwritten,LONG *byteswritten) { + IAVIStreamImpl *as = (IAVIStreamImpl*)iface; + DWORD ckid,xflags; + + FIXME("(%p)->Write(%ld,%ld,%p,%ld,0x%08lx,%p,%p)\n",iface,start,samples,buffer,buffersize,flags,sampwritten,byteswritten); + + ICCompress( + as->hic,flags, + as->lpCompressFormat, + as->compbuffer, + as->lpInputFormat,buffer, + &ckid,&xflags, + as->curframe,0xffffff/*framesize*/,as->aco.dwQuality, + as->lpPrevFormat,as->lpPrev + ); + ICDecompress( + as->hic, + flags, /* FIXME: check */ + as->lpCompressFormat, + as->compbuffer, + as->decompformat, + as->decompbuffer + ); + /* We now have a prev format for the next compress ... */ + as->lpPrevFormat = as->decompformat; + as->lpPrev = as->decompbuffer; + return S_OK; +} + +static HRESULT WINAPI IAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples) { + FIXME("(%p)->Delete(%ld,%ld)\n",iface,start,samples); + return E_FAIL; +} +static HRESULT WINAPI IAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG *lpread) { + FIXME("(%p)->ReadData(0x%08lx,%p,%p)\n",iface,fcc,lp,lpread); + return E_FAIL; +} + +static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG size) { + FIXME("(%p)->WriteData(0x%08lx,%p,%ld)\n",iface,fcc,lp,size); + return E_FAIL; +} + +static HRESULT WINAPI IAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen) { + FIXME("(%p)->SetInfo(%p,%ld)\n",iface,info,infolen); + return E_FAIL; +} + +/*********************************************************************** + * AVIFileCreateStreamA + */ +HRESULT WINAPI AVIFileCreateStreamA(PAVIFILE iface,PAVISTREAM *ppavi,AVISTREAMINFOA * psi) { + AVISTREAMINFOW psiw; + + /* Only the szName at the end is different */ + memcpy(&psiw,psi,sizeof(*psi)-sizeof(psi->szName)); + MultiByteToWideChar( CP_ACP, 0, psi->szName, -1, + psiw.szName, sizeof(psiw.szName) / sizeof(WCHAR) ); + return IAVIFile_CreateStream(iface,ppavi,&psiw); +} + +/*********************************************************************** + * AVIFileCreateStreamW + */ +HRESULT WINAPI AVIFileCreateStreamW(IAVIFile*iface,PAVISTREAM*avis,AVISTREAMINFOW*asi) { + return IAVIFile_CreateStream(iface,avis,asi); +} + + +/*********************************************************************** + * AVIFileGetStream + */ +HRESULT WINAPI AVIFileGetStream(IAVIFile*iface,PAVISTREAM*avis,DWORD fccType,LONG lParam) { + return IAVIFile_GetStream(iface,avis,fccType,lParam); +} + +/*********************************************************************** + * AVIFileInfoA + */ +HRESULT WINAPI AVIFileInfoA(PAVIFILE iface,LPAVIFILEINFOA afi,LONG size) { + AVIFILEINFOW afiw; + HRESULT hres; + + if (size < sizeof(AVIFILEINFOA)) + return AVIERR_BADSIZE; + hres = IAVIFile_Info(iface,&afiw,sizeof(afiw)); + memcpy(afi,&afiw,sizeof(*afi)-sizeof(afi->szFileType)); + WideCharToMultiByte( CP_ACP, 0, afiw.szFileType, -1, + afi->szFileType, sizeof(afi->szFileType), NULL, NULL ); + afi->szFileType[sizeof(afi->szFileType)-1] = 0; + return hres; +} + +/*********************************************************************** + * AVIStreamInfoW + */ +HRESULT WINAPI AVIStreamInfoW(PAVISTREAM iface,AVISTREAMINFOW *asi,LONG + size) { + return IAVIFile_Info(iface,asi,size); +} + +/*********************************************************************** + * AVIStreamInfoA + */ +HRESULT WINAPI AVIStreamInfoA(PAVISTREAM iface,AVISTREAMINFOA *asi,LONG + size) { + AVISTREAMINFOW asiw; + HRESULT hres; + + if (sizeszName, sizeof(asi->szName), NULL, NULL ); + asi->szName[sizeof(asi->szName)-1] = 0; + return hres; +} + +/*********************************************************************** + * AVIFileInfoW + */ +HRESULT WINAPI AVIFileInfoW(PAVIFILE iface,LPAVIFILEINFOW afi,LONG size) { + return IAVIFile_Info(iface,afi,size); +} + +/*********************************************************************** + * AVIMakeCompressedStream + */ +HRESULT WINAPI AVIMakeCompressedStream(PAVISTREAM *ppsCompressed,PAVISTREAM ppsSource,AVICOMPRESSOPTIONS *aco,CLSID *pclsidHandler) { + char fcc[5]; + IAVIStreamImpl *as; + FIXME("(%p,%p,%p,%p)\n",ppsCompressed,ppsSource,aco,pclsidHandler); + fcc[4]='\0'; + memcpy(fcc,&(aco->fccType),4); + FIXME("\tfccType: '%s'\n",fcc); + memcpy(fcc,&(aco->fccHandler),4); + FIXME("\tfccHandler: '%s'\n",fcc); + FIXME("\tdwFlags: 0x%08lx\n",aco->dwFlags); + + /* we just create a duplicate for now */ + IAVIStream_AddRef(ppsSource); + *ppsCompressed = ppsSource; + as = (IAVIStreamImpl*)ppsSource; + + /* this is where the fun begins. Open a compressor and prepare it. */ + as->hic = ICOpen(aco->fccType,aco->fccHandler,ICMODE_COMPRESS); + + /* May happen. for instance if the codec is not able to compress */ + if (!as->hic) + return AVIERR_UNSUPPORTED; + + ICGetInfo(as->hic,&(as->icinfo),sizeof(ICINFO)); + FIXME("Opened compressor: '%s' '%s'\n",debugstr_w(as->icinfo.szName),debugstr_w(as->icinfo.szDescription)); + as->iscompressing = TRUE; + memcpy(&(as->aco),aco,sizeof(*aco)); + if (as->icinfo.dwFlags & VIDCF_COMPRESSFRAMES) { + ICCOMPRESSFRAMES icf; + + /* now what to fill in there ... Hmm */ + memset(&icf,0,sizeof(icf)); + icf.lDataRate = aco->dwBytesPerSecond; + icf.lQuality = aco->dwQuality; + icf.lKeyRate = aco->dwKeyFrameEvery; + + icf.GetData = (void *)0xdead4242; + icf.PutData = (void *)0xdead4243; + ICSendMessage(as->hic,ICM_COMPRESS_FRAMES_INFO,(LPARAM)&icf,sizeof(icf)); + } + return S_OK; +} + +/*********************************************************************** + * AVIStreamSetFormat + */ +HRESULT WINAPI AVIStreamSetFormat(PAVISTREAM iface,LONG pos,LPVOID format,LONG formatsize) { + return IAVIStream_SetFormat(iface,pos,format,formatsize); +} + +/*********************************************************************** + * AVIStreamReadFormat + */ +HRESULT WINAPI AVIStreamReadFormat(PAVISTREAM iface,LONG pos,LPVOID format,LONG *formatsize) { + return IAVIStream_ReadFormat(iface,pos,format,formatsize); +} + +/*********************************************************************** + * AVIStreamWrite( + */ +HRESULT WINAPI AVIStreamWrite(PAVISTREAM iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,DWORD flags,LONG *sampwritten,LONG *byteswritten) { + return IAVIStream_Write(iface,start,samples,buffer,buffersize,flags,sampwritten,byteswritten); +} + +/*********************************************************************** + * AVIStreamRead + */ +HRESULT WINAPI AVIStreamRead(PAVISTREAM iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,LONG *bytesread,LONG *samplesread) { + return IAVIStream_Read(iface,start,samples,buffer,buffersize,bytesread,samplesread); +} + +/*********************************************************************** + * AVIStreamWriteData + */ +HRESULT WINAPI AVIStreamWriteData(PAVISTREAM iface,DWORD fcc,LPVOID lp,LONG size) { + return IAVIStream_WriteData(iface,fcc,lp,size); +} + +/*********************************************************************** + * AVIStreamReadData + */ +HRESULT WINAPI AVIStreamReadData(PAVISTREAM iface,DWORD fcc,LPVOID lp,LONG *lpread) { + return IAVIStream_ReadData(iface,fcc,lp,lpread); +} + +/*********************************************************************** + * AVIStreamStart + */ +LONG WINAPI AVIStreamStart(PAVISTREAM iface) { + AVISTREAMINFOW si; + + IAVIStream_Info(iface,&si,sizeof(si)); + return si.dwStart; +} + +/*********************************************************************** + * AVIStreamLength + */ +LONG WINAPI AVIStreamLength(PAVISTREAM iface) { + AVISTREAMINFOW si; + HRESULT ret; + + ret = IAVIStream_Info(iface,&si,sizeof(si)); + if (ret) /* error */ + return 1; + return si.dwLength; +} + +/*********************************************************************** + * AVIStreamRelease + */ +ULONG WINAPI AVIStreamRelease(PAVISTREAM iface) { + return IAVIStream_Release(iface); +} + +/*********************************************************************** + * AVIStreamGetFrameOpen + */ +PGETFRAME WINAPI AVIStreamGetFrameOpen(PAVISTREAM iface,LPBITMAPINFOHEADER bmi) { + FIXME("(%p)->(%p),stub!\n",iface,bmi); + return NULL; +} + +/*********************************************************************** + * AVIStreamGetFrame + */ +LPVOID WINAPI AVIStreamGetFrame(PGETFRAME pg,LONG pos) { + return IGetFrame_GetFrame(pg,pos); +} + +/*********************************************************************** + * AVIStreamGetFrameClose + */ +HRESULT WINAPI AVIStreamGetFrameClose(PGETFRAME pg) { + if (pg) IGetFrame_Release(pg); + return 0; +} + +/*********************************************************************** + * AVIFileRelease + */ +ULONG WINAPI AVIFileRelease(PAVIFILE iface) { + return IAVIFile_Release(iface); +} + +/*********************************************************************** + * AVIFileExit + */ +void WINAPI AVIFileExit(void) { + FIXME("(), stub.\n"); +} diff --git a/complus/guiddef.h b/complus/guiddef.h new file mode 100644 index 00000000..b329dad2 --- /dev/null +++ b/complus/guiddef.h @@ -0,0 +1,95 @@ +/* guiddef.h + + Copyright (c) 1993-2000 the Wine project authors (see the file WINE-AUTHORS + for a complete list) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* already defined bu Mingw32/cpd +#ifndef GUID_DEFINED +#define GUID_DEFINED +typedef struct _GUID +{ + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[ 8 ]; +} GUID; +#endif +*/ + +#undef DEFINE_GUID + +#ifdef INITGUID +#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + const GUID name = \ + { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } +#else +#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + extern const GUID name +#endif + +#define DEFINE_OLEGUID(name, l, w1, w2) \ + DEFINE_GUID(name, l, w1, w2, 0xC0,0,0,0,0,0,0,0x46) + +#ifndef _GUIDDEF_H_ +#define _GUIDDEF_H_ + +/* typedef GUID *LPGUID; + typedef GUID CLSID,*LPCLSID; */ +typedef GUID IID,*LPIID; +typedef GUID FMTID,*LPFMTID; + +#if defined(__cplusplus) && !defined(CINTERFACE) +#define REFGUID const GUID & +#define REFCLSID const CLSID & +#define REFIID const IID & +#define REFFMTID const FMTID & +#else /* !defined(__cplusplus) && !defined(CINTERFACE) */ +#define REFGUID const GUID* const +#define REFCLSID const CLSID* const +#define REFIID const IID* const +#define REFFMTID const FMTID* const +#endif /* !defined(__cplusplus) && !defined(CINTERFACE) */ + +#if defined(__cplusplus) && !defined(CINTERFACE) +#define IsEqualGUID(rguid1, rguid2) (!memcmp(&(rguid1), &(rguid2), sizeof(GUID))) +#else /* defined(__cplusplus) && !defined(CINTERFACE) */ +#define IsEqualGUID(rguid1, rguid2) (!memcmp(rguid1, rguid2, sizeof(GUID))) +#endif /* defined(__cplusplus) && !defined(CINTERFACE) */ +#define IsEqualIID(riid1, riid2) IsEqualGUID(riid1, riid2) +#define IsEqualCLSID(rclsid1, rclsid2) IsEqualGUID(rclsid1, rclsid2) + +#if defined(__cplusplus) && !defined(CINTERFACE) +inline bool operator==(const GUID& guidOne, const GUID& guidOther) +{ + return !memcmp(&guidOne,&guidOther,sizeof(GUID)); +} +inline bool operator!=(const GUID& guidOne, const GUID& guidOther) +{ + return !(guidOne == guidOther); +} +#endif + +extern const IID GUID_NULL; +#define IID_NULL GUID_NULL +#define CLSID_NULL GUID_NULL +#define FMTID_NULL GUID_NULL + +#endif /* _GUIDDEF_H_ */ diff --git a/complus/ignupg.c b/complus/ignupg.c new file mode 100644 index 00000000..009d5db1 --- /dev/null +++ b/complus/ignupg.c @@ -0,0 +1,202 @@ +/* ignupg.c - COM+ class IGnuPG + * Copyright (C) 2000 Werner Koch (dd9jn) + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#define INITGUID +#include "ignupg.h" + +/* + * Declare the interface implementation structures + */ +typedef struct IGnuPGImpl IGnuPGImpl; +typedef struct IClassFactoryImpl IClassFactoryImpl; + + +struct IGnuPGImpl { + /* IUnknown required stuff */ + ICOM_VFIELD (IGnuPG); + DWORD ref; + /* Our stuff */ + int foo; +}; + + +struct IClassFactoryImpl { + /* IUnknown fields */ + ICOM_VFIELD(IClassFactory); + DWORD ref; +}; + + + +/********************************************************** + ************** IGnuPG Implementation ******************* + **********************************************************/ + +static HRESULT WINAPI +IGnuPGImpl_QueryInterface (IGnuPG *iface, REFIID refiid, LPVOID *obj) +{ + ICOM_THIS (IGnuPGImpl,iface); + + fprintf (stderr,"(%p)->QueryInterface(%s,%p)\n", + This, "debugstr_guid(refiid)", obj); + if ( IsEqualGUID (&IID_IUnknown, refiid) + || !IsEqualGUID (&IID_IGnuPG, refiid) ) { + *obj = iface; + return 0; + } + *obj = NULL; + return E_NOINTERFACE; +} + + +static ULONG WINAPI +IGnuPGImpl_AddRef (IGnuPG *iface) +{ + ICOM_THIS (IGnuPGImpl,iface); + + return ++This->ref; +} + + +static ULONG WINAPI +IGnuPGImpl_Release (IGnuPG *iface) +{ + ICOM_THIS (IGnuPGImpl,iface); + + if (--This->ref) + return This->ref; + + HeapFree(GetProcessHeap(),0,iface); + return 0; +} + + + + +static ICOM_VTABLE(IGnuPG) gnupg_vtbl = +{ + /* IUnknow methods */ + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + IGnuPGImpl_QueryInterface, + IGnuPGImpl_AddRef, + IGnuPGImpl_Release, + /* Our methods */ + +}; + + + +/*************************************************************** + ****************** GnuPG Factory **************************** + ***************************************************************/ + +static HRESULT WINAPI +GnuPGFactory_QueryInterface (IClassFactory *iface, REFIID refiid, LPVOID *obj) +{ + /*ICOM_THIS(IClassFactoryImpl,iface);*/ + return E_NOINTERFACE; +} + +static ULONG WINAPI +GnuPGFactory_AddRef (IClassFactory *iface) +{ + ICOM_THIS(IClassFactoryImpl,iface); + return ++(This->ref); +} + +static ULONG WINAPI +GnuPGFactory_Release (IClassFactory *iface) +{ + ICOM_THIS(IClassFactoryImpl,iface); + return --(This->ref); +} + +static HRESULT WINAPI +GnuPGFactory_CreateInstance (IClassFactory *iface, IUnknown *outer, + REFIID refiid, LPVOID *r_obj ) +{ + /*ICOM_THIS(IClassFactoryImpl,iface);*/ + + if ( IsEqualGUID (&IID_IGnuPG, refiid) ) { + IGnuPGImpl *obj; + + obj = HeapAlloc (GetProcessHeap(), 0, sizeof *obj ); + if ( !obj) + return E_OUTOFMEMORY; + + ICOM_VTBL(obj) = &gnupg_vtbl; + obj->ref = 1; + *r_obj = obj; + return 0; + } + *r_obj = NULL; + return E_NOINTERFACE; +} + +static HRESULT WINAPI +GnuPGFactory_LockServer (IClassFactory *iface, BOOL dolock ) +{ + /*ICOM_THIS(IClassFactoryImpl,iface);*/ + return 0; +} + +static ICOM_VTABLE(IClassFactory) gnupg_factory_vtbl = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + GnuPGFactory_QueryInterface, + GnuPGFactory_AddRef, + GnuPGFactory_Release, + GnuPGFactory_CreateInstance, + GnuPGFactory_LockServer +}; +static IClassFactoryImpl GnuPG_CF = {&gnupg_factory_vtbl, 1 }; + + +IClassFactory * +gnupg_factory_new ( CLSID *r_clsid ) +{ + *r_clsid = CLSID_GnuPG; + IClassFactory_AddRef((IClassFactory*)&GnuPG_CF); + return (IClassFactory*)&GnuPG_CF; +} + +void +gnupg_factory_release ( IClassFactory *factory ) +{ + /* it's static - nothing to do */ +} + + + + + + + + + diff --git a/complus/ignupg.h b/complus/ignupg.h new file mode 100644 index 00000000..e9cf9a69 --- /dev/null +++ b/complus/ignupg.h @@ -0,0 +1,68 @@ +/* ignupg.h - COM+ class IGnuPG + * Copyright (C) 2000 Werner Koch (dd9jn) + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef IGNUPG_H +#define IGNUPG_H 1 + +#include "obj_base.h" + +DEFINE_GUID(CLSID_GnuPG, 0x42424242, 0x62e8, 0x11cf, + 0x93, 0xbc, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0); +DEFINE_GUID(IID_IGnuPG, 0x24242424, 0x4981, 0x11CE, + 0xA5,0x21,0x00,0x20,0xAF,0x0B,0xE5,0x60); +typedef struct IGnuPG IGnuPG; + + + +#define ICOM_INTERFACE IGnuPG + +#define IGnuPG_METHODS \ + ICOM_METHOD1(HRESULT,Initialize, REFIID,) \ + ICOM_METHOD1(HRESULT,EnumDevices, LPVOID,) + +#define IGnuPG_IMETHODS \ + IUnknown_IMETHODS \ + IGnuPG_METHODS + +ICOM_DEFINE(IGnuPG,IUnknown) +#undef ICOM_INTERFACE + + +/*** IUnknown methods ***/ +#define IGnuPG_QueryInterface(p,a,b) ICOM_CALL2(QueryInterface,p,a,b) +#define IGnuPG_AddRef(p) ICOM_CALL (AddRef,p) +#define IGnuPG_Release(p) ICOM_CALL (Release,p) +/*** IGnuPG methods ***/ +#define IGnuPG_Initialize(p,a) ICOM_CALL1(Initialize,p,a) +#define IGnuPG_EnumDevices(p,a,b) ICOM_CALL2(EnumDevice,p,a,b) + + +#endif /*IGNUPG_H*/ + + + + + + + + + + + diff --git a/complus/main.c b/complus/main.c index 221a66b0..519d2bc6 100644 --- a/complus/main.c +++ b/complus/main.c @@ -28,6 +28,8 @@ #include #include +#include "obj_base.h" + #include "argparse.h" #include "main.h" @@ -71,6 +73,9 @@ static ARGPARSE_OPTS opts[] = { { oEmbedding, "Embedding" , 0, "@" }, {0} }; + + + static const char * my_strusage( int level ) { @@ -258,30 +263,23 @@ enter_complus () { HANDLE running; int reg; - void *factory; + IClassFactory *factory; + CLSID clsid; - /* CoInitializeEx (NULL, COINIT_MULTITHREADED); */ + CoInitializeEx (NULL, COINIT_MULTITHREADED); running = CreateEvent (NULL, FALSE, FALSE, NULL ); - #if 0 - factory = create_class_factory (); - CoRegisterClassObject (CLSID_gpgme, factory, + factory = gnupg_factory_new ( &clsid ); + CoRegisterClassObject (&clsid, (IUnknown*)factory, CLSCTX_LOCAL_SERVER, - REGCLS_SUSPENDED|REGCLASS_MULTIPLEUSE, ® ); + REGCLS_SUSPENDED|REGCLS_MULTIPLEUSE, ® ); CoResumeClassObjects (); - #endif WaitForSingleObject ( running, INFINITE ); CloseHandle (running); - #if 0 CoRevokeClassObject ( reg ); - factory->release (); - CoUnitialize (); - #endif + gnupg_factory_release (factory); + CoUninitialize (); } - - - - diff --git a/complus/main.h b/complus/main.h index 9c48c7b5..472b8cd8 100644 --- a/complus/main.h +++ b/complus/main.h @@ -38,6 +38,10 @@ struct { } opt; +/*-- ignupg.c --*/ +IClassFactory *gnupg_factory_new ( CLSID *r_clsid ); +void gnupg_factory_release ( IClassFactory *factory ); + #endif /* COMPLUS_MAIN_H */ diff --git a/complus/obj_base.h b/complus/obj_base.h new file mode 100644 index 00000000..8707ae95 --- /dev/null +++ b/complus/obj_base.h @@ -0,0 +1,800 @@ +/* obj_base.h - This file defines the macros and types necessary to + define COM interfaces, and the three most basic COM interfaces: + IUnknown, IMalloc and IClassFactory. + + Copyright (c) 1993-2000 the Wine project authors (see the file WINE-AUTHORS + for a complete list) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __WINE_WINE_OBJ_BASE_H +#define __WINE_WINE_OBJ_BASE_H + +/* check these values! */ +#define E_NOINTERFACE 0x80040002 +#define E_OUTOFMEMORY 0x8007000E + +/***************************************************************************** + * define ICOM_MSVTABLE_COMPAT + * to implement the microsoft com vtable compatibility workaround for g++. + * + * NOTE: Turning this option on will produce a winelib that is incompatible + * with the binary emulator. + * + * If the compiler supports the com_interface attribute, leave this off, and + * define the ICOM_USE_COM_INTERFACE_ATTRIBUTE macro below. This may also + * require the addition of the -vtable-thunks option for g++. + * + * If you aren't interested in Winelib C++ compatibility at all, leave both + * options off. + * + * The preferable method for using ICOM_USE_COM_INTERFACE_ATTRIBUTE macro + * would be to define it only for your Winelib application. This allows you + * to have both binary and Winelib compatibility for C and C++ at the same + * time :) + */ +/* #define ICOM_MSVTABLE_COMPAT 1 */ +/* #define ICOM_USE_COM_INTERFACE_ATTRIBUTE 1 */ + +/***************************************************************************** + * Defines the basic types + */ +#include "wtypes.h" +#include "guiddef.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifndef NONAMELESSSTRUCT +#define LISet32(li, v) ((li).HighPart = (v) < 0 ? -1 : 0, (li).LowPart = (v)) +#define ULISet32(li, v) ((li).HighPart = 0, (li).LowPart = (v)) +#else +#define LISet32(li, v) ((li).s.HighPart = (v) < 0 ? -1 : 0, (li).s.LowPart = (v)) +#define ULISet32(li, v) ((li).s.HighPart = 0, (li).s.LowPart = (v)) +#endif + +/***************************************************************************** + * GUID API + */ +HRESULT WINAPI StringFromCLSID16(REFCLSID id, LPOLESTR16*); +HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR*); + +HRESULT WINAPI CLSIDFromString16(LPCOLESTR16, CLSID *); +HRESULT WINAPI CLSIDFromString(LPCOLESTR, CLSID *); + +HRESULT WINAPI CLSIDFromProgID16(LPCOLESTR16 progid, LPCLSID riid); +HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid); + +HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID); + + +INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax); + + +/***************************************************************************** + * Macros to define a COM interface + */ +/* + * The goal of the following set of definitions is to provide a way to use the same + * header file definitions to provide both a C interface and a C++ object oriented + * interface to COM interfaces. The type of interface is selected automatically + * depending on the language but it is always possible to get the C interface in C++ + * by defining CINTERFACE. + * + * It is based on the following assumptions: + * - all COM interfaces derive from IUnknown, this should not be a problem. + * - the header file only defines the interface, the actual fields are defined + * separately in the C file implementing the interface. + * + * The natural approach to this problem would be to make sure we get a C++ class and + * virtual methods in C++ and a structure with a table of pointer to functions in C. + * Unfortunately the layout of the virtual table is compiler specific, the layout of + * g++ virtual tables is not the same as that of an egcs virtual table which is not the + * same as that generated by Visual C+. There are workarounds to make the virtual tables + * compatible via padding but unfortunately the one which is imposed to the WINE emulator + * by the Windows binaries, i.e. the Visual C++ one, is the most compact of all. + * + * So the solution I finally adopted does not use virtual tables. Instead I use inline + * non virtual methods that dereference the method pointer themselves and perform the call. + * + * Let's take Direct3D as an example: + * + * #define ICOM_INTERFACE IDirect3D + * #define IDirect3D_METHODS \ + * ICOM_METHOD1(HRESULT,Initialize, REFIID,) \ + * ICOM_METHOD2(HRESULT,EnumDevices, LPD3DENUMDEVICESCALLBACK,, LPVOID,) \ + * ICOM_METHOD2(HRESULT,CreateLight, LPDIRECT3DLIGHT*,, IUnknown*,) \ + * ICOM_METHOD2(HRESULT,CreateMaterial,LPDIRECT3DMATERIAL*,, IUnknown*,) \ + * ICOM_METHOD2(HRESULT,CreateViewport,LPDIRECT3DVIEWPORT*,, IUnknown*,) \ + * ICOM_METHOD2(HRESULT,FindDevice, LPD3DFINDDEVICESEARCH,, LPD3DFINDDEVICERESULT,) + * #define IDirect3D_IMETHODS \ + * IUnknown_IMETHODS \ + * IDirect3D_METHODS + * ICOM_DEFINE(IDirect3D,IUnknown) + * #undef ICOM_INTERFACE + * + * #ifdef ICOM_CINTERFACE + * // *** IUnknown methods *** // + * #define IDirect3D_QueryInterface(p,a,b) ICOM_CALL2(QueryInterface,p,a,b) + * #define IDirect3D_AddRef(p) ICOM_CALL (AddRef,p) + * #define IDirect3D_Release(p) ICOM_CALL (Release,p) + * // *** IDirect3D methods *** // + * #define IDirect3D_Initialize(p,a) ICOM_CALL1(Initialize,p,a) + * #define IDirect3D_EnumDevices(p,a,b) ICOM_CALL2(EnumDevice,p,a,b) + * #define IDirect3D_CreateLight(p,a,b) ICOM_CALL2(CreateLight,p,a,b) + * #define IDirect3D_CreateMaterial(p,a,b) ICOM_CALL2(CreateMaterial,p,a,b) + * #define IDirect3D_CreateViewport(p,a,b) ICOM_CALL2(CreateViewport,p,a,b) + * #define IDirect3D_FindDevice(p,a,b) ICOM_CALL2(FindDevice,p,a,b) + * #endif + * + * Comments: + * - The ICOM_INTERFACE macro is used in the ICOM_METHOD macros to define the type of the 'this' + * pointer. Defining this macro here saves us the trouble of having to repeat the interface + * name everywhere. Note however that because of the way macros work, a macro like ICOM_METHOD1 + * cannot use 'ICOM_INTERFACE##_VTABLE' because this would give 'ICOM_INTERFACE_VTABLE' and not + * 'IDirect3D_VTABLE'. + * - ICOM_METHODS defines the methods specific to this interface. It is then aggregated with the + * inherited methods to form ICOM_IMETHODS. + * - ICOM_IMETHODS defines the list of methods that are inheritable from this interface. It must + * be written manually (rather than using a macro to generate the equivalent code) to avoid + * macro recursion (which compilers don't like). + * - The ICOM_DEFINE finally declares all the structures necessary for the interface. We have to + * explicitly use the interface name for macro expansion reasons again. + * Inherited methods are inherited in C by using the IDirect3D_METHODS macro and the parent's + * Xxx_IMETHODS macro. In C++ we need only use the IDirect3D_METHODS since method inheritance + * is taken care of by the language. + * - In C++ the ICOM_METHOD macros generate a function prototype and a call to a function pointer + * method. This means using once 't1 p1, t2 p2, ...' and once 'p1, p2' without the types. The + * only way I found to handle this is to have one ICOM_METHOD macro per number of parameters and + * to have it take only the type information (with const if necessary) as parameters. + * The 'undef ICOM_INTERFACE' is here to remind you that using ICOM_INTERFACE in the following + * macros will not work. This time it's because the ICOM_CALL macro expansion is done only once + * the 'IDirect3D_Xxx' macro is expanded. And by that time ICOM_INTERFACE will be long gone + * anyway. + * - You may have noticed the double commas after each parameter type. This allows you to put the + * name of that parameter which I think is good for documentation. It is not required and since + * I did not know what to put there for this example (I could only find doc about IDirect3D2), + * I left them blank. + * - Finally the set of 'IDirect3D_Xxx' macros is a standard set of macros defined to ease access + * to the interface methods in C. Unfortunately I don't see any way to avoid having to duplicate + * the inherited method definitions there. This time I could have used a trick to use only one + * macro whatever the number of parameters but I prefered to have it work the same way as above. + * - You probably have noticed that we don't define the fields we need to actually implement this + * interface: reference count, pointer to other resources and miscellaneous fields. That's + * because these interfaces are just that: interfaces. They may be implemented more than once, in + * different contexts and sometimes not even in Wine. Thus it would not make sense to impose + * that the interface contains some specific fields. + * + * + * In C this gives: + * typedef struct IDirect3DVtbl IDirect3DVtbl; + * struct IDirect3D { + * IDirect3DVtbl* lpVtbl; + * }; + * struct IDirect3DVtbl { + * HRESULT (*fnQueryInterface)(IDirect3D* me, REFIID riid, LPVOID* ppvObj); + * ULONG (*fnQueryInterface)(IDirect3D* me); + * ULONG (*fnQueryInterface)(IDirect3D* me); + * HRESULT (*fnInitialize)(IDirect3D* me, REFIID a); + * HRESULT (*fnEnumDevices)(IDirect3D* me, LPD3DENUMDEVICESCALLBACK a, LPVOID b); + * HRESULT (*fnCreateLight)(IDirect3D* me, LPDIRECT3DLIGHT* a, IUnknown* b); + * HRESULT (*fnCreateMaterial)(IDirect3D* me, LPDIRECT3DMATERIAL* a, IUnknown* b); + * HRESULT (*fnCreateViewport)(IDirect3D* me, LPDIRECT3DVIEWPORT* a, IUnknown* b); + * HRESULT (*fnFindDevice)(IDirect3D* me, LPD3DFINDDEVICESEARCH a, LPD3DFINDDEVICERESULT b); + * }; + * + * #ifdef ICOM_CINTERFACE + * // *** IUnknown methods *** // + * #define IDirect3D_QueryInterface(p,a,b) (p)->lpVtbl->fnQueryInterface(p,a,b) + * #define IDirect3D_AddRef(p) (p)->lpVtbl->fnAddRef(p) + * #define IDirect3D_Release(p) (p)->lpVtbl->fnRelease(p) + * // *** IDirect3D methods *** // + * #define IDirect3D_Initialize(p,a) (p)->lpVtbl->fnInitialize(p,a) + * #define IDirect3D_EnumDevices(p,a,b) (p)->lpVtbl->fnEnumDevice(p,a,b) + * #define IDirect3D_CreateLight(p,a,b) (p)->lpVtbl->fnCreateLight(p,a,b) + * #define IDirect3D_CreateMaterial(p,a,b) (p)->lpVtbl->fnCreateMaterial(p,a,b) + * #define IDirect3D_CreateViewport(p,a,b) (p)->lpVtbl->fnCreateViewport(p,a,b) + * #define IDirect3D_FindDevice(p,a,b) (p)->lpVtbl->fnFindDevice(p,a,b) + * #endif + * + * Comments: + * - IDirect3D only contains a pointer to the IDirect3D virtual/jump table. This is the only thing + * the user needs to know to use the interface. Of course the structure we will define to + * implement this interface will have more fields but the first one will match this pointer. + * - The code generated by ICOM_DEFINE defines both the structure representing the interface and + * the structure for the jump table. ICOM_DEFINE uses the parent's Xxx_IMETHODS macro to + * automatically repeat the prototypes of all the inherited methods and then uses IDirect3D_METHODS + * to define the IDirect3D methods. + * - Each method is declared as a pointer to function field in the jump table. The implementation + * will fill this jump table with appropriate values, probably using a static variable, and + * initialize the lpVtbl field to point to this variable. + * - The IDirect3D_Xxx macros then just derefence the lpVtbl pointer and use the function pointer + * corresponding to the macro name. This emulates the behavior of a virtual table and should be + * just as fast. + * - This C code should be quite compatible with the Windows headers both for code that uses COM + * interfaces and for code implementing a COM interface. + * + * + * And in C++ (with gcc's g++): + * + * typedef struct IDirect3D: public IUnknown { + * private: HRESULT (*fnInitialize)(IDirect3D* me, REFIID a); + * public: inline HRESULT Initialize(REFIID a) { return ((IDirect3D*)t.lpVtbl)->fnInitialize(this,a); }; + * private: HRESULT (*fnEnumDevices)(IDirect3D* me, LPD3DENUMDEVICESCALLBACK a, LPVOID b); + * public: inline HRESULT EnumDevices(LPD3DENUMDEVICESCALLBACK a, LPVOID b) + * { return ((IDirect3D*)t.lpVtbl)->fnEnumDevices(this,a,b); }; + * private: HRESULT (*fnCreateLight)(IDirect3D* me, LPDIRECT3DLIGHT* a, IUnknown* b); + * public: inline HRESULT CreateLight(LPDIRECT3DLIGHT* a, IUnknown* b) + * { return ((IDirect3D*)t.lpVtbl)->fnCreateLight(this,a,b); }; + * private: HRESULT (*fnCreateMaterial)(IDirect3D* me, LPDIRECT3DMATERIAL* a, IUnknown* b); + * public: inline HRESULT CreateMaterial(LPDIRECT3DMATERIAL* a, IUnknown* b) + * { return ((IDirect3D*)t.lpVtbl)->fnCreateMaterial(this,a,b); }; + * private: HRESULT (*fnCreateViewport)(IDirect3D* me, LPDIRECT3DVIEWPORT* a, IUnknown* b); + * public: inline HRESULT CreateViewport(LPDIRECT3DVIEWPORT* a, IUnknown* b) + * { return ((IDirect3D*)t.lpVtbl)->fnCreateViewport(this,a,b); }; + * private: HRESULT (*fnFindDevice)(IDirect3D* me, LPD3DFINDDEVICESEARCH a, LPD3DFINDDEVICERESULT b); + * public: inline HRESULT FindDevice(LPD3DFINDDEVICESEARCH a, LPD3DFINDDEVICERESULT b) + * { return ((IDirect3D*)t.lpVtbl)->fnFindDevice(this,a,b); }; + * }; + * + * Comments: + * - In C++ IDirect3D does double duty as both the virtual/jump table and as the interface + * definition. The reason for this is to avoid having to duplicate the mehod definitions: once + * to have the function pointers in the jump table and once to have the methods in the interface + * class. Here one macro can generate both. This means though that the first pointer, t.lpVtbl + * defined in IUnknown, must be interpreted as the jump table pointer if we interpret the + * structure as the the interface class, and as the function pointer to the QueryInterface + * method, t.fnQueryInterface, if we interpret the structure as the jump table. Fortunately this + * gymnastic is entirely taken care of in the header of IUnknown. + * - Of course in C++ we use inheritance so that we don't have to duplicate the method definitions. + * - Since IDirect3D does double duty, each ICOM_METHOD macro defines both a function pointer and + * a non-vritual inline method which dereferences it and calls it. This way this method behaves + * just like a virtual method but does not create a true C++ virtual table which would break the + * structure layout. If you look at the implementation of these methods you'll notice that they + * would not work for void functions. We have to return something and fortunately this seems to + * be what all the COM methods do (otherwise we would need another set of macros). + * - Note how the ICOM_METHOD generates both function prototypes mixing types and formal parameter + * names and the method invocation using only the formal parameter name. This is the reason why + * we need different macros to handle different numbers of parameters. + * - Finally there is no IDirect3D_Xxx macro. These are not needed in C++ unless the CINTERFACE + * macro is defined in which case we would not be here. + * - This C++ code works well for code that just uses COM interfaces. But it will not work with + * C++ code implement a COM interface. That's because such code assumes the interface methods + * are declared as virtual C++ methods which is not the case here. + * + * + * Implementing a COM interface. + * + * This continues the above example. This example assumes that the implementation is in C. + * + * typedef struct _IDirect3D { + * void* lpVtbl; + * // ... + * + * } _IDirect3D; + * + * static ICOM_VTABLE(IDirect3D) d3dvt; + * + * // implement the IDirect3D methods here + * + * int IDirect3D_fnQueryInterface(IDirect3D* me) + * { + * ICOM_THIS(IDirect3D,me); + * // ... + * } + * + * // ... + * + * static ICOM_VTABLE(IDirect3D) d3dvt = { + * ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + * IDirect3D_fnQueryInterface, + * IDirect3D_fnAdd, + * IDirect3D_fnAdd2, + * IDirect3D_fnInitialize, + * IDirect3D_fnSetWidth + * }; + * + * Comments: + * - We first define what the interface really contains. This is th e_IDirect3D structure. The + * first field must of course be the virtual table pointer. Everything else is free. + * - Then we predeclare our static virtual table variable, we will need its address in some + * methods to initialize the virtual table pointer of the returned interface objects. + * - Then we implement the interface methods. To match what has been declared in the header file + * they must take a pointer to a IDirect3D structure and we must cast it to an _IDirect3D so that + * we can manipulate the fields. This is performed by the ICOM_THIS macro. + * - Finally we initialize the virtual table. + */ + + +#define ICOM_VTABLE(iface) iface##Vtbl +#define ICOM_VFIELD(iface) ICOM_VTABLE(iface)* lpVtbl +#define ICOM_VTBL(iface) (iface)->lpVtbl + + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define ICOM_CINTERFACE 1 +#endif + +#ifndef ICOM_CINTERFACE +/* C++ interface */ + +#define ICOM_METHOD(ret,xfn) \ + public: virtual ret CALLBACK (xfn)(void) = 0; +#define ICOM_METHOD1(ret,xfn,ta,na) \ + public: virtual ret CALLBACK (xfn)(ta a) = 0; +#define ICOM_METHOD2(ret,xfn,ta,na,tb,nb) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b) = 0; +#define ICOM_METHOD3(ret,xfn,ta,na,tb,nb,tc,nc) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b,tc c) = 0; +#define ICOM_METHOD4(ret,xfn,ta,na,tb,nb,tc,nc,td,nd) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b,tc c,td d) = 0; +#define ICOM_METHOD5(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b,tc c,td d,te e) = 0; +#define ICOM_METHOD6(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f) = 0; +#define ICOM_METHOD7(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g) = 0; +#define ICOM_METHOD8(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g,th h) = 0; +#define ICOM_METHOD9(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i) = 0; +#define ICOM_METHOD10(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j) = 0; +#define ICOM_METHOD11(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj,tk,nk) \ + public: virtual ret CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j,tk k) = 0; + + +#define ICOM_VMETHOD(xfn) \ + public: virtual void CALLBACK (xfn)(void) = 0; +#define ICOM_VMETHOD1(xfn,ta,na) \ + public: virtual void CALLBACK (xfn)(ta a) = 0; +#define ICOM_VMETHOD2(xfn,ta,na,tb,nb) \ + public: virtual void CALLBACK (xfn)(ta a,tb b) = 0; +#define ICOM_VMETHOD3(xfn,ta,na,tb,nb,tc,nc) \ + public: virtual void CALLBACK (xfn)(ta a,tb b,tc c) = 0; +#define ICOM_VMETHOD4(xfn,ta,na,tb,nb,tc,nc,td,nd) \ + public: virtual void CALLBACK (xfn)(ta a,tb b,tc c,td d) = 0; +#define ICOM_VMETHOD5(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne) \ + public: virtual void CALLBACK (xfn)(ta a,tb b,tc c,td d,te e) = 0; +#define ICOM_VMETHOD6(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf) \ + public: virtual void CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f) = 0; +#define ICOM_VMETHOD7(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng) \ + public: virtual void CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g) = 0; +#define ICOM_VMETHOD8(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh) \ + public: virtual void CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g,th h) = 0; +#define ICOM_VMETHOD9(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni) \ + public: virtual void CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i) = 0; +#define ICOM_VMETHOD10(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj) \ + public: virtual void CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i, tj j) = 0; +#define ICOM_VMETHOD11(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj,tk,nk) \ + public: virtual void CALLBACK (xfn)(ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i, tj j, tk k) = 0; + + +#ifdef ICOM_USE_COM_INTERFACE_ATTRIBUTE + +#define ICOM_DEFINE(iface,ibase) \ + typedef struct iface: public ibase { \ + iface##_METHODS \ + } __attribute__ ((com_interface)); + +#else + +#define ICOM_DEFINE(iface,ibase) \ + typedef struct iface: public ibase { \ + iface##_METHODS \ + }; + +#endif /* ICOM_USE_COM_INTERFACE_ATTRIBUTE */ + +#define ICOM_CALL(xfn, p) (p)->xfn() +#define ICOM_CALL1(xfn, p,a) (p)->xfn(a) +#define ICOM_CALL2(xfn, p,a,b) (p)->xfn(a,b) +#define ICOM_CALL3(xfn, p,a,b,c) (p)->xfn(a,b,c) +#define ICOM_CALL4(xfn, p,a,b,c,d) (p)->xfn(a,b,c,d) +#define ICOM_CALL5(xfn, p,a,b,c,d,e) (p)->xfn(a,b,c,d,e) +#define ICOM_CALL6(xfn, p,a,b,c,d,e,f) (p)->xfn(a,b,c,d,e,f) +#define ICOM_CALL7(xfn, p,a,b,c,d,e,f,g) (p)->xfn(a,b,c,d,e,f,g) +#define ICOM_CALL8(xfn, p,a,b,c,d,e,f,g,h) (p)->xfn(a,b,c,d,e,f,g,h) +#define ICOM_CALL9(xfn, p,a,b,c,d,e,f,g,h,i) (p)->xfn(a,b,c,d,e,f,g,h,i) +#define ICOM_CALL10(xfn, p,a,b,c,d,e,f,g,h,i,j) (p)->xfn(a,b,c,d,e,f,g,h,i,j) +#define ICOM_CALL11(xfn, p,a,b,c,d,e,f,g,h,i,j,k) (p)->xfn(a,b,c,d,e,f,g,h,i,j,k) + + +#else +/* C interface */ + + +#ifdef __WINE__ + +#define ICOM_METHOD(ret,xfn) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me); +#define ICOM_METHOD1(ret,xfn,ta,na) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a); +#define ICOM_METHOD2(ret,xfn,ta,na,tb,nb) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b); +#define ICOM_METHOD3(ret,xfn,ta,na,tb,nb,tc,nc) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c); +#define ICOM_METHOD4(ret,xfn,ta,na,tb,nb,tc,nc,td,nd) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d); +#define ICOM_METHOD5(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e); +#define ICOM_METHOD6(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f); +#define ICOM_METHOD7(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g); +#define ICOM_METHOD8(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h); +#define ICOM_METHOD9(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i); +#define ICOM_METHOD10(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j); +#define ICOM_METHOD11(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj,tk,nk) \ + ret CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j,tk k); + +#define ICOM_VMETHOD(xfn) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me); +#define ICOM_VMETHOD1(xfn,ta,na) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a); +#define ICOM_VMETHOD2(xfn,ta,na,tb,nb) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b); +#define ICOM_VMETHOD3(xfn,ta,na,tb,nb,tc,nc) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c); +#define ICOM_VMETHOD4(xfn,ta,na,tb,nb,tc,nc,td,nd) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d); +#define ICOM_VMETHOD5(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e); +#define ICOM_VMETHOD6(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f); +#define ICOM_VMETHOD7(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g); +#define ICOM_VMETHOD8(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,nh) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h); +#define ICOM_VMETHOD9(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ni) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i); +#define ICOM_VMETHOD10(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,nj) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j); +#define ICOM_VMETHOD11(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj,nk) \ + void CALLBACK (*fn##xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j,tk k); + +#define ICOM_CALL(xfn, p) ICOM_VTBL(p)->fn##xfn(p) +#define ICOM_CALL1(xfn, p,a) ICOM_VTBL(p)->fn##xfn(p,a) +#define ICOM_CALL2(xfn, p,a,b) ICOM_VTBL(p)->fn##xfn(p,a,b) +#define ICOM_CALL3(xfn, p,a,b,c) ICOM_VTBL(p)->fn##xfn(p,a,b,c) +#define ICOM_CALL4(xfn, p,a,b,c,d) ICOM_VTBL(p)->fn##xfn(p,a,b,c,d) +#define ICOM_CALL5(xfn, p,a,b,c,d,e) ICOM_VTBL(p)->fn##xfn(p,a,b,c,d,e) +#define ICOM_CALL6(xfn, p,a,b,c,d,e,f) ICOM_VTBL(p)->fn##xfn(p,a,b,c,d,e,f) +#define ICOM_CALL7(xfn, p,a,b,c,d,e,f,g) ICOM_VTBL(p)->fn##xfn(p,a,b,c,d,e,f,g) +#define ICOM_CALL8(xfn, p,a,b,c,d,e,f,g,h) ICOM_VTBL(p)->fn##xfn(p,a,b,c,d,e,f,g,h) +#define ICOM_CALL9(xfn, p,a,b,c,d,e,f,g,h,i) ICOM_VTBL(p)->fn##xfn(p,a,b,c,d,e,f,g,h,i) +#define ICOM_CALL10(xfn, p,a,b,c,d,e,f,g,h,i,j) ICOM_VTBL(p)->fn##xfn(p,a,b,c,d,e,f,g,h,i,j) +#define ICOM_CALL11(xfn, p,a,b,c,d,e,f,g,h,i,j,k) ICOM_VTBL(p)->fn##xfn(p,a,b,c,d,e,f,g,h,i,j,k) + +#else + +/* WINELIB case */ + +#define ICOM_METHOD(ret,xfn) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me); +#define ICOM_METHOD1(ret,xfn,ta,na) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a); +#define ICOM_METHOD2(ret,xfn,ta,na,tb,nb) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b); +#define ICOM_METHOD3(ret,xfn,ta,na,tb,nb,tc,nc) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c); +#define ICOM_METHOD4(ret,xfn,ta,na,tb,nb,tc,nc,td,nd) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d); +#define ICOM_METHOD5(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e); +#define ICOM_METHOD6(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f); +#define ICOM_METHOD7(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g); +#define ICOM_METHOD8(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h); +#define ICOM_METHOD9(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i); +#define ICOM_METHOD10(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j); +#define ICOM_METHOD11(ret,xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj,tk,nk) \ + ret CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j,tk k); + +#define ICOM_VMETHOD(xfn) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me); +#define ICOM_VMETHOD1(xfn,ta,na) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a); +#define ICOM_VMETHOD2(xfn,ta,na,tb,nb) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b); +#define ICOM_VMETHOD3(xfn,ta,na,tb,nb,tc,nc) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c); +#define ICOM_VMETHOD4(xfn,ta,na,tb,nb,tc,nc,td,nd) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d); +#define ICOM_VMETHOD5(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e); +#define ICOM_VMETHOD6(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f); +#define ICOM_VMETHOD7(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g); +#define ICOM_VMETHOD8(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,nh) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h); +#define ICOM_VMETHOD9(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ni) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i); +#define ICOM_VMETHOD10(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,nj) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j); +#define ICOM_VMETHOD11(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj,nk) \ + void CALLBACK (*xfn)(ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j,tk k); + +#define ICOM_CVMETHOD(xfn) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me); +#define ICOM_CVMETHOD1(xfn,ta,na) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a); +#define ICOM_CVMETHOD2(xfn,ta,na,tb,nb) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b); +#define ICOM_CVMETHOD3(xfn,ta,na,tb,nb,tc,nc) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b,tc c); +#define ICOM_CVMETHOD4(xfn,ta,na,tb,nb,tc,nc,td,nd) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b,tc c,td d); +#define ICOM_CVMETHOD5(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e); +#define ICOM_CVMETHOD6(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f); +#define ICOM_CVMETHOD7(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g); +#define ICOM_CVMETHOD8(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h); + +#define ICOM_CVMETHOD9(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i); +#define ICOM_CVMETHOD10(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j); +#define ICOM_CVMETHOD11(xfn,ta,na,tb,nb,tc,nc,td,nd,te,ne,tf,nf,tg,ng,th,nh,ti,ni,tj,nj,tk,nk) \ + void CALLBACK (*xfn)(const ICOM_INTERFACE* me,ta a,tb b,tc c,td d,te e,tf f,tg g,th h,ti i,tj j,tk k); + +#define ICOM_CALL(xfn, p) ICOM_VTBL(p)->xfn(p) +#define ICOM_CALL1(xfn, p,a) ICOM_VTBL(p)->xfn(p,a) +#define ICOM_CALL2(xfn, p,a,b) ICOM_VTBL(p)->xfn(p,a,b) +#define ICOM_CALL3(xfn, p,a,b,c) ICOM_VTBL(p)->xfn(p,a,b,c) +#define ICOM_CALL4(xfn, p,a,b,c,d) ICOM_VTBL(p)->xfn(p,a,b,c,d) +#define ICOM_CALL5(xfn, p,a,b,c,d,e) ICOM_VTBL(p)->xfn(p,a,b,c,d,e) +#define ICOM_CALL6(xfn, p,a,b,c,d,e,f) ICOM_VTBL(p)->xfn(p,a,b,c,d,e,f) +#define ICOM_CALL7(xfn, p,a,b,c,d,e,f,g) ICOM_VTBL(p)->xfn(p,a,b,c,d,e,f,g) +#define ICOM_CALL8(xfn, p,a,b,c,d,e,f,g,h) ICOM_VTBL(p)->xfn(p,a,b,c,d,e,f,g,h) +#define ICOM_CALL9(xfn, p,a,b,c,d,e,f,g,h,i) ICOM_VTBL(p)->xfn(p,a,b,c,d,e,f,g,h,i) +#define ICOM_CALL10(xfn, p,a,b,c,d,e,f,g,h,i,j) ICOM_VTBL(p)->xfn(p,a,b,c,d,e,f,g,h,i,j) +#define ICOM_CALL11(xfn, p,a,b,c,d,e,f,g,h,i,j,k) ICOM_VTBL(p)->xfn(p,a,b,c,d,e,f,g,h,i,j,k) + +#endif /* __WINE__ */ + +#ifdef ICOM_MSVTABLE_COMPAT +#define ICOM_DEFINE(iface,ibase) \ + typedef struct ICOM_VTABLE(iface) ICOM_VTABLE(iface); \ + struct iface { \ + const ICOM_VFIELD(iface); \ + }; \ + struct ICOM_VTABLE(iface) { \ + long dummyRTTI1; \ + long dummyRTTI2; \ + ibase##_IMETHODS \ + iface##_METHODS \ + }; +#define ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE 0,0, + +#else +#define ICOM_DEFINE(iface,ibase) \ + typedef struct ICOM_VTABLE(iface) ICOM_VTABLE(iface); \ + struct iface { \ + const ICOM_VFIELD(iface); \ + }; \ + struct ICOM_VTABLE(iface) { \ + ibase##_IMETHODS \ + iface##_METHODS \ + }; +#define ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE +#endif /* ICOM_MSVTABLE_COMPAT */ + + +#define ICOM_THIS(impl,iface) impl* const This=(impl*)iface +#define ICOM_CTHIS(impl,iface) const impl* const This=(const impl*)iface + +#endif + + +/***************************************************************************** + * Predeclare the interfaces + */ +DEFINE_OLEGUID(IID_IClassFactory, 0x00000001L, 0, 0); +typedef struct IClassFactory IClassFactory, *LPCLASSFACTORY; + +DEFINE_OLEGUID(IID_IMalloc, 0x00000002L, 0, 0); +typedef struct IMalloc IMalloc,*LPMALLOC; + +DEFINE_OLEGUID(IID_IUnknown, 0x00000000L, 0, 0); +typedef struct IUnknown IUnknown, *LPUNKNOWN; + + +/***************************************************************************** + * IUnknown interface + */ +#define ICOM_INTERFACE IUnknown +#define IUnknown_IMETHODS \ + ICOM_METHOD2(HRESULT,QueryInterface,REFIID,riid, LPVOID*,ppvObj) \ + ICOM_METHOD (ULONG,AddRef) \ + ICOM_METHOD (ULONG,Release) +#ifdef ICOM_CINTERFACE +typedef struct ICOM_VTABLE(IUnknown) ICOM_VTABLE(IUnknown); +struct IUnknown { + ICOM_VFIELD(IUnknown); +#if defined(ICOM_USE_COM_INTERFACE_ATTRIBUTE) +} __attribute__ ((com_interface)); +#else +}; +#endif /* ICOM_US_COM_INTERFACE_ATTRIBUTE */ + +struct ICOM_VTABLE(IUnknown) { +#ifdef ICOM_MSVTABLE_COMPAT + long dummyRTTI1; + long dummyRTTI2; +#endif /* ICOM_MSVTABLE_COMPAT */ + +#else /* ICOM_CINTERFACE */ +struct IUnknown { + +#endif /* ICOM_CINTERFACE */ + + ICOM_METHOD2(HRESULT,QueryInterface,REFIID,riid, LPVOID*,ppvObj) + ICOM_METHOD (ULONG,AddRef) + ICOM_METHOD (ULONG,Release) +#if defined(ICOM_USE_COM_INTERFACE_ATTRIBUTE) +} __attribute__ ((com_interface)); +#else +}; +#endif /* ICOM_US_COM_INTERFACE_ATTRIBUTE */ + +#undef ICOM_INTERFACE + +/*** IUnknown methods ***/ +#define IUnknown_QueryInterface(p,a,b) ICOM_CALL2(QueryInterface,p,a,b) +#define IUnknown_AddRef(p) ICOM_CALL (AddRef,p) +#define IUnknown_Release(p) ICOM_CALL (Release,p) + +/***************************************************************************** + * IClassFactory interface + */ +#define ICOM_INTERFACE IClassFactory +#define IClassFactory_METHODS \ + ICOM_METHOD3(HRESULT,CreateInstance, LPUNKNOWN,pUnkOuter, REFIID,riid, LPVOID*,ppvObject) \ + ICOM_METHOD1(HRESULT,LockServer, BOOL,fLock) +#define IClassFactory_IMETHODS \ + IUnknown_IMETHODS \ + IClassFactory_METHODS +ICOM_DEFINE(IClassFactory,IUnknown) +#undef ICOM_INTERFACE + +/*** IUnknown methods ***/ +#define IClassFactory_QueryInterface(p,a,b) ICOM_CALL2(QueryInterface,p,a,b) +#define IClassFactory_AddRef(p) ICOM_CALL (AddRef,p) +#define IClassFactory_Release(p) ICOM_CALL (Release,p) +/*** IClassFactory methods ***/ +#define IClassFactory_CreateInstance(p,a,b,c) ICOM_CALL3(CreateInstance,p,a,b,c) +#define IClassFactory_LockServer(p,a) ICOM_CALL1(LockServer,p,a) + + +/***************************************************************************** + * IMalloc interface + */ +#define ICOM_INTERFACE IMalloc +#define IMalloc_METHODS \ + ICOM_METHOD1 (LPVOID,Alloc, DWORD,cb) \ + ICOM_METHOD2 (LPVOID,Realloc, LPVOID,pv, DWORD,cb) \ + ICOM_VMETHOD1( Free, LPVOID,pv) \ + ICOM_METHOD1(DWORD, GetSize, LPVOID,pv) \ + ICOM_METHOD1(INT, DidAlloc, LPVOID,pv) \ + ICOM_METHOD (VOID, HeapMinimize) +#define IMalloc_IMETHODS \ + IUnknown_IMETHODS \ + IMalloc_METHODS +ICOM_DEFINE(IMalloc,IUnknown) +#undef ICOM_INTERFACE + +/*** IUnknown methods ***/ +#define IMalloc_QueryInterface(p,a,b) ICOM_CALL2(QueryInterface,p,a,b) +#define IMalloc_AddRef(p) ICOM_CALL (AddRef,p) +#define IMalloc_Release(p) ICOM_CALL (Release,p) +/*** IMalloc32 methods ***/ +#define IMalloc_Alloc(p,a) ICOM_CALL1(Alloc,p,a) +#define IMalloc_Realloc(p,a,b) ICOM_CALL2(Realloc,p,a,b) +#define IMalloc_Free(p,a) ICOM_CALL1(Free,p,a) +#define IMalloc_GetSize(p,a) ICOM_CALL1(GetSize,p,a) +#define IMalloc_DidAlloc(p,a) ICOM_CALL1(DidAlloc,p,a) +#define IMalloc_HeapMinimize(p) ICOM_CALL (HeapMinimize,p) + + +HRESULT WINAPI CoGetMalloc(DWORD dwMemContext,LPMALLOC* lpMalloc); + +LPVOID WINAPI CoTaskMemAlloc(ULONG size); + +void WINAPI CoTaskMemFree(LPVOID ptr); + +/* FIXME: unimplemented */ +LPVOID WINAPI CoTaskMemRealloc(LPVOID ptr, ULONG size); + + +/***************************************************************************** + * Additional API + */ + +HRESULT WINAPI CoCreateGuid(GUID* pguid); + +HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree); + +void WINAPI CoFreeAllLibraries(void); + +void WINAPI CoFreeLibrary(HINSTANCE hLibrary); + +void WINAPI CoFreeUnusedLibraries(void); + +HRESULT WINAPI CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID iid, LPVOID *ppv); + +HRESULT WINAPI CoGetClassObject(REFCLSID rclsid, DWORD dwClsContext, LPVOID pvReserved, REFIID iid, LPVOID *ppv); + +HRESULT WINAPI CoInitialize(LPVOID lpReserved); +HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit); + +void WINAPI CoUninitialize(void); + +typedef enum tagCOINIT +{ + COINIT_APARTMENTTHREADED = 0x2, /* Apartment model */ + COINIT_MULTITHREADED = 0x0, /* OLE calls objects on any thread */ + COINIT_DISABLE_OLE1DDE = 0x4, /* Don't use DDE for Ole1 support */ + COINIT_SPEED_OVER_MEMORY = 0x8 /* Trade memory for speed */ +} COINIT; + + +/* FIXME: not implemented */ +BOOL WINAPI CoIsOle1Class(REFCLSID rclsid); + +HRESULT WINAPI CoLockObjectExternal(LPUNKNOWN pUnk, BOOL fLock, BOOL fLastUnlockReleases); + +/* class registration flags; passed to CoRegisterClassObject */ +typedef enum tagREGCLS +{ + REGCLS_SINGLEUSE = 0, + REGCLS_MULTIPLEUSE = 1, + REGCLS_MULTI_SEPARATE = 2, + REGCLS_SUSPENDED = 4 +} REGCLS; + +HRESULT WINAPI CoResumeClassObjects (void); +HRESULT WINAPI CoRegisterClassObject(REFCLSID rclsid,LPUNKNOWN pUnk,DWORD dwClsContext,DWORD flags,LPDWORD lpdwRegister); + +HRESULT WINAPI CoRevokeClassObject(DWORD dwRegister); + +/***************************************************************************** + * COM Server dll - exports + */ +HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID * ppv); +HRESULT WINAPI DllCanUnloadNow(void); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __WINE_WINE_OBJ_BASE_H */ diff --git a/complus/wtypes.h b/complus/wtypes.h new file mode 100644 index 00000000..bff3f301 --- /dev/null +++ b/complus/wtypes.h @@ -0,0 +1,272 @@ +/* wtypes.h - Defines the basic types used by COM interfaces. + + Copyright (c) 1993-2000 the Wine project authors (see the file WINE-AUTHORS + for a complete list) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __WINE_WTYPES_H +#define __WINE_WTYPES_H + +#include "basetsd.h" +#include "guiddef.h" +/*#include "rpc.h"*/ +/*#include "rpcndr.h"*/ + +typedef WORD CLIPFORMAT, *LPCLIPFORMAT; + +/* FIXME: does not belong here */ +typedef CHAR OLECHAR16; +typedef LPSTR LPOLESTR16; +typedef LPCSTR LPCOLESTR16; +typedef OLECHAR16 *BSTR16; +typedef BSTR16 *LPBSTR16; +#define OLESTR16(x) x + +typedef WCHAR OLECHAR; +typedef LPWSTR LPOLESTR; +typedef LPCWSTR LPCOLESTR; +typedef OLECHAR *BSTR; +typedef BSTR *LPBSTR; + +/* +#ifndef _DWORDLONG_ +#define _DWORDLONG_ +typedef __uint64 DWORDLONG, *PDWORDLONG; +#endif + +#ifndef _ULONGLONG_ +#define _ULONGLONG_ +typedef __int64 LONGLONG, *PLONGLONG; +typedef __uint64 ULONGLONG, *PULONGLONG; +#endif +*/ + +#define OLESTR(x) L##x + +typedef enum tagDVASPECT +{ + DVASPECT_CONTENT = 1, + DVASPECT_THUMBNAIL = 2, + DVASPECT_ICON = 4, + DVASPECT_DOCPRINT = 8 +} DVASPECT; + +typedef enum tagSTGC +{ + STGC_DEFAULT = 0, + STGC_OVERWRITE = 1, + STGC_ONLYIFCURRENT = 2, + STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE = 4, + STGC_CONSOLIDATE = 8 +} STGC; + +typedef enum tagSTGMOVE +{ + STGMOVE_MOVE = 0, + STGMOVE_COPY = 1, + STGMOVE_SHALLOWCOPY = 2 +} STGMOVE; + + +typedef struct _COAUTHIDENTITY +{ + USHORT* User; + ULONG UserLength; + USHORT* Domain; + ULONG DomainLength; + USHORT* Password; + ULONG PasswordLength; + ULONG Flags; +} COAUTHIDENTITY; + +typedef struct _COAUTHINFO +{ + DWORD dwAuthnSvc; + DWORD dwAuthzSvc; + LPWSTR pwszServerPrincName; + DWORD dwAuthnLevel; + DWORD dwImpersonationLevel; + COAUTHIDENTITY* pAuthIdentityData; + DWORD dwCapabilities; +} COAUTHINFO; + +typedef struct _COSERVERINFO +{ + DWORD dwReserved1; + LPWSTR pwszName; + COAUTHINFO* pAuthInfo; + DWORD dwReserved2; +} COSERVERINFO; + +typedef enum tagCLSCTX +{ + CLSCTX_INPROC_SERVER = 0x1, + CLSCTX_INPROC_HANDLER = 0x2, + CLSCTX_LOCAL_SERVER = 0x4, + CLSCTX_INPROC_SERVER16 = 0x8, + CLSCTX_REMOTE_SERVER = 0x10, + CLSCTX_INPROC_HANDLER16 = 0x20, + CLSCTX_INPROC_SERVERX86 = 0x40, + CLSCTX_INPROC_HANDLERX86 = 0x80, + CLSCTX_ESERVER_HANDLER = 0x100 +} CLSCTX; + +#define CLSCTX_INPROC (CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) +#define CLSCTX_ALL (CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER) +#define CLSCTX_SERVER (CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER) + +typedef enum tagMSHLFLAGS +{ + MSHLFLAGS_NORMAL = 0, + MSHLFLAGS_TABLESTRONG = 1, + MSHLFLAGS_TABLEWEAK = 2, + MSHLFLAGS_NOPING = 4 +} MSHLFLAGS; + +typedef enum tagMSHCTX +{ + MSHCTX_LOCAL = 0, + MSHCTX_NOSHAREDMEM = 1, + MSHCTX_DIFFERENTMACHINE = 2, + MSHCTX_INPROC = 3 +} MSHCTX; + +typedef unsigned short VARTYPE; + +typedef ULONG PROPID; + +/* +#ifndef _tagBLOB_DEFINED +#define _tagBLOB_DEFINED +#define _BLOB_DEFINED +#define _LPBLOB_DEFINED +typedef struct tagBLOB +{ + ULONG cbSize; + BYTE *pBlobData; +} BLOB, *LPBLOB; +#endif +*/ + +#ifndef _tagCY_DEFINED +#define _tagCY_DEFINED + +typedef union tagCY { + struct { +#ifdef BIG_ENDIAN + LONG Hi; + LONG Lo; +#else /* defined(BIG_ENDIAN) */ + ULONG Lo; + LONG Hi; +#endif /* defined(BIG_ENDIAN) */ + } DUMMYSTRUCTNAME; + LONGLONG int64; +} CY; + +#endif /* _tagCY_DEFINED */ + +/* + * 0 == FALSE and -1 == TRUE + */ +#define VARIANT_TRUE ((VARIANT_BOOL)0xFFFF) +#define VARIANT_FALSE ((VARIANT_BOOL)0x0000) +typedef short VARIANT_BOOL,_VARIANT_BOOL; + +typedef struct tagCLIPDATA +{ + ULONG cbSize; + long ulClipFmt; + BYTE *pClipData; +} CLIPDATA; + +/* Macro to calculate the size of the above pClipData */ +#define CBPCLIPDATA(clipdata) ( (clipdata).cbSize - sizeof((clipdata).ulClipFmt) ) + +typedef LONG SCODE; + +/* +#ifndef _FILETIME_ +#define _FILETIME_ +*/ +/* 64 bit number of 100 nanoseconds intervals since January 1, 1601 */ +/* +typedef struct +{ + DWORD dwLowDateTime; + DWORD dwHighDateTime; +} FILETIME, *LPFILETIME; +#endif +*/ + +#ifndef _SECURITY_DEFINED +#define _SECURITY_DEFINED + +/* +typedef struct { + BYTE Value[6]; +} SID_IDENTIFIER_AUTHORITY,*PSID_IDENTIFIER_AUTHORITY; + +typedef struct _SID { + BYTE Revision; + BYTE SubAuthorityCount; + SID_IDENTIFIER_AUTHORITY IdentifierAuthority; + DWORD SubAuthority[1]; +} SID,*PSID; +*/ +/* + * ACL + */ +/* +typedef struct _ACL { + BYTE AclRevision; + BYTE Sbz1; + WORD AclSize; + WORD AceCount; + WORD Sbz2; +} ACL, *PACL; + +typedef DWORD SECURITY_INFORMATION; +typedef WORD SECURITY_DESCRIPTOR_CONTROL, *PSECURITY_DESCRIPTOR_CONTROL; +typedef DWORD ACCESS_MASK, *PACCESS_MASK; + +typedef PVOID PGENERIC_MAPPING; +*/ +/* The security descriptor structure */ +/* +typedef struct { + BYTE Revision; + BYTE Sbz1; + SECURITY_DESCRIPTOR_CONTROL Control; + PSID Owner; + PSID Group; + PACL Sacl; + PACL Dacl; +} SECURITY_DESCRIPTOR, *PSECURITY_DESCRIPTOR; +*/ +#endif /* _SECURITY_DEFINED */ + +#ifndef _ROTFLAGS_DEFINED +#define _ROTFLAGS_DEFINED +#define ROTFLAGS_REGISTRATIONKEEPSALIVE 0x1 +#define ROTFLAGS_ALLOWANYCLIENT 0x2 +#endif /* !defined(_ROTFLAGS_DEFINED) */ + +#endif /* __WINE_WTYPES_H */ diff --git a/configure.in b/configure.in index ec98903f..41a8b18c 100644 --- a/configure.in +++ b/configure.in @@ -13,7 +13,7 @@ AM_MAINTAINER_MODE # AGE, set REVISION to 0. # 3. Interfaces removed (BAD, breaks upward compatibility): Increment # CURRENT, set AGE and REVISION to 0. -AM_INIT_AUTOMAKE(gpgme,0.1.1) +AM_INIT_AUTOMAKE(gpgme,0.1.2) LIBGPGME_LT_CURRENT=0 LIBGPGME_LT_AGE=0 LIBGPGME_LT_REVISION=3 @@ -24,6 +24,8 @@ AC_SUBST(LIBGPGME_LT_AGE) AC_SUBST(LIBGPGME_LT_REVISION) +AM_MAINTAINER_MODE + dnl dnl Checks for programs dnl @@ -47,7 +49,7 @@ case "${target}" in AC_DEFINE(HAVE_DRIVE_LETTERS) AC_DEFINE(HAVE_DOSISH_SYSTEM) GPG='c:\\gnupg\\gpg.exe' - component_system='COM+' + #component_system='COM+' ;; *) ;; diff --git a/gpgme/Makefile.am b/gpgme/Makefile.am index 6fe3bb1a..ec08ae6f 100644 --- a/gpgme/Makefile.am +++ b/gpgme/Makefile.am @@ -24,7 +24,7 @@ libgpgme_la_SOURCES = \ key.c key.h \ keylist.c \ rungpg.c rungpg.h status-table.h \ - io.h posix-io.c w32-io.c \ + syshdr.h io.h posix-io.c w32-io.c \ gpgme.c version.c errors.c diff --git a/gpgme/context.h b/gpgme/context.h index 324245a4..ba5a1b4a 100644 --- a/gpgme/context.h +++ b/gpgme/context.h @@ -69,7 +69,8 @@ struct gpgme_context_s { volatile int key_cond; /* something new is available */ struct key_queue_item_s *key_queue; - char *prompt_1; + GpgmePassphraseCb passphrase_cb; + void *passphrase_cb_value; }; diff --git a/gpgme/data.c b/gpgme/data.c index 94438f62..6581db4d 100644 --- a/gpgme/data.c +++ b/gpgme/data.c @@ -25,8 +25,7 @@ #include #include #include -#include - +#include "syshdr.h" #include "util.h" #include "context.h" diff --git a/gpgme/decrypt.c b/gpgme/decrypt.c index 0a2545f3..465101b2 100644 --- a/gpgme/decrypt.c +++ b/gpgme/decrypt.c @@ -33,7 +33,7 @@ struct decrypt_result_s { int no_passphrase; int okay; int failed; - + void *last_pw_handle; }; @@ -76,8 +76,6 @@ decrypt_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) case STATUS_NEED_PASSPHRASE: case STATUS_NEED_PASSPHRASE_SYM: fprintf (stderr, "need a passphrase ...\n" ); - _gpgme_set_prompt (ctx, 1, "Hey! We need your passphrase!"); - /* next thing gpg has to do is to read it from the passphrase-fd */ break; case STATUS_MISSING_PASSPHRASE: @@ -101,9 +99,44 @@ decrypt_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) } } +static const char * +command_handler ( void *opaque, GpgStatusCode code, const char *key ) +{ + GpgmeCtx c = opaque; + + if ( c->result_type == RESULT_TYPE_NONE ) { + if ( create_result_struct ( c ) ) { + c->out_of_core = 1; + return NULL; + } + } + + if ( !code ) { + /* We have been called for cleanup */ + if ( c->passphrase_cb ) { + /* Fixme: take the key in account */ + c->passphrase_cb (c->passphrase_cb_value, 0, + &c->result.decrypt->last_pw_handle ); + } + + return NULL; + } + + if ( !key || !c->passphrase_cb ) + return NULL; + + if ( code == STATUS_GET_HIDDEN && !strcmp (key, "passphrase.enter") ) { + return c->passphrase_cb (c->passphrase_cb_value, + "Hey, Mr. Hoover wants your passphrase!", + &c->result.decrypt->last_pw_handle ); + } + + return NULL; +} + GpgmeError -gpgme_op_decrypt_start ( GpgmeCtx c, GpgmeData passphrase, +gpgme_op_decrypt_start ( GpgmeCtx c, GpgmeData ciph, GpgmeData plain ) { int rc = 0; @@ -124,16 +157,16 @@ gpgme_op_decrypt_start ( GpgmeCtx c, GpgmeData passphrase, goto leave; _gpgme_gpg_set_status_handler ( c->gpg, decrypt_status_handler, c ); + if (c->passphrase_cb) { + rc = _gpgme_gpg_set_command_handler ( c->gpg, command_handler, c ); + if (rc) + goto leave; + } /* build the commandline */ _gpgme_gpg_add_arg ( c->gpg, "--decrypt" ); for ( i=0; i < c->verbosity; i++ ) _gpgme_gpg_add_arg ( c->gpg, "--verbose" ); - if (passphrase) { - _gpgme_gpg_add_arg (c->gpg, "--passphrase-fd" ); - _gpgme_gpg_add_data (c->gpg, passphrase, -2 ); - } - /* Check the supplied data */ if ( !ciph || gpgme_data_get_type (ciph) == GPGME_DATA_TYPE_NONE ) { @@ -169,7 +202,6 @@ gpgme_op_decrypt_start ( GpgmeCtx c, GpgmeData passphrase, /** * gpgme_op_decrypt: * @c: The context - * @passphrase: A data object with the passphrase or NULL. * @in: ciphertext input * @out: plaintext output * @@ -180,10 +212,10 @@ gpgme_op_decrypt_start ( GpgmeCtx c, GpgmeData passphrase, * Return value: 0 on success or an errorcode. **/ GpgmeError -gpgme_op_decrypt ( GpgmeCtx c, GpgmeData passphrase, +gpgme_op_decrypt ( GpgmeCtx c, GpgmeData in, GpgmeData out ) { - GpgmeError err = gpgme_op_decrypt_start ( c, passphrase, in, out ); + GpgmeError err = gpgme_op_decrypt_start ( c, in, out ); if ( !err ) { gpgme_wait (c, 1); if ( c->result_type != RESULT_TYPE_DECRYPT ) diff --git a/gpgme/gpgme.c b/gpgme/gpgme.c index d6b189ce..ad74e109 100644 --- a/gpgme/gpgme.c +++ b/gpgme/gpgme.c @@ -52,6 +52,7 @@ gpgme_new (GpgmeCtx *r_ctx) c->verbosity = 1; c->use_armor = 1; /* fixme: reset this to 0 */ *r_ctx = c; + return 0; } @@ -70,7 +71,6 @@ gpgme_release ( GpgmeCtx c ) _gpgme_key_release ( c->tmp_key ); gpgme_data_release ( c->notation ); /* fixme: release the key_queue */ - xfree (c->prompt_1); xfree (c); } @@ -147,36 +147,41 @@ gpgme_set_textmode ( GpgmeCtx c, int yes ) c->use_textmode = yes; } -/* - * The only which currently allowed is 1 - */ +/** + * gpgme_set_passphrase_cb: + * @c: the context + * @cb: A callback function + * @cb_value: The value passed to the callback function + * + * This function sets a callback function to be used to pass a passphrase + * to gpg. The preferred way to handle this is by using the gpg-agent, but + * because that beast is not ready for real use, you can use this passphrase + * thing. + * + * The callback function is defined as: + * + * typedef const char *(*GpgmePassphraseCb)(void*cb_value, + * const char *desc, + * void *r_hd); + * + * and called whenever gpgme needs a passphrase. DESC will have a nice + * text, to be used to prompt for the passphrase and R_HD is just a parameter + * to be used by the callback it self. Becuase the callback returns a const + * string, the callback might want to know when it can releae resources + * assocated with that returned string; gpgme helps here by calling this + * passphrase callback with an DESC of %NULL as soon as it does not need + * the returned string anymore. The callback function might then choose + * to release resources depending on R_HD. + * + **/ void -_gpgme_set_prompt ( GpgmeCtx c, int which, const char *text ) +gpgme_set_passphrase_cb ( GpgmeCtx c, GpgmePassphraseCb cb, void *cb_value ) { - assert ( which == 1 ); - - xfree (c->prompt_1); c->prompt_1 = NULL; - if (text) { - c->prompt_1 = xtrystrdup (text); - if ( !c->prompt_1 ) - c->out_of_core = 1; - } -} - -const char * -gpgme_get_prompt ( GpgmeCtx c, int which ) -{ - if ( which != 1 ) - return NULL; - return c->prompt_1; + c->passphrase_cb = cb; + c->passphrase_cb_value = cb_value; } - - - - - diff --git a/gpgme/gpgme.h b/gpgme/gpgme.h index b9509cc4..57066e54 100644 --- a/gpgme/gpgme.h +++ b/gpgme/gpgme.h @@ -34,7 +34,7 @@ extern "C" { * let autoconf (using the AM_PATH_GPGME macro) check that this * header matches the installed library. * Warning: Do not edit the next line. configure will do that for you! */ -#define GPGME_VERSION "0.1.1" +#define GPGME_VERSION "0.1.2" @@ -92,6 +92,15 @@ typedef enum { GPGME_SIG_STAT_ERROR = 5 } GpgmeSigStat; +typedef enum { + GPGME_SIG_MODE_NORMAL = 0, + GPGME_SIG_MODE_DETACH = 1, + GPGME_SIG_MODE_CLEAR = 2 +} GpgmeSigMode; + + +typedef const char *(*GpgmePassphraseCb)(void*, const char *desc, void *r_hd); + /* Context management */ GpgmeError gpgme_new (GpgmeCtx *r_ctx); @@ -101,6 +110,8 @@ GpgmeCtx gpgme_wait ( GpgmeCtx c, int hang ); char *gpgme_get_notation ( GpgmeCtx c ); void gpgme_set_armor ( GpgmeCtx c, int yes ); void gpgme_set_textmode ( GpgmeCtx c, int yes ); +void gpgme_set_passphrase_cb ( GpgmeCtx c, + GpgmePassphraseCb cb, void *cb_value ); @@ -138,9 +149,11 @@ char *gpgme_key_get_as_xml ( GpgmeKey key ); GpgmeError gpgme_op_encrypt_start ( GpgmeCtx c, GpgmeRecipients recp, GpgmeData in, GpgmeData out ); -GpgmeError gpgme_op_decrypt_start ( GpgmeCtx c, GpgmeData passphrase, +GpgmeError gpgme_op_decrypt_start ( GpgmeCtx c, GpgmeData ciph, GpgmeData plain ); -GpgmeError gpgme_op_sign_start ( GpgmeCtx c, GpgmeData in, GpgmeData out ); +GpgmeError gpgme_op_sign_start ( GpgmeCtx c, + GpgmeData in, GpgmeData out, + GpgmeSigMode mode ); GpgmeError gpgme_op_verify_start ( GpgmeCtx c, GpgmeData sig, GpgmeData text ); @@ -154,9 +167,10 @@ GpgmeError gpgme_op_keylist_next ( GpgmeCtx c, GpgmeKey *r_key ); /* Convenience functions for normal usage */ GpgmeError gpgme_op_encrypt ( GpgmeCtx c, GpgmeRecipients recp, GpgmeData in, GpgmeData out ); -GpgmeError gpgme_op_decrypt ( GpgmeCtx c, GpgmeData passphrase, +GpgmeError gpgme_op_decrypt ( GpgmeCtx c, GpgmeData in, GpgmeData out ); -GpgmeError gpgme_op_sign ( GpgmeCtx c, GpgmeData in, GpgmeData out ); +GpgmeError gpgme_op_sign ( GpgmeCtx c, GpgmeData in, GpgmeData out, + GpgmeSigMode mode); GpgmeError gpgme_op_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text, GpgmeSigStat *r_status ); diff --git a/gpgme/io.h b/gpgme/io.h index 0ae58a2b..14c09476 100644 --- a/gpgme/io.h +++ b/gpgme/io.h @@ -35,6 +35,7 @@ struct io_select_fd_s { int for_read; int for_write; int signaled; + int frozen; void *opaque; }; diff --git a/gpgme/ops.h b/gpgme/ops.h index ba382a9f..0019b82e 100644 --- a/gpgme/ops.h +++ b/gpgme/ops.h @@ -25,11 +25,12 @@ /*-- gpgme.c --*/ void _gpgme_release_result ( GpgmeCtx c ); -void _gpgme_set_prompt ( GpgmeCtx c, int which, const char *text ); /*-- wait.c --*/ GpgmeCtx _gpgme_wait_on_condition ( GpgmeCtx c, int hang, volatile int *cond ); +void _gpgme_freeze_fd ( int fd ); +void _gpgme_thaw_fd ( int fd ); /*-- recipient.c --*/ diff --git a/gpgme/posix-io.c b/gpgme/posix-io.c index dede3f90..740e98f5 100644 --- a/gpgme/posix-io.c +++ b/gpgme/posix-io.c @@ -28,10 +28,10 @@ #include #include #include -#include #include #include #include +#include "syshdr.h" #include "io.h" @@ -100,8 +100,24 @@ _gpgme_io_spawn ( const char *path, char **argv, struct spawn_fd_item_s *fd_child_list, struct spawn_fd_item_s *fd_parent_list ) { + static volatile int fixed_signals; pid_t pid; int i; + + if ( !fixed_signals ) { + struct sigaction act; + + sigaction( SIGPIPE, NULL, &act ); + if( act.sa_handler == SIG_DFL ) { + act.sa_handler = SIG_IGN; + sigemptyset( &act.sa_mask ); + act.sa_flags = 0; + sigaction( SIGPIPE, &act, NULL); + } + fixed_signals = 1; + /* fixme: This is not really MT safe */ + } + pid = fork (); if (pid == -1) @@ -134,7 +150,7 @@ _gpgme_io_spawn ( const char *path, char **argv, } if( !duped_stdin || !duped_stderr ) { - int fd = open ( "/dev/null", O_RDONLY ); + int fd = open ( "/dev/null", O_RDWR ); if ( fd == -1 ) { fprintf (stderr,"can't open `/dev/null': %s\n", strerror (errno) ); diff --git a/gpgme/rungpg.c b/gpgme/rungpg.c index 1a8f6ae2..dde29a37 100644 --- a/gpgme/rungpg.c +++ b/gpgme/rungpg.c @@ -26,9 +26,9 @@ #include #include #include -#include #include #include +#include "unistd.h" #include "gpgme.h" #include "util.h" @@ -94,6 +94,26 @@ struct gpg_object_s { int running; int exit_status; int exit_signal; + + /* stuff needed for pipemode */ + struct { + int used; + int active; + GpgmeData sig; + GpgmeData text; + int stream_started; + } pm; + + /* stuff needed for interactive (command) mode */ + struct { + int used; + int fd; + GpgmeData cb_data; /* hack to get init the above fd later */ + GpgStatusCode code; /* last code */ + char *keyword; /* what has been requested (malloced) */ + GpgCommandHandler fnc; + void *fnc_value; + } cmd; }; static void kill_gpg ( GpgObject gpg ); @@ -109,6 +129,11 @@ static GpgmeError read_status ( GpgObject gpg ); static int gpg_colon_line_handler ( void *opaque, int pid, int fd ); static GpgmeError read_colon_line ( GpgObject gpg ); +static int pipemode_cb ( void *opaque, + char *buffer, size_t length, size_t *nread ); +static int command_cb ( void *opaque, + char *buffer, size_t length, size_t *nread ); + GpgmeError @@ -128,6 +153,7 @@ _gpgme_gpg_new ( GpgObject *r_gpg ) gpg->status.fd[1] = -1; gpg->colon.fd[0] = -1; gpg->colon.fd[1] = -1; + gpg->cmd.fd = -1; /* allocate the read buffer for the status pipe */ gpg->status.bufsize = 1024; @@ -150,7 +176,6 @@ _gpgme_gpg_new ( GpgObject *r_gpg ) sprintf ( buf, "%d", gpg->status.fd[1]); _gpgme_gpg_add_arg ( gpg, buf ); } - _gpgme_gpg_add_arg ( gpg, "--batch" ); _gpgme_gpg_add_arg ( gpg, "--no-tty" ); @@ -164,6 +189,7 @@ _gpgme_gpg_new ( GpgObject *r_gpg ) return rc; } + void _gpgme_gpg_release ( GpgObject gpg ) { @@ -173,6 +199,8 @@ _gpgme_gpg_release ( GpgObject gpg ) xfree (gpg->colon.buffer); if ( gpg->argv ) free_argv (gpg->argv); + xfree (gpg->cmd.keyword); + #if 0 /* fixme: We need a way to communicate back closed fds, so that we * don't do it a second time. One way to do it is by using a global @@ -209,7 +237,13 @@ kill_gpg ( GpgObject gpg ) #endif } - +void +_gpgme_gpg_enable_pipemode ( GpgObject gpg ) +{ + gpg->pm.used = 1; + assert ( !gpg->pm.sig ); + assert ( !gpg->pm.text ); +} GpgmeError _gpgme_gpg_add_arg ( GpgObject gpg, const char *arg ) @@ -218,6 +252,10 @@ _gpgme_gpg_add_arg ( GpgObject gpg, const char *arg ) assert (gpg); assert (arg); + + if (gpg->pm.active) + return 0; + a = xtrymalloc ( sizeof *a + strlen (arg) ); if ( !a ) { gpg->arg_error = 1; @@ -239,6 +277,9 @@ _gpgme_gpg_add_data ( GpgObject gpg, GpgmeData data, int dup_to ) assert (gpg); assert (data); + if (gpg->pm.active) + return 0; + a = xtrymalloc ( sizeof *a - 1 ); if ( !a ) { gpg->arg_error = 1; @@ -259,6 +300,45 @@ _gpgme_gpg_add_data ( GpgObject gpg, GpgmeData data, int dup_to ) return 0; } +GpgmeError +_gpgme_gpg_add_pm_data ( GpgObject gpg, GpgmeData data, int what ) +{ + GpgmeError rc=0; + + assert ( gpg->pm.used ); + + if ( !what ) { + /* the signature */ + assert ( !gpg->pm.sig ); + gpg->pm.sig = data; + } + else if (what == 1) { + /* the signed data */ + assert ( !gpg->pm.text ); + gpg->pm.text = data; + } + else { + assert (0); + } + + if ( gpg->pm.sig && gpg->pm.text ) { + if ( !gpg->pm.active ) { + /* create the callback handler and connect it to stdin */ + GpgmeData tmp; + + rc = gpgme_data_new_with_read_cb ( &tmp, pipemode_cb, gpg ); + if (!rc ) + rc = _gpgme_gpg_add_data (gpg, tmp, 0); + } + if ( !rc ) { + /* here we can reset the handler stuff */ + gpg->pm.stream_started = 0; + } + } + + return rc; +} + /* * Note, that the status_handler is allowed to modifiy the args value */ @@ -267,6 +347,9 @@ _gpgme_gpg_set_status_handler ( GpgObject gpg, GpgStatusHandler fnc, void *fnc_value ) { assert (gpg); + if (gpg->pm.active) + return; + gpg->status.fnc = fnc; gpg->status.fnc_value = fnc_value; } @@ -277,6 +360,8 @@ _gpgme_gpg_set_colon_line_handler ( GpgObject gpg, GpgColonLineHandler fnc, void *fnc_value ) { assert (gpg); + if (gpg->pm.active) + return 0; gpg->colon.bufsize = 1024; gpg->colon.readpos = 0; @@ -295,6 +380,39 @@ _gpgme_gpg_set_colon_line_handler ( GpgObject gpg, } +/* + * The Fnc will be called to get a value for one of the commands with + * a key KEY. If the Code pssed to FNC is 0, the function may release + * resources associated with the returned value from another call. To + * match such a second call to a first call, the returned value from + * the first call is passed as keyword. + */ + +GpgmeError +_gpgme_gpg_set_command_handler ( GpgObject gpg, + GpgCommandHandler fnc, void *fnc_value ) +{ + GpgmeData tmp; + GpgmeError err; + + assert (gpg); + if (gpg->pm.active) + return 0; + + err = gpgme_data_new_with_read_cb ( &tmp, command_cb, gpg ); + if (err) + return err; + + _gpgme_gpg_add_arg ( gpg, "--command-fd" ); + _gpgme_gpg_add_data (gpg, tmp, -2); + gpg->cmd.cb_data = tmp; + gpg->cmd.fnc = fnc; + gpg->cmd.fnc_value = fnc_value; + gpg->cmd.used = 1; + return 0; +} + + static void free_argv ( char **argv ) { @@ -362,6 +480,8 @@ build_argv ( GpgObject gpg ) argc++; if (use_agent) argc++; + if (!gpg->cmd.used) + argc++; argv = xtrycalloc ( argc+1, sizeof *argv ); if (!argv) @@ -398,6 +518,15 @@ build_argv ( GpgObject gpg ) } argc++; } + if ( !gpg->cmd.used ) { + argv[argc] = xtrystrdup ( "--batch" ); + if (!argv[argc]) { + xfree (fd_data_map); + free_argv (argv); + return mk_error (Out_Of_Core); + } + argc++; + } for ( a=gpg->arglist; a; a = a->next ) { if ( a->data ) { switch ( _gpgme_data_get_mode (a->data) ) { @@ -453,6 +582,13 @@ build_argv ( GpgObject gpg ) fd_data_map[datac].peer_fd = fds[0]; } } + + /* Hack to get hands on the fd later */ + if ( gpg->cmd.used && gpg->cmd.cb_data == a->data ) { + assert (gpg->cmd.fd == -1); + gpg->cmd.fd = fd_data_map[datac].fd; + } + fd_data_map[datac].data = a->data; fd_data_map[datac].dup_to = a->dup_to; if ( a->dup_to == -1 ) { @@ -501,6 +637,9 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque ) if ( gpg->arg_error ) return mk_error (Out_Of_Core); + if (gpg->pm.active) + return 0; + rc = build_argv ( gpg ); if ( rc ) return rc; @@ -570,6 +709,8 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque ) } gpg->pid = pid; + if (gpg->pm.used) + gpg->pm.active = 1; /*_gpgme_register_term_handler ( closure, closure_value, pid );*/ @@ -610,8 +751,11 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque ) } } - /* fixme: check what data we can release here */ + if ( gpg->cmd.used ) + _gpgme_freeze_fd ( gpg->cmd.fd ); + /* fixme: check what data we can release here */ + gpg->running = 1; return 0; } @@ -699,7 +843,7 @@ write_cb_data ( GpgmeData dh, int fd ) return 1; } - nwritten = _gpgme_io_write ( fd, dh->data+dh->readpos, nbytes ); + nwritten = _gpgme_io_write ( fd, buffer, nbytes ); if (nwritten == -1 && errno == EAGAIN ) return 0; if ( nwritten < 1 ) { @@ -710,6 +854,7 @@ write_cb_data ( GpgmeData dh, int fd ) } if ( nwritten < nbytes ) { + /* ugly, ugly: It does currently only for for MEM type data */ if ( _gpgme_data_unread (dh, buffer + nwritten, nbytes - nwritten ) ) fprintf (stderr, "wite_cb_data: unread of %d bytes failed\n", nbytes - nwritten ); @@ -819,8 +964,7 @@ read_status ( GpgObject gpg ) *p = 0; fprintf (stderr, "read_status: `%s'\n", buffer); if (!strncmp (buffer, "[GNUPG:] ", 9 ) - && buffer[9] >= 'A' && buffer[9] <= 'Z' - && gpg->status.fnc ) { + && buffer[9] >= 'A' && buffer[9] <= 'Z' ) { struct status_table_s t, *r; char *rest; @@ -835,8 +979,30 @@ read_status ( GpgObject gpg ) r = bsearch ( &t, status_table, DIM(status_table)-1, sizeof t, status_cmp ); if ( r ) { - gpg->status.fnc ( gpg->status.fnc_value, - r->code, rest); + if ( gpg->cmd.used + && ( r->code == STATUS_GET_BOOL + || r->code == STATUS_GET_LINE + || r->code == STATUS_GET_HIDDEN )) { + gpg->cmd.code = r->code; + xfree (gpg->cmd.keyword); + gpg->cmd.keyword = xtrystrdup (rest); + if ( !gpg->cmd.keyword ) + return mk_error (Out_Of_Core); + /* this should be the last thing we have received + * and the next thing will be that the command + * handler does it action */ + if ( nread > 1 ) + fprintf (stderr, "** ERROR, unxpected data in" + " read_status\n" ); + _gpgme_thaw_fd (gpg->cmd.fd); + } + else if ( gpg->status.fnc ) { + gpg->status.fnc ( gpg->status.fnc_value, + r->code, rest); + } + } + if ( r->code == STATUS_END_STREAM ) { + /* _gpgme_freeze_fd ( ? );*/ } } /* To reuse the buffer for the next line we have to @@ -957,3 +1123,140 @@ read_colon_line ( GpgObject gpg ) return 0; } +static GpgmeError +pipemode_copy (char *buffer, size_t length, size_t *nread, GpgmeData data ) +{ + GpgmeError err; + int nbytes; + char tmp[1000], *s, *d; + + /* we can optimize this whole thing but for now we just + * return after each escape character */ + if (length > 990) + length = 990; + + err = gpgme_data_read ( data, tmp, length, &nbytes ); + if (err) + return err; + for (s=tmp, d=buffer; nbytes; s++, nbytes--) { + *d++ = *s; + if (*s == '@' ) { + *d++ = '@'; + break; + } + } + *nread = d - buffer; + return 0; +} + + +static int +pipemode_cb ( void *opaque, char *buffer, size_t length, size_t *nread ) +{ + GpgObject gpg = opaque; + GpgmeError err; + + if ( !buffer || !length || !nread ) + return 0; /* those values are reserved for extensions */ + *nread =0; + if ( !gpg->pm.stream_started ) { + assert (length > 4 ); + strcpy (buffer, "@<@B" ); + *nread = 4; + gpg->pm.stream_started = 1; + } + else if ( gpg->pm.sig ) { + err = pipemode_copy ( buffer, length, nread, gpg->pm.sig ); + if ( err == GPGME_EOF ) { + gpg->pm.sig = NULL; + assert (length > 4 ); + strcpy (buffer, "@t" ); + *nread = 2; + } + else if (err) { + fprintf (stderr, "** pipemode_cb: copy sig failed: %s\n", + gpgme_strerror (err) ); + return -1; + } + } + else if ( gpg->pm.text ) { + err = pipemode_copy ( buffer, length, nread, gpg->pm.text ); + if ( err == GPGME_EOF ) { + gpg->pm.text = NULL; + assert (length > 4 ); + strcpy (buffer, "@.@>" ); + *nread = 4; + } + else if (err) { + fprintf (stderr, "** pipemode_cb: copy data failed: %s\n", + gpgme_strerror (err) ); + return -1; + } + } + else { + return 0; /* eof */ + } + + return 0; +} + + +/* + * Here we handle --command-fd. This works closely together with + * the status handler. + */ + +static int +command_cb ( void *opaque, char *buffer, size_t length, size_t *nread ) +{ + GpgObject gpg = opaque; + const char *value; + int value_len; + + fprintf (stderr, "** command_cb: enter\n"); + assert (gpg->cmd.used); + if ( !buffer || !length || !nread ) + return 0; /* those values are reserved for extensions */ + *nread =0; + if ( !gpg->cmd.code ) { + fprintf (stderr, "** command_cb: no code\n"); + return -1; + } + + if ( !gpg->cmd.fnc ) { + fprintf (stderr, "** command_cb: no user cb\n"); + return -1; + } + + value = gpg->cmd.fnc ( gpg->cmd.fnc_value, + gpg->cmd.code, gpg->cmd.keyword ); + if ( !value ) { + fprintf (stderr, "** command_cb: no data from user cb\n"); + gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); + return -1; + } + + value_len = strlen (value); + if ( value_len+1 > length ) { + fprintf (stderr, "** command_cb: too much data from user cb\n"); + gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); + return -1; + } + + memcpy ( buffer, value, value_len ); + if ( !value_len || (value_len && value[value_len-1] != '\n') ) + buffer[value_len++] = '\n'; + *nread = value_len; + + fprintf (stderr, "** command_cb: leave (wrote `%.*s')\n", + (int)*nread-1, buffer); + gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); + gpg->cmd.code = 0; + /* and sleep again until read_status will wake us up again */ + _gpgme_freeze_fd ( gpg->cmd.fd ); + return 0; +} + + + + diff --git a/gpgme/rungpg.h b/gpgme/rungpg.h index 3ab09040..0d7be621 100644 --- a/gpgme/rungpg.h +++ b/gpgme/rungpg.h @@ -81,22 +81,32 @@ typedef enum { STATUS_SESSION_KEY , STATUS_NOTATION_NAME , STATUS_NOTATION_DATA , - STATUS_POLICY_URL + STATUS_POLICY_URL , + STATUS_BEGIN_STREAM , + STATUS_END_STREAM } GpgStatusCode; typedef void (*GpgStatusHandler)( GpgmeCtx, GpgStatusCode code, char *args ); typedef void (*GpgColonLineHandler)( GpgmeCtx, char *line ); +typedef const char *(*GpgCommandHandler)(void*, GpgStatusCode code, + const char *keyword); + GpgmeError _gpgme_gpg_new ( GpgObject *r_gpg ); void _gpgme_gpg_release ( GpgObject gpg ); +void _gpgme_gpg_enable_pipemode ( GpgObject gpg ); GpgmeError _gpgme_gpg_add_arg ( GpgObject gpg, const char *arg ); GpgmeError _gpgme_gpg_add_data ( GpgObject gpg, GpgmeData data, int dup_to ); +GpgmeError _gpgme_gpg_add_pm_data ( GpgObject gpg, GpgmeData data, int what ); void _gpgme_gpg_set_status_handler ( GpgObject gpg, GpgStatusHandler fnc, void *fnc_value ); GpgmeError _gpgme_gpg_set_colon_line_handler ( GpgObject gpg, GpgColonLineHandler fnc, void *fnc_value ); +GpgmeError _gpgme_gpg_set_command_handler ( GpgObject gpg, + GpgCommandHandler fnc, + void *fnc_value ); GpgmeError _gpgme_gpg_spawn ( GpgObject gpg, void *opaque ); diff --git a/gpgme/sign.c b/gpgme/sign.c index 3274f118..11480e0a 100644 --- a/gpgme/sign.c +++ b/gpgme/sign.c @@ -32,6 +32,7 @@ struct sign_result_s { int no_passphrase; int okay; + void *last_pw_handle; }; @@ -84,10 +85,48 @@ sign_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) } } +static const char * +command_handler ( void *opaque, GpgStatusCode code, const char *key ) +{ + GpgmeCtx c = opaque; + + if ( c->result_type == RESULT_TYPE_NONE ) { + assert ( !c->result.sign ); + c->result.sign = xtrycalloc ( 1, sizeof *c->result.sign ); + if ( !c->result.sign ) { + c->out_of_core = 1; + return NULL; + } + c->result_type = RESULT_TYPE_SIGN; + } + + if ( !code ) { + /* We have been called for cleanup */ + if ( c->passphrase_cb ) { + /* Fixme: take the key in account */ + c->passphrase_cb (c->passphrase_cb_value, 0, + &c->result.sign->last_pw_handle ); + } + + return NULL; + } + + if ( !key || !c->passphrase_cb ) + return NULL; + + if ( code == STATUS_GET_HIDDEN && !strcmp (key, "passphrase.enter") ) { + return c->passphrase_cb (c->passphrase_cb_value, + "Please enter your Friedrich Willem!", + &c->result.sign->last_pw_handle ); + } + + return NULL; +} GpgmeError -gpgme_op_sign_start ( GpgmeCtx c, GpgmeData in, GpgmeData out ) +gpgme_op_sign_start ( GpgmeCtx c, GpgmeData in, GpgmeData out, + GpgmeSigMode mode ) { int rc = 0; int i; @@ -98,23 +137,39 @@ gpgme_op_sign_start ( GpgmeCtx c, GpgmeData in, GpgmeData out ) _gpgme_release_result (c); c->out_of_core = 0; - /* do some checks */ - assert ( !c->gpg ); + + if ( mode != GPGME_SIG_MODE_NORMAL + && mode != GPGME_SIG_MODE_DETACH + && mode != GPGME_SIG_MODE_CLEAR ) + return mk_error (Invalid_Value); /* create a process object */ + _gpgme_gpg_release (c->gpg); + c->gpg = NULL; rc = _gpgme_gpg_new ( &c->gpg ); if (rc) goto leave; _gpgme_gpg_set_status_handler ( c->gpg, sign_status_handler, c ); + if (c->passphrase_cb) { + rc = _gpgme_gpg_set_command_handler ( c->gpg, command_handler, c ); + if (rc) + goto leave; + } /* build the commandline */ - _gpgme_gpg_add_arg ( c->gpg, "--sign" ); - _gpgme_gpg_add_arg ( c->gpg, "--detach" ); - if ( c->use_armor ) - _gpgme_gpg_add_arg ( c->gpg, "--armor" ); - if ( c->use_textmode ) - _gpgme_gpg_add_arg ( c->gpg, "--textmode" ); + if ( mode == GPGME_SIG_MODE_CLEAR ) { + _gpgme_gpg_add_arg ( c->gpg, "--clearsign" ); + } + else { + _gpgme_gpg_add_arg ( c->gpg, "--sign" ); + if ( mode == GPGME_SIG_MODE_DETACH ) + _gpgme_gpg_add_arg ( c->gpg, "--detach" ); + if ( c->use_armor ) + _gpgme_gpg_add_arg ( c->gpg, "--armor" ); + if ( c->use_textmode ) + _gpgme_gpg_add_arg ( c->gpg, "--textmode" ); + } for ( i=0; i < c->verbosity; i++ ) _gpgme_gpg_add_arg ( c->gpg, "--verbose" ); @@ -151,17 +206,26 @@ gpgme_op_sign_start ( GpgmeCtx c, GpgmeData in, GpgmeData out ) * @c: The context * @in: Data to be signed * @out: Detached signature + * @mode: Signature creation mode * * Create a detached signature for @in and write it to @out. * The data will be signed using either the default key or the ones * defined through @c. + * The defined modes for signature create are: + * + * GPGME_SIG_MODE_NORMAL (or 0) + * GPGME_SIG_MODE_DETACH + * GPGME_SIG_MODE_CLEAR + * + * Note that the settings done by gpgme_set_armor() and gpgme_set_textmode() + * are ignore for @mode GPGME_SIG_MODE_CLEAR. * * Return value: 0 on success or an error code. **/ GpgmeError -gpgme_op_sign ( GpgmeCtx c, GpgmeData in, GpgmeData out ) +gpgme_op_sign ( GpgmeCtx c, GpgmeData in, GpgmeData out, GpgmeSigMode mode ) { - GpgmeError err = gpgme_op_sign_start ( c, in, out ); + GpgmeError err = gpgme_op_sign_start ( c, in, out, mode ); if ( !err ) { gpgme_wait (c, 1); if ( c->result_type != RESULT_TYPE_SIGN ) diff --git a/gpgme/status-table.h b/gpgme/status-table.h index ce427100..4922d4ec 100644 --- a/gpgme/status-table.h +++ b/gpgme/status-table.h @@ -15,12 +15,14 @@ static struct status_table_s status_table[] = { "BAD_PASSPHRASE", STATUS_BAD_PASSPHRASE }, { "BEGIN_DECRYPTION", STATUS_BEGIN_DECRYPTION }, { "BEGIN_ENCRYPTION", STATUS_BEGIN_ENCRYPTION }, + { "BEGIN_STREAM", STATUS_BEGIN_STREAM }, { "DECRYPTION_FAILED", STATUS_DECRYPTION_FAILED }, { "DECRYPTION_OKAY", STATUS_DECRYPTION_OKAY }, { "DELETE_PROBLEM", STATUS_DELETE_PROBLEM }, { "ENC_TO", STATUS_ENC_TO }, { "END_DECRYPTION", STATUS_END_DECRYPTION }, { "END_ENCRYPTION", STATUS_END_ENCRYPTION }, + { "END_STREAM", STATUS_END_STREAM }, { "ENTER", STATUS_ENTER }, { "ERRMDC", STATUS_ERRMDC }, { "ERRSIG", STATUS_ERRSIG }, diff --git a/gpgme/verify.c b/gpgme/verify.c index 4c3e61ba..fad5cd9b 100644 --- a/gpgme/verify.c +++ b/gpgme/verify.c @@ -124,6 +124,9 @@ verify_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) add_notation ( ctx, code, args ); break; + case STATUS_END_STREAM: + break; + default: /* ignore all other codes */ fprintf (stderr, "verify_status: code=%d not handled\n", code ); @@ -138,29 +141,30 @@ gpgme_op_verify_start ( GpgmeCtx c, GpgmeData sig, GpgmeData text ) { int rc = 0; int i; + int pipemode = 0 /*!!text*/; /* use pipemode for detached sigs */ fail_on_pending_request( c ); c->pending = 1; _gpgme_release_result (c); c->out_of_core = 0; - - /* create a process object. - * To optimize this, we should reuse an existing one and - * run gpg in the new --pipemode (I started with this but it is - * not yet finished) */ - if ( c->gpg ) { - _gpgme_gpg_release ( c->gpg ); + + if ( !pipemode ) { + _gpgme_gpg_release ( c->gpg ); c->gpg = NULL; } - rc = _gpgme_gpg_new ( &c->gpg ); + + if ( !c->gpg ) + rc = _gpgme_gpg_new ( &c->gpg ); if (rc) goto leave; + if (pipemode) + _gpgme_gpg_enable_pipemode ( c->gpg ); _gpgme_gpg_set_status_handler ( c->gpg, verify_status_handler, c ); /* build the commandline */ - _gpgme_gpg_add_arg ( c->gpg, "--verify" ); + _gpgme_gpg_add_arg ( c->gpg, pipemode?"--pipemode" : "--verify" ); for ( i=0; i < c->verbosity; i++ ) _gpgme_gpg_add_arg ( c->gpg, "--verbose" ); @@ -178,10 +182,16 @@ gpgme_op_verify_start ( GpgmeCtx c, GpgmeData sig, GpgmeData text ) _gpgme_data_set_mode (text, GPGME_DATA_MODE_OUT ); /* Tell the gpg object about the data */ _gpgme_gpg_add_arg ( c->gpg, "--" ); - _gpgme_gpg_add_data ( c->gpg, sig, -1 ); - if (text) { - _gpgme_gpg_add_arg ( c->gpg, "-" ); - _gpgme_gpg_add_data ( c->gpg, text, 0 ); + if (pipemode) { + _gpgme_gpg_add_pm_data ( c->gpg, sig, 0 ); + _gpgme_gpg_add_pm_data ( c->gpg, text, 1 ); + } + else { + _gpgme_gpg_add_data ( c->gpg, sig, -1 ); + if (text) { + _gpgme_gpg_add_arg ( c->gpg, "-" ); + _gpgme_gpg_add_data ( c->gpg, text, 0 ); + } } /* and kick off the process */ @@ -214,6 +224,7 @@ gpgme_op_verify_start ( GpgmeCtx c, GpgmeData sig, GpgmeData text ) * missing key * GPGME_SIG_STAT_NOSIG: This is not a signature * GPGME_SIG_STAT_ERROR: Due to some other error the check could not be done. + * FIXME: What do we return if only some o the signatures ae valid? * * Return value: 0 on success or an errorcode if something not related to * the signature itself did go wrong. diff --git a/gpgme/w32-io.c b/gpgme/w32-io.c index 21d4b1fd..fe5e52d7 100644 --- a/gpgme/w32-io.c +++ b/gpgme/w32-io.c @@ -28,10 +28,10 @@ #include #include #include -#include #include #include #include +#include "syshdr.h" #include "util.h" #include "io.h" @@ -209,6 +209,7 @@ _gpgme_io_spawn ( const char *path, char **argv, int duped_stdin = 0; int duped_stderr = 0; HANDLE hnul = INVALID_HANDLE_VALUE; + int debug_me = !!getenv ("GPGME_DEBUG"); memset (&sec_attr, 0, sizeof sec_attr ); sec_attr.nLength = sizeof sec_attr; @@ -220,7 +221,8 @@ _gpgme_io_spawn ( const char *path, char **argv, memset (&si, 0, sizeof si); si.cb = sizeof (si); - si.dwFlags = STARTF_USESTDHANDLES; + si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + si.wShowWindow = debug_me? SW_SHOW : SW_HIDE; si.hStdInput = GetStdHandle (STD_INPUT_HANDLE); si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE); si.hStdError = GetStdHandle (STD_ERROR_HANDLE); @@ -268,7 +270,7 @@ _gpgme_io_spawn ( const char *path, char **argv, } /* We normally don't want all the normal output */ if ( !duped_stderr ) { - if (!getenv ("GPGME_DEBUG") ) { + if (!debug_me) { si.hStdError = hnul; DEBUG_SELECT ((stderr,"** using %d for stderr\n", (int)hnul )); } @@ -340,7 +342,7 @@ _gpgme_io_waitpid ( int pid, int hang, int *r_status, int *r_signal ) *r_status = 0; *r_signal = 0; - code = WaitForSingleObject ( proc, hang? INFINITE : NULL ); + code = WaitForSingleObject ( proc, hang? INFINITE : 0 ); switch (code) { case WAIT_FAILED: fprintf (stderr, "** WFSO pid=%d failed: %d\n", @@ -565,8 +567,9 @@ _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds ) } } if ( !once_more && !count ) { + /* once more but after relinquishing our timeslot */ once_more = 1; - Sleep (300); + Sleep (0); goto restart; } diff --git a/gpgme/wait.c b/gpgme/wait.c index a337ad0a..b024b092 100644 --- a/gpgme/wait.c +++ b/gpgme/wait.c @@ -24,9 +24,8 @@ #include #include #include -#include #include -#include +#include "syshdr.h" #include "util.h" #include "context.h" @@ -236,7 +235,8 @@ do_select ( void ) return 0; /* error or timeout */ for (i=0; i < fd_table_size /*&& n*/; i++ ) { - if ( fd_table[i].fd != -1 && fd_table[i].signaled ) { + if ( fd_table[i].fd != -1 && fd_table[i].signaled + && !fd_table[i].frozen ) { q = fd_table[i].opaque; assert (n); n--; @@ -261,7 +261,7 @@ do_select ( void ) * called by rungpg.c to register something for select() */ GpgmeError -_gpgme_register_pipe_handler( void *opaque, +_gpgme_register_pipe_handler ( void *opaque, int (*handler)(void*,int,int), void *handler_value, int pid, int fd, int inbound ) @@ -292,6 +292,7 @@ _gpgme_register_pipe_handler( void *opaque, fd_table[i].for_read = inbound; fd_table[i].for_write = !inbound; fd_table[i].signaled = 0; + fd_table[i].frozen = 0; fd_table[i].opaque = q; unlock_table (); return 0; @@ -318,6 +319,38 @@ _gpgme_register_pipe_handler( void *opaque, } +void +_gpgme_freeze_fd ( int fd ) +{ + int i; + + lock_table (); + for (i=0; i < fd_table_size; i++ ) { + if ( fd_table[i].fd == fd ) { + fd_table[i].frozen = 1; + fprintf (stderr, "** FD %d frozen\n", fd ); + break; + } + } + unlock_table (); +} + +void +_gpgme_thaw_fd ( int fd ) +{ + int i; + + lock_table (); + for (i=0; i < fd_table_size; i++ ) { + if ( fd_table[i].fd == fd ) { + fd_table[i].frozen = 0; + fprintf (stderr, "** FD %d thawed\n", fd ); + break; + } + } + unlock_table (); +} + diff --git a/tests/Makefile.am b/tests/Makefile.am index 5e03d459..51d1195a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -22,7 +22,7 @@ all-local: ./pubring.gpg ./secring.gpg -gpg --homedir . --import $(srcdir)/pubdemo.asc ./secring.gpg: ./Alpha/Secret.gpg - -gpg --homedir . --import Alpha/Secret.gpg Zulu/Secret.gpg + -gpg --homedir . --allow-secret-key-import --import Alpha/Secret.gpg Zulu/Secret.gpg ./Alpha/Secret.gpg: secdemo.asc srcdir=$(srcdir) $(srcdir)/mkdemodirs diff --git a/tests/t-decrypt.c b/tests/t-decrypt.c index dd646895..677d3822 100644 --- a/tests/t-decrypt.c +++ b/tests/t-decrypt.c @@ -57,28 +57,23 @@ print_data ( GpgmeData dh ) } -static int -passphrase_cb ( void *opaque, char *buffer, size_t length, size_t *nread ) +static const char * +passphrase_cb ( void *opaque, const char *desc, void *r_hd ) { - struct passphrase_cb_info_s *info = opaque; - const char *desc; + const char *pass; - assert (info); - assert (info->c); - if ( !buffer || !length || !nread ) - return 0; /* those values are reserved for extensions */ - if ( info->did_it ) - return -1; /* eof */ + if ( !desc ) { + /* cleanup by looking at *r_hd */ - desc = gpgme_get_prompt (info->c, 1); - if (desc) - fprintf (stderr, "Request passphrase for '%s'\n", desc ); - if ( length < 3 ) - return -1; /* FIXME - sending an EOF here is wrong */ - memcpy (buffer, "abc", 3 ); - *nread = 3; - info->did_it = 1; - return 0; + + return NULL; + } + + pass = "abc"; + fprintf (stderr, "%% requesting passphrase for `%s': ", desc ); + fprintf (stderr, "sending `%s'\n", pass ); + + return pass; } @@ -111,10 +106,10 @@ main (int argc, char **argv ) do { err = gpgme_new (&ctx); fail_if_err (err); - if ( 0 && !getenv("GPG_AGENT_INFO") ) { + if ( !getenv("GPG_AGENT_INFO") ) { memset ( &info, 0, sizeof info ); info.c = ctx; - gpgme_data_new_with_read_cb ( &pwdata, passphrase_cb, &info ); + gpgme_set_passphrase_cb ( ctx, passphrase_cb, &info ); } err = gpgme_data_new_from_file ( &in, cipher_1_asc, 1 ); @@ -123,7 +118,7 @@ main (int argc, char **argv ) err = gpgme_data_new ( &out ); fail_if_err (err); - err = gpgme_op_decrypt (ctx, pwdata, in, out ); + err = gpgme_op_decrypt (ctx, in, out ); fail_if_err (err); fflush (NULL); diff --git a/tests/t-sign.c b/tests/t-sign.c index c09b2c96..79f6b5cb 100644 --- a/tests/t-sign.c +++ b/tests/t-sign.c @@ -47,6 +47,24 @@ print_data ( GpgmeData dh ) fail_if_err (err); } +static const char * +passphrase_cb ( void *opaque, const char *desc, void *r_hd ) +{ + const char *pass; + + if ( !desc ) { + /* cleanup by looking at *r_hd */ + + + return NULL; + } + + pass = "abc"; + fprintf (stderr, "%% requesting passphrase for `%s': ", desc ); + fprintf (stderr, "sending `%s'\n", pass ); + + return pass; +} int @@ -59,25 +77,55 @@ main (int argc, char **argv ) do { err = gpgme_new (&ctx); fail_if_err (err); + if ( !getenv("GPG_AGENT_INFO") ) { + gpgme_set_passphrase_cb ( ctx, passphrase_cb, NULL ); + } + + gpgme_set_textmode (ctx, 1); + gpgme_set_armor (ctx, 1); err = gpgme_data_new_from_mem ( &in, "Hallo Leute\n", 12, 0 ); fail_if_err (err); + /* first a normal signature */ err = gpgme_data_new ( &out ); fail_if_err (err); - - gpgme_set_textmode (ctx, 1); - gpgme_set_armor (ctx, 1); - err = gpgme_op_sign (ctx, in, out ); + err = gpgme_op_sign (ctx, in, out, GPGME_SIG_MODE_NORMAL ); fail_if_err (err); - fflush (NULL); fputs ("Begin Result:\n", stdout ); print_data (out); fputs ("End Result.\n", stdout ); - - gpgme_data_release (in); gpgme_data_release (out); + gpgme_data_rewind (in); + + /* now a detached signature */ + err = gpgme_data_new ( &out ); + fail_if_err (err); + err = gpgme_op_sign (ctx, in, out, GPGME_SIG_MODE_DETACH ); + fail_if_err (err); + fflush (NULL); + fputs ("Begin Result:\n", stdout ); + print_data (out); + fputs ("End Result.\n", stdout ); + gpgme_data_release (out); + gpgme_data_rewind (in); + + + /* And finally a cleartext signature */ + err = gpgme_data_new ( &out ); + fail_if_err (err); + err = gpgme_op_sign (ctx, in, out, GPGME_SIG_MODE_CLEAR ); + fail_if_err (err); + fflush (NULL); + fputs ("Begin Result:\n", stdout ); + print_data (out); + fputs ("End Result.\n", stdout ); + gpgme_data_release (out); + gpgme_data_rewind (in); + + /* ready */ + gpgme_data_release (in); gpgme_release (ctx); } while ( argc > 1 && !strcmp( argv[1], "--loop" ) ); diff --git a/tests/t-verify.c b/tests/t-verify.c index ac9e3376..2b91a99a 100644 --- a/tests/t-verify.c +++ b/tests/t-verify.c @@ -35,7 +35,7 @@ static const char test_sig1[] = "ZgIAn0204PBR7yxSdQx6CFxugstNqmRv\n" "=yku6\n" "-----END PGP SIGNATURE-----\n" -#elif 0 +#elif 0 "-----BEGIN PGP SIGNATURE-----\n" "Version: GnuPG v1.0.4-2 (GNU/Linux)\n" "Comment: For info see http://www.gnupg.org\n" @@ -108,14 +108,19 @@ main (int argc, char **argv ) err = gpgme_data_new_from_mem ( &text, test_text1, strlen (test_text1), 0 ); fail_if_err (err); + #if 1 err = gpgme_data_new_from_mem ( &sig, test_sig1, strlen (test_sig1), 0 ); + #else + err = gpgme_data_new_from_file ( &sig, "xx1", 1 ); + #endif fail_if_err (err); puts ("checking a valid message:\n"); err = gpgme_op_verify (ctx, sig, text, &status ); print_sig_stat ( status ); fail_if_err (err); + if ( (nota=gpgme_get_notation (ctx)) ) printf ("---Begin Notation---\n%s---End Notation---\n", nota );