cominterop.c 129 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325
  1. /**
  2. * \file
  3. * COM Interop Support
  4. *
  5. *
  6. * (C) 2002 Ximian, Inc. http://www.ximian.com
  7. *
  8. */
  9. #include "config.h"
  10. #include <glib.h>
  11. #ifdef HAVE_ALLOCA_H
  12. #include <alloca.h>
  13. #endif
  14. #include "object.h"
  15. #include "loader.h"
  16. #include "cil-coff.h"
  17. #include "metadata/abi-details.h"
  18. #include "metadata/cominterop.h"
  19. #include "metadata/marshal.h"
  20. #include "metadata/method-builder.h"
  21. #include "metadata/tabledefs.h"
  22. #include "metadata/exception.h"
  23. #include "metadata/appdomain.h"
  24. #include "metadata/reflection-internals.h"
  25. #include "mono/metadata/class-init.h"
  26. #include "mono/metadata/class-internals.h"
  27. #include "mono/metadata/debug-helpers.h"
  28. #include "mono/metadata/threads.h"
  29. #include "mono/metadata/monitor.h"
  30. #include "mono/metadata/metadata-internals.h"
  31. #include "mono/metadata/method-builder-ilgen-internals.h"
  32. #include "mono/metadata/domain-internals.h"
  33. #include "mono/metadata/gc-internals.h"
  34. #include "mono/metadata/threads-types.h"
  35. #include "mono/metadata/string-icalls.h"
  36. #include "mono/metadata/attrdefs.h"
  37. #include "mono/utils/mono-counters.h"
  38. #include "mono/utils/strenc.h"
  39. #include "mono/utils/atomic.h"
  40. #include "mono/utils/mono-error.h"
  41. #include "mono/utils/mono-error-internals.h"
  42. #include <string.h>
  43. #include <errno.h>
  44. #include <mono/utils/w32api.h>
  45. #if defined (HOST_WIN32)
  46. MONO_PRAGMA_WARNING_PUSH()
  47. MONO_PRAGMA_WARNING_DISABLE (4115) // warning C4115: 'IRpcStubBuffer': named type definition in parentheses
  48. #include <oleauto.h>
  49. MONO_PRAGMA_WARNING_POP()
  50. #include <mono/utils/w32subset.h>
  51. #endif
  52. #include "icall-decl.h"
  53. #include "icall-signatures.h"
  54. static void
  55. mono_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj);
  56. #if !defined (DISABLE_COM) || defined (HOST_WIN32)
  57. static int
  58. mono_IUnknown_QueryInterface (MonoIUnknown *pUnk, gconstpointer riid, gpointer* ppv)
  59. {
  60. g_assert (pUnk);
  61. return pUnk->vtable->QueryInterface (pUnk, riid, ppv);
  62. }
  63. static int
  64. mono_IUnknown_AddRef (MonoIUnknown *pUnk)
  65. {
  66. // The return value is a reference count, generally transient, generally not to be used, except for debugging,
  67. // or to assert that it is > 0.
  68. g_assert (pUnk);
  69. return pUnk->vtable->AddRef (pUnk);
  70. }
  71. static int
  72. mono_IUnknown_Release (MonoIUnknown *pUnk)
  73. {
  74. // Release is like free -- null is silently ignored.
  75. // Also, the return value is a reference count, generally transient, generally not to be used, except for debugging.
  76. return pUnk ? pUnk->vtable->Release (pUnk) : 0;
  77. }
  78. #endif
  79. /*
  80. Code shared between the DISABLE_COM and !DISABLE_COM
  81. */
  82. // func is an identifier, that names a function, and is also in jit-icall-reg.h,
  83. // and therefore a field in mono_jit_icall_info and can be token pasted into an enum value.
  84. //
  85. // The name of func must be linkable for AOT, for example g_free does not work (monoeg_g_free instead),
  86. // nor does the C++ overload fmod (mono_fmod instead). These functions therefore
  87. // must be extern "C".
  88. #define register_icall(func, sig, save) \
  89. (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->func, func, #func, (sig), (save), #func))
  90. mono_bstr
  91. mono_string_to_bstr_impl (MonoStringHandle s, MonoError *error)
  92. {
  93. if (MONO_HANDLE_IS_NULL (s))
  94. return NULL;
  95. MonoGCHandle gchandle = NULL;
  96. mono_bstr const res = mono_ptr_to_bstr (mono_string_handle_pin_chars (s, &gchandle), mono_string_handle_length (s));
  97. mono_gchandle_free_internal (gchandle);
  98. return res;
  99. }
  100. static void*
  101. mono_cominterop_get_com_interface_internal (gboolean icall, MonoObjectHandle object, MonoClass *ic, MonoError *error);
  102. #ifndef DISABLE_COM
  103. #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
  104. a = i,
  105. typedef enum {
  106. MONO_MARSHAL_NONE, /* No marshalling needed */
  107. MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
  108. MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
  109. MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
  110. } MonoXDomainMarshalType;
  111. typedef enum {
  112. MONO_COM_DEFAULT,
  113. MONO_COM_MS
  114. } MonoCOMProvider;
  115. static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
  116. enum {
  117. #include "mono/cil/opcode.def"
  118. LAST = 0xff
  119. };
  120. #undef OPDEF
  121. /* This mutex protects the various cominterop related caches in MonoImage */
  122. #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
  123. #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
  124. static mono_mutex_t cominterop_mutex;
  125. GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, "Mono.Interop", "ComInteropProxy")
  126. GENERATE_GET_CLASS_WITH_CACHE (idispatch, "Mono.Interop", "IDispatch")
  127. GENERATE_GET_CLASS_WITH_CACHE (iunknown, "Mono.Interop", "IUnknown")
  128. GENERATE_GET_CLASS_WITH_CACHE (com_object, "System", "__ComObject")
  129. GENERATE_GET_CLASS_WITH_CACHE (variant, "System", "Variant")
  130. static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, "System.Runtime.InteropServices", "InterfaceTypeAttribute")
  131. static GENERATE_GET_CLASS_WITH_CACHE (com_visible_attribute, "System.Runtime.InteropServices", "ComVisibleAttribute")
  132. static GENERATE_GET_CLASS_WITH_CACHE (com_default_interface_attribute, "System.Runtime.InteropServices", "ComDefaultInterfaceAttribute")
  133. static GENERATE_GET_CLASS_WITH_CACHE (class_interface_attribute, "System.Runtime.InteropServices", "ClassInterfaceAttribute")
  134. /* Upon creation of a CCW, only allocate a weak handle and set the
  135. * reference count to 0. If the unmanaged client code decides to addref and
  136. * hold onto the CCW, I then allocate a strong handle. Once the reference count
  137. * goes back to 0, convert back to a weak handle.
  138. */
  139. typedef struct {
  140. guint32 ref_count;
  141. MonoGCHandle gc_handle;
  142. GHashTable* vtable_hash;
  143. #ifdef HOST_WIN32
  144. MonoIUnknown *free_marshaler; // actually IMarshal
  145. #endif
  146. } MonoCCW;
  147. /* This type is the actual pointer passed to unmanaged code
  148. * to represent a COM interface.
  149. */
  150. typedef struct {
  151. gpointer vtable;
  152. MonoCCW* ccw;
  153. } MonoCCWInterface;
  154. /* IUnknown */
  155. static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
  156. static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
  157. static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv);
  158. /* IDispatch */
  159. static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
  160. static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
  161. static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
  162. gunichar2** rgszNames, guint32 cNames,
  163. guint32 lcid, gint32 *rgDispId);
  164. static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
  165. gpointer riid, guint32 lcid,
  166. guint16 wFlags, gpointer pDispParams,
  167. gpointer pVarResult, gpointer pExcepInfo,
  168. guint32 *puArgErr);
  169. static MonoMethod *
  170. cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
  171. static gpointer
  172. cominterop_get_ccw (MonoObject* object, MonoClass* itf);
  173. static gpointer
  174. cominterop_get_ccw_checked (MonoObjectHandle object, MonoClass *itf, MonoError *error);
  175. static MonoObject*
  176. cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
  177. static MonoObjectHandle
  178. cominterop_get_ccw_handle (MonoCCWInterface* ccw_entry, gboolean verify);
  179. static MonoObject*
  180. cominterop_set_ccw_object_domain (MonoObject *object, MonoDomain **prev_domain);
  181. static void
  182. cominterop_restore_domain (MonoDomain *domain);
  183. /* SAFEARRAY marshalling */
  184. static gboolean
  185. mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
  186. static gpointer
  187. mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
  188. static gboolean
  189. mono_marshal_safearray_next (gpointer safearray, gpointer indices);
  190. static void
  191. mono_marshal_safearray_end (gpointer safearray, gpointer indices);
  192. static gboolean
  193. mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
  194. static void
  195. mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
  196. static void
  197. mono_marshal_safearray_free_indices (gpointer indices);
  198. MonoClass*
  199. mono_class_try_get_com_object_class (void)
  200. {
  201. static MonoClass *tmp_class;
  202. static gboolean inited;
  203. MonoClass *klass;
  204. if (!inited) {
  205. klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
  206. mono_memory_barrier ();
  207. tmp_class = klass;
  208. mono_memory_barrier ();
  209. inited = TRUE;
  210. }
  211. return tmp_class;
  212. }
  213. /**
  214. * cominterop_method_signature:
  215. * @method: a method
  216. *
  217. * Returns: the corresponding unmanaged method signature for a managed COM
  218. * method.
  219. */
  220. static MonoMethodSignature*
  221. cominterop_method_signature (MonoMethod* method)
  222. {
  223. MonoMethodSignature *res;
  224. MonoImage *image = m_class_get_image (method->klass);
  225. MonoMethodSignature *sig = mono_method_signature_internal (method);
  226. gboolean const preserve_sig = (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) != 0;
  227. int sigsize;
  228. int i;
  229. int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
  230. if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
  231. param_count++;
  232. res = mono_metadata_signature_alloc (image, param_count);
  233. sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
  234. memcpy (res, sig, sigsize);
  235. // now move args forward one
  236. for (i = sig->param_count-1; i >= 0; i--)
  237. res->params[i+1] = sig->params[i];
  238. // first arg is interface pointer
  239. res->params[0] = mono_get_int_type ();
  240. if (preserve_sig) {
  241. res->ret = sig->ret;
  242. }
  243. else {
  244. // last arg is return type
  245. if (!MONO_TYPE_IS_VOID (sig->ret)) {
  246. res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
  247. res->params[param_count-1]->byref = 1;
  248. res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
  249. }
  250. // return type is always int32 (HRESULT)
  251. res->ret = mono_get_int32_type ();
  252. }
  253. // no pinvoke
  254. res->pinvoke = FALSE;
  255. // no hasthis
  256. res->hasthis = 0;
  257. // set param_count
  258. res->param_count = param_count;
  259. // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
  260. #ifdef HOST_WIN32
  261. res->call_convention = MONO_CALL_STDCALL;
  262. #else
  263. res->call_convention = MONO_CALL_C;
  264. #endif
  265. return res;
  266. }
  267. /**
  268. * cominterop_get_function_pointer:
  269. * @itf: a pointer to the COM interface
  270. * @slot: the vtable slot of the method pointer to return
  271. *
  272. * Returns: the unmanaged vtable function pointer from the interface
  273. */
  274. static gpointer
  275. cominterop_get_function_pointer (gpointer itf, int slot)
  276. {
  277. gpointer func;
  278. func = *((*(gpointer**)itf)+slot);
  279. return func;
  280. }
  281. /**
  282. * cominterop_object_is_com_object:
  283. * @obj: a pointer to the object
  284. *
  285. * Returns: a value indicating if the object is a
  286. * Runtime Callable Wrapper (RCW) for a COM object
  287. */
  288. static gboolean
  289. cominterop_object_is_rcw_handle (MonoObjectHandle obj, MonoRealProxyHandle *real_proxy)
  290. {
  291. MonoClass *klass;
  292. return !MONO_HANDLE_IS_NULL (obj)
  293. && (klass = mono_handle_class (obj))
  294. && mono_class_is_transparent_proxy (klass)
  295. && !MONO_HANDLE_IS_NULL (*real_proxy = MONO_HANDLE_NEW_GET (MonoRealProxy, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp))
  296. && (klass = mono_handle_class (*real_proxy))
  297. && klass == mono_class_get_interop_proxy_class ();
  298. }
  299. static gboolean
  300. cominterop_object_is_rcw (MonoObject *obj_raw)
  301. {
  302. if (!obj_raw)
  303. return FALSE;
  304. HANDLE_FUNCTION_ENTER ();
  305. MONO_HANDLE_DCL (MonoObject, obj);
  306. MonoRealProxyHandle real_proxy;
  307. gboolean const result = cominterop_object_is_rcw_handle (obj, &real_proxy);
  308. HANDLE_FUNCTION_RETURN_VAL (result);
  309. }
  310. static int
  311. cominterop_get_com_slot_begin (MonoClass* klass)
  312. {
  313. ERROR_DECL (error);
  314. MonoCustomAttrInfo *cinfo = NULL;
  315. MonoInterfaceTypeAttribute* itf_attr = NULL;
  316. cinfo = mono_custom_attrs_from_class_checked (klass, error);
  317. mono_error_assert_ok (error);
  318. if (cinfo) {
  319. itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), error);
  320. mono_error_assert_ok (error); /*FIXME proper error handling*/
  321. if (!cinfo->cached)
  322. mono_custom_attrs_free (cinfo);
  323. }
  324. if (itf_attr && itf_attr->intType == 1)
  325. return 3; /* 3 methods in IUnknown*/
  326. else
  327. return 7; /* 7 methods in IDispatch*/
  328. }
  329. /**
  330. * cominterop_get_method_interface:
  331. * @method: method being called
  332. *
  333. * Returns: the MonoClass* representing the interface on which
  334. * the method is defined.
  335. */
  336. static MonoClass*
  337. cominterop_get_method_interface (MonoMethod* method)
  338. {
  339. ERROR_DECL (error);
  340. MonoClass *ic = method->klass;
  341. /* if method is on a class, we need to look up interface method exists on */
  342. if (!MONO_CLASS_IS_INTERFACE_INTERNAL (method->klass)) {
  343. GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, error);
  344. mono_error_assert_ok (error);
  345. if (ifaces) {
  346. int i;
  347. mono_class_setup_vtable (method->klass);
  348. for (i = 0; i < ifaces->len; ++i) {
  349. int j, offset;
  350. gboolean found = FALSE;
  351. ic = (MonoClass *)g_ptr_array_index (ifaces, i);
  352. offset = mono_class_interface_offset (method->klass, ic);
  353. int mcount = mono_class_get_method_count (ic);
  354. MonoMethod **method_klass_vtable = m_class_get_vtable (method->klass);
  355. for (j = 0; j < mcount; ++j) {
  356. if (method_klass_vtable [j + offset] == method) {
  357. found = TRUE;
  358. break;
  359. }
  360. }
  361. if (found)
  362. break;
  363. ic = NULL;
  364. }
  365. g_ptr_array_free (ifaces, TRUE);
  366. }
  367. }
  368. return ic;
  369. }
  370. static void
  371. mono_cominterop_get_interface_missing_error (MonoError* error, MonoMethod* method)
  372. {
  373. mono_error_set_invalid_operation (error, "Method '%s' in ComImport class '%s' must implement an interface method.", method->name, m_class_get_name (method->klass));
  374. }
  375. /**
  376. * cominterop_get_com_slot_for_method:
  377. * @method: a method
  378. * @error: set on error
  379. *
  380. * Returns: the method's slot in the COM interface vtable
  381. */
  382. static int
  383. cominterop_get_com_slot_for_method (MonoMethod* method, MonoError* error)
  384. {
  385. guint32 slot = method->slot;
  386. MonoClass *ic = method->klass;
  387. error_init (error);
  388. /* if method is on a class, we need to look up interface method exists on */
  389. if (!MONO_CLASS_IS_INTERFACE_INTERNAL (ic)) {
  390. int offset = 0;
  391. int i = 0;
  392. ic = cominterop_get_method_interface (method);
  393. if (!ic || !MONO_CLASS_IS_INTERFACE_INTERNAL (ic)) {
  394. mono_cominterop_get_interface_missing_error (error, method);
  395. return -1;
  396. }
  397. offset = mono_class_interface_offset (method->klass, ic);
  398. g_assert(offset >= 0);
  399. int mcount = mono_class_get_method_count (ic);
  400. MonoMethod **ic_methods = m_class_get_methods (ic);
  401. MonoMethod **method_klass_vtable = m_class_get_vtable (method->klass);
  402. for(i = 0; i < mcount; ++i) {
  403. if (method_klass_vtable [i + offset] == method)
  404. {
  405. slot = ic_methods[i]->slot;
  406. break;
  407. }
  408. }
  409. }
  410. g_assert (ic);
  411. g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (ic));
  412. return slot + cominterop_get_com_slot_begin (ic);
  413. }
  414. static gboolean
  415. cominterop_class_guid (MonoClass* klass, guint8* guid)
  416. {
  417. ERROR_DECL (error);
  418. mono_metadata_get_class_guid (klass, guid, error);
  419. mono_error_assert_ok (error); /*FIXME proper error handling*/
  420. return TRUE;
  421. }
  422. static gboolean
  423. cominterop_com_visible (MonoClass* klass)
  424. {
  425. ERROR_DECL (error);
  426. MonoCustomAttrInfo *cinfo;
  427. GPtrArray *ifaces;
  428. MonoBoolean visible = 1;
  429. cinfo = mono_custom_attrs_from_class_checked (klass, error);
  430. mono_error_assert_ok (error);
  431. if (cinfo) {
  432. MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_com_visible_attribute_class (), error);
  433. mono_error_assert_ok (error); /*FIXME proper error handling*/
  434. if (attr)
  435. visible = attr->visible;
  436. if (!cinfo->cached)
  437. mono_custom_attrs_free (cinfo);
  438. if (visible)
  439. return TRUE;
  440. }
  441. ifaces = mono_class_get_implemented_interfaces (klass, error);
  442. mono_error_assert_ok (error);
  443. if (ifaces) {
  444. int i;
  445. for (i = 0; i < ifaces->len; ++i) {
  446. MonoClass *ic = NULL;
  447. ic = (MonoClass *)g_ptr_array_index (ifaces, i);
  448. if (MONO_CLASS_IS_IMPORT (ic))
  449. visible = TRUE;
  450. }
  451. g_ptr_array_free (ifaces, TRUE);
  452. }
  453. return visible;
  454. }
  455. gboolean
  456. mono_cominterop_method_com_visible (MonoMethod *method)
  457. {
  458. ERROR_DECL (error);
  459. MonoCustomAttrInfo *cinfo;
  460. MonoBoolean visible = 1;
  461. cinfo = mono_custom_attrs_from_method_checked (method, error);
  462. mono_error_assert_ok (error);
  463. if (cinfo) {
  464. MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_com_visible_attribute_class (), error);
  465. mono_error_assert_ok (error); /*FIXME proper error handling*/
  466. if (attr)
  467. visible = attr->visible;
  468. if (!cinfo->cached)
  469. mono_custom_attrs_free (cinfo);
  470. }
  471. return visible;
  472. }
  473. static void
  474. cominterop_set_hr_error (MonoError *oerror, int hr)
  475. {
  476. ERROR_DECL (error);
  477. MonoException* ex;
  478. void* params[1] = {&hr};
  479. MONO_STATIC_POINTER_INIT (MonoMethod, throw_exception_for_hr)
  480. throw_exception_for_hr = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetExceptionForHR", 1, 0, error);
  481. mono_error_assert_ok (error);
  482. MONO_STATIC_POINTER_INIT_END (MonoMethod, throw_exception_for_hr)
  483. ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, error);
  484. g_assert (ex);
  485. mono_error_assert_ok (error);
  486. mono_error_set_exception_instance (oerror, ex);
  487. }
  488. /**
  489. * cominterop_get_interface_checked:
  490. * @obj: managed wrapper object containing COM object
  491. * @ic: interface type to retrieve for COM object
  492. * @error: set on error
  493. *
  494. * Returns: the COM interface requested. On failure returns NULL and sets @error
  495. */
  496. static gpointer
  497. cominterop_get_interface_checked (MonoComObjectHandle obj, MonoClass* ic, MonoError *error)
  498. {
  499. gpointer itf = NULL;
  500. g_assert (ic);
  501. g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (ic));
  502. error_init (error);
  503. mono_cominterop_lock ();
  504. if (MONO_HANDLE_GETVAL (obj, itf_hash))
  505. itf = g_hash_table_lookup (MONO_HANDLE_GETVAL (obj, itf_hash), GUINT_TO_POINTER ((guint)m_class_get_interface_id (ic)));
  506. mono_cominterop_unlock ();
  507. if (itf)
  508. return itf;
  509. guint8 iid [16];
  510. gboolean const found = cominterop_class_guid (ic, iid);
  511. g_assert (found);
  512. g_assert (MONO_HANDLE_GETVAL (obj, iunknown));
  513. int const hr = mono_IUnknown_QueryInterface (MONO_HANDLE_GETVAL (obj, iunknown), iid, &itf);
  514. if (hr < 0) {
  515. g_assert (!itf);
  516. cominterop_set_hr_error (error, hr);
  517. g_assert (!is_ok (error));
  518. return NULL;
  519. }
  520. g_assert (itf);
  521. mono_cominterop_lock ();
  522. if (!MONO_HANDLE_GETVAL (obj, itf_hash))
  523. MONO_HANDLE_SETVAL (obj, itf_hash, GHashTable*, g_hash_table_new (mono_aligned_addr_hash, NULL));
  524. g_hash_table_insert (MONO_HANDLE_GETVAL (obj, itf_hash), GUINT_TO_POINTER ((guint)m_class_get_interface_id (ic)), itf);
  525. mono_cominterop_unlock ();
  526. return itf;
  527. }
  528. /**
  529. * cominterop_get_interface:
  530. * @obj: managed wrapper object containing COM object
  531. * @ic: interface type to retrieve for COM object
  532. *
  533. * Returns: the COM interface requested
  534. */
  535. static gpointer
  536. cominterop_get_interface (MonoComObject *obj_raw, MonoClass *ic)
  537. {
  538. HANDLE_FUNCTION_ENTER ();
  539. ERROR_DECL (error);
  540. MONO_HANDLE_DCL (MonoComObject, obj);
  541. gpointer const itf = cominterop_get_interface_checked (obj, ic, error);
  542. g_assert (!!itf == is_ok (error)); // two equal success indicators
  543. mono_error_set_pending_exception (error);
  544. HANDLE_FUNCTION_RETURN_VAL (itf);
  545. }
  546. // This is an icall, it will return NULL and set pending exception (in
  547. // mono_type_from_handle wrapper) on failure.
  548. static MonoReflectionType *
  549. cominterop_type_from_handle (MonoType *handle)
  550. {
  551. return mono_type_from_handle (handle);
  552. }
  553. #endif // DISABLE_COM
  554. void
  555. mono_cominterop_init (void)
  556. {
  557. #ifndef DISABLE_COM
  558. mono_os_mutex_init_recursive (&cominterop_mutex);
  559. char* const com_provider_env = g_getenv ("MONO_COM");
  560. if (com_provider_env && !strcmp(com_provider_env, "MS"))
  561. com_provider = MONO_COM_MS;
  562. g_free (com_provider_env);
  563. register_icall (cominterop_get_method_interface, mono_icall_sig_ptr_ptr, FALSE);
  564. register_icall (cominterop_get_function_pointer, mono_icall_sig_ptr_ptr_int32, FALSE);
  565. register_icall (cominterop_object_is_rcw, mono_icall_sig_int32_object, FALSE);
  566. register_icall (cominterop_get_ccw, mono_icall_sig_ptr_object_ptr, FALSE);
  567. register_icall (cominterop_get_ccw_object, mono_icall_sig_object_ptr_int32, FALSE);
  568. register_icall (cominterop_get_interface, mono_icall_sig_ptr_object_ptr, FALSE);
  569. register_icall (cominterop_type_from_handle, mono_icall_sig_object_ptr, FALSE);
  570. register_icall (cominterop_set_ccw_object_domain, mono_icall_sig_object_object_ptr, FALSE);
  571. register_icall (cominterop_restore_domain, mono_icall_sig_void_ptr, FALSE);
  572. /* SAFEARRAY marshalling */
  573. register_icall (mono_marshal_safearray_begin, mono_icall_sig_int32_ptr_ptr_ptr_ptr_ptr_int32, FALSE);
  574. register_icall (mono_marshal_safearray_get_value, mono_icall_sig_ptr_ptr_ptr, FALSE);
  575. register_icall (mono_marshal_safearray_next, mono_icall_sig_int32_ptr_ptr, FALSE);
  576. register_icall (mono_marshal_safearray_end, mono_icall_sig_void_ptr_ptr, FALSE);
  577. register_icall (mono_marshal_safearray_create, mono_icall_sig_int32_object_ptr_ptr_ptr, FALSE);
  578. register_icall (mono_marshal_safearray_set_value, mono_icall_sig_void_ptr_ptr_ptr, FALSE);
  579. register_icall (mono_marshal_safearray_free_indices, mono_icall_sig_void_ptr, FALSE);
  580. #endif // DISABLE_COM
  581. /*FIXME
  582. This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
  583. If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
  584. g_assert.
  585. The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
  586. emit an exception in the generated IL.
  587. */
  588. register_icall (mono_string_to_bstr, mono_icall_sig_ptr_obj, FALSE);
  589. register_icall (mono_string_from_bstr_icall, mono_icall_sig_obj_ptr, FALSE);
  590. register_icall (mono_free_bstr, mono_icall_sig_void_ptr, FALSE);
  591. }
  592. #ifndef DISABLE_COM
  593. void
  594. mono_cominterop_cleanup (void)
  595. {
  596. mono_os_mutex_destroy (&cominterop_mutex);
  597. }
  598. void
  599. mono_mb_emit_cominterop_get_function_pointer (MonoMethodBuilder *mb, MonoMethod *method)
  600. {
  601. #ifndef DISABLE_JIT
  602. int slot;
  603. ERROR_DECL (error);
  604. // get function pointer from 1st arg, the COM interface pointer
  605. mono_mb_emit_ldarg (mb, 0);
  606. slot = cominterop_get_com_slot_for_method (method, error);
  607. if (is_ok (error)) {
  608. mono_mb_emit_icon (mb, slot);
  609. mono_mb_emit_icall (mb, cominterop_get_function_pointer);
  610. /* Leaves the function pointer on top of the stack */
  611. }
  612. else {
  613. mono_mb_emit_exception_for_error (mb, error);
  614. }
  615. mono_error_cleanup (error);
  616. #endif
  617. }
  618. void
  619. mono_mb_emit_cominterop_call_function_pointer (MonoMethodBuilder *mb, MonoMethodSignature *sig)
  620. {
  621. #ifndef DISABLE_JIT
  622. mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
  623. mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
  624. mono_mb_emit_calli (mb, sig);
  625. mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
  626. mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
  627. #endif /* DISABLE_JIT */
  628. }
  629. void
  630. mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
  631. {
  632. #ifndef DISABLE_JIT
  633. mono_mb_emit_cominterop_get_function_pointer (mb, method);
  634. mono_mb_emit_cominterop_call_function_pointer (mb, sig);
  635. #endif /* DISABLE_JIT */
  636. }
  637. void
  638. mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
  639. {
  640. #ifndef DISABLE_JIT
  641. switch (conv) {
  642. case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
  643. case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
  644. case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
  645. guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
  646. MonoClass *klass = NULL;
  647. klass = mono_class_from_mono_type_internal (type);
  648. mono_mb_emit_ldloc (mb, 1);
  649. mono_mb_emit_byte (mb, CEE_LDNULL);
  650. mono_mb_emit_byte (mb, CEE_STIND_REF);
  651. mono_mb_emit_ldloc (mb, 0);
  652. mono_mb_emit_byte (mb, CEE_LDIND_I);
  653. pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  654. /* load dst to store later */
  655. mono_mb_emit_ldloc (mb, 1);
  656. mono_mb_emit_ldloc (mb, 0);
  657. mono_mb_emit_byte (mb, CEE_LDIND_I);
  658. mono_mb_emit_icon (mb, TRUE);
  659. mono_mb_emit_icall (mb, cominterop_get_ccw_object);
  660. pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
  661. MONO_STATIC_POINTER_INIT (MonoMethod, com_interop_proxy_get_proxy)
  662. ERROR_DECL (error);
  663. com_interop_proxy_get_proxy = mono_class_get_method_from_name_checked (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE, error);
  664. mono_error_assert_ok (error);
  665. MONO_STATIC_POINTER_INIT_END (MonoMethod, com_interop_proxy_get_proxy)
  666. #ifndef DISABLE_REMOTING
  667. MONO_STATIC_POINTER_INIT (MonoMethod, get_transparent_proxy)
  668. ERROR_DECL (error);
  669. get_transparent_proxy = mono_class_get_method_from_name_checked (mono_defaults.real_proxy_class, "GetTransparentProxy", 0, 0, error);
  670. mono_error_assert_ok (error);
  671. MONO_STATIC_POINTER_INIT_END (MonoMethod, get_transparent_proxy)
  672. #else
  673. static MonoMethod* const get_transparent_proxy = NULL; // FIXME?
  674. #endif
  675. mono_mb_add_local (mb, m_class_get_byval_arg (mono_class_get_interop_proxy_class ()));
  676. mono_mb_emit_ldloc (mb, 0);
  677. mono_mb_emit_byte (mb, CEE_LDIND_I);
  678. mono_mb_emit_ptr (mb, m_class_get_byval_arg (mono_class_get_com_object_class ()));
  679. mono_mb_emit_icall (mb, cominterop_type_from_handle);
  680. mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
  681. mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
  682. if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
  683. g_assert (klass);
  684. mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
  685. }
  686. mono_mb_emit_byte (mb, CEE_STIND_REF);
  687. pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
  688. /* is already managed object */
  689. mono_mb_patch_short_branch (mb, pos_ccw);
  690. mono_mb_emit_ldloc (mb, 0);
  691. mono_mb_emit_byte (mb, CEE_LDIND_I);
  692. mono_mb_emit_icon (mb, TRUE);
  693. mono_mb_emit_icall (mb, cominterop_get_ccw_object);
  694. if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
  695. g_assert (klass);
  696. mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
  697. }
  698. mono_mb_emit_byte (mb, CEE_STIND_REF);
  699. mono_mb_patch_short_branch (mb, pos_end);
  700. /* case if null */
  701. mono_mb_patch_short_branch (mb, pos_null);
  702. break;
  703. }
  704. default:
  705. g_assert_not_reached ();
  706. }
  707. #endif /* DISABLE_JIT */
  708. }
  709. void
  710. mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
  711. {
  712. #ifndef DISABLE_JIT
  713. switch (conv) {
  714. case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
  715. case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
  716. case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
  717. guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
  718. mono_mb_emit_ldloc (mb, 1);
  719. mono_mb_emit_icon (mb, 0);
  720. mono_mb_emit_byte (mb, CEE_CONV_U);
  721. mono_mb_emit_byte (mb, CEE_STIND_I);
  722. mono_mb_emit_ldloc (mb, 0);
  723. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  724. // if null just break, dst was already inited to 0
  725. pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  726. mono_mb_emit_ldloc (mb, 0);
  727. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  728. mono_mb_emit_icall (mb, cominterop_object_is_rcw);
  729. pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  730. // load dst to store later
  731. mono_mb_emit_ldloc (mb, 1);
  732. // load src
  733. mono_mb_emit_ldloc (mb, 0);
  734. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  735. mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
  736. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  737. /* load the RCW from the ComInteropProxy*/
  738. mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
  739. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  740. if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
  741. mono_mb_emit_ptr (mb, mono_type_get_class_internal (type));
  742. mono_mb_emit_icall (mb, cominterop_get_interface);
  743. }
  744. else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
  745. MONO_STATIC_POINTER_INIT (MonoProperty, iunknown)
  746. iunknown = mono_class_get_property_from_name_internal (mono_class_get_com_object_class (), "IUnknown");
  747. MONO_STATIC_POINTER_INIT_END (MonoProperty, iunknown)
  748. mono_mb_emit_managed_call (mb, iunknown->get, NULL);
  749. }
  750. else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
  751. MONO_STATIC_POINTER_INIT (MonoProperty, idispatch)
  752. idispatch = mono_class_get_property_from_name_internal (mono_class_get_com_object_class (), "IDispatch");
  753. MONO_STATIC_POINTER_INIT_END (MonoProperty, idispatch)
  754. mono_mb_emit_managed_call (mb, idispatch->get, NULL);
  755. }
  756. else {
  757. g_assert_not_reached ();
  758. }
  759. mono_mb_emit_byte (mb, CEE_STIND_I);
  760. pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
  761. // if not rcw
  762. mono_mb_patch_short_branch (mb, pos_rcw);
  763. /* load dst to store later */
  764. mono_mb_emit_ldloc (mb, 1);
  765. /* load src */
  766. mono_mb_emit_ldloc (mb, 0);
  767. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  768. if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
  769. mono_mb_emit_ptr (mb, mono_type_get_class_internal (type));
  770. else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
  771. mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
  772. else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
  773. mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
  774. else
  775. g_assert_not_reached ();
  776. mono_mb_emit_icall (mb, cominterop_get_ccw);
  777. mono_mb_emit_byte (mb, CEE_STIND_I);
  778. mono_mb_patch_short_branch (mb, pos_end);
  779. mono_mb_patch_short_branch (mb, pos_null);
  780. break;
  781. }
  782. default:
  783. g_assert_not_reached ();
  784. }
  785. #endif /* DISABLE_JIT */
  786. }
  787. /**
  788. * cominterop_get_native_wrapper_adjusted:
  789. * @method: managed COM Interop method
  790. *
  791. * Returns: the generated method to call with signature matching
  792. * the unmanaged COM Method signature
  793. */
  794. static MonoMethod *
  795. cominterop_get_native_wrapper_adjusted (MonoMethod *method)
  796. {
  797. MonoMethod *res;
  798. MonoMethodBuilder *mb_native;
  799. MonoMarshalSpec **mspecs;
  800. MonoMethodSignature *sig, *sig_native;
  801. MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
  802. int i;
  803. sig = mono_method_signature_internal (method);
  804. // create unmanaged wrapper
  805. mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
  806. sig_native = cominterop_method_signature (method);
  807. mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count + 1);
  808. mono_method_get_marshal_info (method, mspecs);
  809. // move managed args up one
  810. for (i = sig->param_count; i >= 1; i--)
  811. mspecs[i+1] = mspecs[i];
  812. // first arg is IntPtr for interface
  813. mspecs[1] = NULL;
  814. if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
  815. // move return spec to last param
  816. if (!MONO_TYPE_IS_VOID (sig->ret))
  817. mspecs[sig_native->param_count] = mspecs[0];
  818. mspecs[0] = NULL;
  819. }
  820. for (i = 1; i < sig_native->param_count; i++) {
  821. int mspec_index = i + 1;
  822. if (mspecs[mspec_index] == NULL) {
  823. // default object to VARIANT
  824. if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
  825. mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
  826. mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
  827. }
  828. else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
  829. mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
  830. mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
  831. }
  832. else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
  833. mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
  834. mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
  835. }
  836. else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
  837. mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
  838. mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
  839. }
  840. }
  841. }
  842. if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
  843. // move return spec to last param
  844. if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
  845. // default object to VARIANT
  846. if (sig->ret->type == MONO_TYPE_OBJECT) {
  847. mspecs[0] = g_new0 (MonoMarshalSpec, 1);
  848. mspecs[0]->native = MONO_NATIVE_STRUCT;
  849. }
  850. else if (sig->ret->type == MONO_TYPE_STRING) {
  851. mspecs[0] = g_new0 (MonoMarshalSpec, 1);
  852. mspecs[0]->native = MONO_NATIVE_BSTR;
  853. }
  854. else if (sig->ret->type == MONO_TYPE_CLASS) {
  855. mspecs[0] = g_new0 (MonoMarshalSpec, 1);
  856. mspecs[0]->native = MONO_NATIVE_INTERFACE;
  857. }
  858. else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
  859. mspecs[0] = g_new0 (MonoMarshalSpec, 1);
  860. mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
  861. }
  862. }
  863. }
  864. mono_marshal_emit_native_wrapper (m_class_get_image (method->klass), mb_native, sig_native, piinfo, mspecs, piinfo->addr, EMIT_NATIVE_WRAPPER_CHECK_EXCEPTIONS);
  865. res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
  866. mono_mb_free (mb_native);
  867. for (i = sig_native->param_count; i >= 0; i--)
  868. if (mspecs [i])
  869. mono_metadata_free_marshal_spec (mspecs [i]);
  870. g_free (mspecs);
  871. return res;
  872. }
  873. /**
  874. * mono_cominterop_get_native_wrapper:
  875. * \param method managed method
  876. * \returns the generated method to call
  877. */
  878. MonoMethod *
  879. mono_cominterop_get_native_wrapper (MonoMethod *method)
  880. {
  881. MonoMethod *res;
  882. GHashTable *cache;
  883. MonoMethodBuilder *mb;
  884. MonoMethodSignature *sig, *csig;
  885. g_assert (method);
  886. cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
  887. if ((res = mono_marshal_find_in_cache (cache, method)))
  888. return res;
  889. if (!m_class_get_vtable (method->klass))
  890. mono_class_setup_vtable (method->klass);
  891. if (!m_class_get_methods (method->klass))
  892. mono_class_setup_methods (method->klass);
  893. g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
  894. sig = mono_method_signature_internal (method);
  895. mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
  896. #ifndef DISABLE_JIT
  897. /* if method klass is import, that means method
  898. * is really a com call. let interop system emit it.
  899. */
  900. if (MONO_CLASS_IS_IMPORT(method->klass)) {
  901. /* FIXME: we have to call actual class .ctor
  902. * instead of just __ComObject .ctor.
  903. */
  904. if (!strcmp(method->name, ".ctor")) {
  905. MONO_STATIC_POINTER_INIT (MonoMethod, ctor)
  906. ERROR_DECL (error);
  907. ctor = mono_class_get_method_from_name_checked (mono_class_get_com_object_class (), ".ctor", 0, 0, error);
  908. mono_error_assert_ok (error);
  909. MONO_STATIC_POINTER_INIT_END (MonoMethod, ctor)
  910. mono_mb_emit_ldarg (mb, 0);
  911. mono_mb_emit_managed_call (mb, ctor, NULL);
  912. mono_mb_emit_byte (mb, CEE_RET);
  913. }
  914. else if (method->flags & METHOD_ATTRIBUTE_STATIC) {
  915. /*
  916. * The method's class must implement an interface.
  917. * However, no interfaces are allowed to have static methods.
  918. * Thus, calling it should invariably lead to an exception.
  919. */
  920. ERROR_DECL (error);
  921. mono_cominterop_get_interface_missing_error (error, method);
  922. mono_mb_emit_exception_for_error (mb, error);
  923. mono_error_cleanup (error);
  924. }
  925. else {
  926. MonoMethod *adjusted_method;
  927. int retval = 0;
  928. int ptr_this;
  929. int i;
  930. gboolean const preserve_sig = (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) != 0;
  931. // add local variables
  932. ptr_this = mono_mb_add_local (mb, mono_get_int_type ());
  933. if (!MONO_TYPE_IS_VOID (sig->ret))
  934. retval = mono_mb_add_local (mb, sig->ret);
  935. // get the type for the interface the method is defined on
  936. // and then get the underlying COM interface for that type
  937. mono_mb_emit_ldarg (mb, 0);
  938. mono_mb_emit_ptr (mb, method);
  939. mono_mb_emit_icall (mb, cominterop_get_method_interface);
  940. mono_mb_emit_icall (mb, cominterop_get_interface);
  941. mono_mb_emit_stloc (mb, ptr_this);
  942. // arg 1 is unmanaged this pointer
  943. mono_mb_emit_ldloc (mb, ptr_this);
  944. // load args
  945. for (i = 1; i <= sig->param_count; i++)
  946. mono_mb_emit_ldarg (mb, i);
  947. // push managed return value as byref last argument
  948. if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
  949. mono_mb_emit_ldloc_addr (mb, retval);
  950. adjusted_method = cominterop_get_native_wrapper_adjusted (method);
  951. mono_mb_emit_managed_call (mb, adjusted_method, NULL);
  952. if (!preserve_sig) {
  953. MONO_STATIC_POINTER_INIT (MonoMethod, ThrowExceptionForHR)
  954. ERROR_DECL (error);
  955. ThrowExceptionForHR = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "ThrowExceptionForHR", 1, 0, error);
  956. mono_error_assert_ok (error);
  957. MONO_STATIC_POINTER_INIT_END (MonoMethod, ThrowExceptionForHR)
  958. mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
  959. // load return value managed is expecting
  960. if (!MONO_TYPE_IS_VOID (sig->ret))
  961. mono_mb_emit_ldloc (mb, retval);
  962. }
  963. mono_mb_emit_byte (mb, CEE_RET);
  964. }
  965. }
  966. /* Does this case ever get hit? */
  967. else {
  968. char *msg = g_strdup ("non imported interfaces on \
  969. imported classes is not yet implemented.");
  970. mono_mb_emit_exception (mb, "NotSupportedException", msg);
  971. }
  972. #endif /* DISABLE_JIT */
  973. csig = mono_metadata_signature_dup_full (m_class_get_image (method->klass), sig);
  974. csig->pinvoke = 0;
  975. res = mono_mb_create_and_cache (cache, method,
  976. mb, csig, csig->param_count + 16);
  977. mono_mb_free (mb);
  978. return res;
  979. }
  980. /**
  981. * mono_cominterop_get_invoke:
  982. * \param method managed method
  983. * \returns the generated method that calls the underlying \c __ComObject
  984. * rather than the proxy object.
  985. */
  986. MonoMethod *
  987. mono_cominterop_get_invoke (MonoMethod *method)
  988. {
  989. MonoMethodSignature *sig;
  990. MonoMethodBuilder *mb;
  991. MonoMethod *res;
  992. int i;
  993. GHashTable* cache;
  994. cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
  995. g_assert (method);
  996. if ((res = mono_marshal_find_in_cache (cache, method)))
  997. return res;
  998. sig = mono_signature_no_pinvoke (method);
  999. /* we cant remote methods without this pointer */
  1000. if (!sig->hasthis)
  1001. return method;
  1002. mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
  1003. #ifndef DISABLE_JIT
  1004. /* get real proxy object, which is a ComInteropProxy in this case*/
  1005. mono_mb_add_local (mb, mono_get_object_type ());
  1006. mono_mb_emit_ldarg (mb, 0);
  1007. mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
  1008. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  1009. /* load the RCW from the ComInteropProxy*/
  1010. mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
  1011. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  1012. /* load args and make the call on the RCW */
  1013. for (i = 1; i <= sig->param_count; i++)
  1014. mono_mb_emit_ldarg (mb, i);
  1015. if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || mono_class_is_interface (method->klass)) {
  1016. MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
  1017. mono_mb_emit_managed_call (mb, native_wrapper, NULL);
  1018. }
  1019. else {
  1020. if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
  1021. mono_mb_emit_op (mb, CEE_CALLVIRT, method);
  1022. else
  1023. mono_mb_emit_op (mb, CEE_CALL, method);
  1024. }
  1025. if (!strcmp(method->name, ".ctor")) {
  1026. MONO_STATIC_POINTER_INIT (MonoMethod, cache_proxy)
  1027. ERROR_DECL (error);
  1028. cache_proxy = mono_class_get_method_from_name_checked (mono_class_get_interop_proxy_class (), "CacheProxy", 0, 0, error);
  1029. mono_error_assert_ok (error);
  1030. MONO_STATIC_POINTER_INIT_END (MonoMethod, cache_proxy)
  1031. mono_mb_emit_ldarg (mb, 0);
  1032. mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
  1033. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  1034. mono_mb_emit_managed_call (mb, cache_proxy, NULL);
  1035. }
  1036. mono_marshal_emit_thread_interrupt_checkpoint (mb);
  1037. mono_mb_emit_byte (mb, CEE_RET);
  1038. #endif /* DISABLE_JIT */
  1039. res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
  1040. mono_mb_free (mb);
  1041. return res;
  1042. }
  1043. /* Maps a managed object to its unmanaged representation
  1044. * i.e. it's COM Callable Wrapper (CCW).
  1045. * Key: MonoObject*
  1046. * Value: MonoCCW*
  1047. */
  1048. static GHashTable* ccw_hash = NULL;
  1049. /* Maps a CCW interface to it's containing CCW.
  1050. * Note that a CCW support many interfaces.
  1051. * Key: MonoCCW*
  1052. * Value: MonoCCWInterface*
  1053. */
  1054. static GHashTable* ccw_interface_hash = NULL;
  1055. /* Maps the IUnknown value of a RCW to
  1056. * it's MonoComInteropProxy*.
  1057. * Key: void*
  1058. * Value: gchandle
  1059. */
  1060. static GHashTable* rcw_hash = NULL;
  1061. static MonoMethod*
  1062. mono_get_addref (void)
  1063. {
  1064. MONO_STATIC_POINTER_INIT (MonoMethod, AddRef)
  1065. ERROR_DECL (error);
  1066. AddRef = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "AddRef", 1, 0, error);
  1067. mono_error_assert_ok (error);
  1068. MONO_STATIC_POINTER_INIT_END (MonoMethod, AddRef)
  1069. return AddRef;
  1070. }
  1071. int
  1072. mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
  1073. MonoType *t,
  1074. MonoMarshalSpec *spec,
  1075. int conv_arg, MonoType **conv_arg_type,
  1076. MarshalAction action)
  1077. {
  1078. MonoMethodBuilder *mb = m->mb;
  1079. MonoClass *klass = t->data.klass;
  1080. ERROR_DECL (error);
  1081. MONO_STATIC_POINTER_INIT (MonoMethod, get_object_for_iunknown)
  1082. get_object_for_iunknown = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetObjectForIUnknown", 1, 0, error);
  1083. mono_error_assert_ok (error);
  1084. MONO_STATIC_POINTER_INIT_END (MonoMethod, get_object_for_iunknown)
  1085. MONO_STATIC_POINTER_INIT (MonoMethod, get_iunknown_for_object_internal)
  1086. get_iunknown_for_object_internal = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1, 0, error);
  1087. mono_error_assert_ok (error);
  1088. MONO_STATIC_POINTER_INIT_END (MonoMethod, get_iunknown_for_object_internal)
  1089. MONO_STATIC_POINTER_INIT (MonoMethod, get_idispatch_for_object_internal)
  1090. get_idispatch_for_object_internal = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1, 0, error);
  1091. mono_error_assert_ok (error);
  1092. MONO_STATIC_POINTER_INIT_END (MonoMethod, get_idispatch_for_object_internal)
  1093. MONO_STATIC_POINTER_INIT (MonoMethod, get_com_interface_for_object_internal)
  1094. get_com_interface_for_object_internal = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2, 0, error);
  1095. mono_error_assert_ok (error);
  1096. MONO_STATIC_POINTER_INIT_END (MonoMethod, get_com_interface_for_object_internal)
  1097. MONO_STATIC_POINTER_INIT (MonoMethod, marshal_release)
  1098. marshal_release = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "Release", 1, 0, error);
  1099. mono_error_assert_ok (error);
  1100. MONO_STATIC_POINTER_INIT_END (MonoMethod, marshal_release)
  1101. #ifdef DISABLE_JIT
  1102. switch (action) {
  1103. case MARSHAL_ACTION_CONV_IN:
  1104. *conv_arg_type = mono_get_int_type ();
  1105. break;
  1106. case MARSHAL_ACTION_MANAGED_CONV_IN:
  1107. *conv_arg_type = mono_get_int_type ();
  1108. break;
  1109. default:
  1110. break;
  1111. }
  1112. #else
  1113. switch (action) {
  1114. case MARSHAL_ACTION_CONV_IN: {
  1115. guint32 pos_null = 0;
  1116. MonoType *int_type = mono_get_int_type ();
  1117. *conv_arg_type = int_type;
  1118. conv_arg = mono_mb_add_local (mb, int_type);
  1119. mono_mb_emit_ptr (mb, NULL);
  1120. mono_mb_emit_stloc (mb, conv_arg);
  1121. /* we dont need any conversions for out parameters */
  1122. if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
  1123. break;
  1124. mono_mb_emit_ldarg (mb, argnum);
  1125. if (t->byref)
  1126. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  1127. /* if null just break, conv arg was already inited to 0 */
  1128. pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  1129. mono_mb_emit_ldarg (mb, argnum);
  1130. if (t->byref)
  1131. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  1132. if (klass && klass != mono_defaults.object_class) {
  1133. mono_mb_emit_ptr (mb, t);
  1134. mono_mb_emit_icall (mb, cominterop_type_from_handle);
  1135. mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
  1136. }
  1137. else if (spec->native == MONO_NATIVE_IUNKNOWN)
  1138. mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
  1139. else if (spec->native == MONO_NATIVE_IDISPATCH)
  1140. mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
  1141. else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
  1142. mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
  1143. else
  1144. g_assert_not_reached ();
  1145. mono_mb_emit_stloc (mb, conv_arg);
  1146. mono_mb_patch_short_branch (mb, pos_null);
  1147. break;
  1148. }
  1149. case MARSHAL_ACTION_CONV_OUT: {
  1150. if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
  1151. int ccw_obj;
  1152. guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
  1153. ccw_obj = mono_mb_add_local (mb, mono_get_object_type ());
  1154. mono_mb_emit_ldarg (mb, argnum);
  1155. mono_mb_emit_byte (mb, CEE_LDNULL);
  1156. mono_mb_emit_byte (mb, CEE_STIND_REF);
  1157. mono_mb_emit_ldloc (mb, conv_arg);
  1158. pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  1159. mono_mb_emit_ldloc (mb, conv_arg);
  1160. mono_mb_emit_icon (mb, TRUE);
  1161. mono_mb_emit_icall (mb, cominterop_get_ccw_object);
  1162. mono_mb_emit_stloc (mb, ccw_obj);
  1163. mono_mb_emit_ldloc (mb, ccw_obj);
  1164. pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
  1165. mono_mb_emit_ldarg (mb, argnum);
  1166. mono_mb_emit_ldloc (mb, conv_arg);
  1167. mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
  1168. if (klass && klass != mono_defaults.object_class)
  1169. mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
  1170. mono_mb_emit_byte (mb, CEE_STIND_REF);
  1171. pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
  1172. /* is already managed object */
  1173. mono_mb_patch_short_branch (mb, pos_ccw);
  1174. mono_mb_emit_ldarg (mb, argnum);
  1175. mono_mb_emit_ldloc (mb, ccw_obj);
  1176. if (klass && klass != mono_defaults.object_class)
  1177. mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
  1178. mono_mb_emit_byte (mb, CEE_STIND_REF);
  1179. mono_mb_patch_short_branch (mb, pos_end);
  1180. /* need to call Release to follow COM rules of ownership */
  1181. mono_mb_emit_ldloc (mb, conv_arg);
  1182. mono_mb_emit_managed_call (mb, marshal_release, NULL);
  1183. mono_mb_emit_byte (mb, CEE_POP);
  1184. /* case if null */
  1185. mono_mb_patch_short_branch (mb, pos_null);
  1186. }
  1187. break;
  1188. }
  1189. case MARSHAL_ACTION_PUSH:
  1190. if (t->byref)
  1191. mono_mb_emit_ldloc_addr (mb, conv_arg);
  1192. else
  1193. mono_mb_emit_ldloc (mb, conv_arg);
  1194. break;
  1195. case MARSHAL_ACTION_CONV_RESULT: {
  1196. int ccw_obj, ret_ptr;
  1197. guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
  1198. ccw_obj = mono_mb_add_local (mb, mono_get_object_type ());
  1199. ret_ptr = mono_mb_add_local (mb, mono_get_int_type ());
  1200. /* store return value */
  1201. mono_mb_emit_stloc (mb, ret_ptr);
  1202. mono_mb_emit_ldloc (mb, ret_ptr);
  1203. pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  1204. mono_mb_emit_ldloc (mb, ret_ptr);
  1205. mono_mb_emit_icon (mb, TRUE);
  1206. mono_mb_emit_icall (mb, cominterop_get_ccw_object);
  1207. mono_mb_emit_stloc (mb, ccw_obj);
  1208. mono_mb_emit_ldloc (mb, ccw_obj);
  1209. pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
  1210. mono_mb_emit_ldloc (mb, ret_ptr);
  1211. mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
  1212. if (klass && klass != mono_defaults.object_class)
  1213. mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
  1214. mono_mb_emit_stloc (mb, 3);
  1215. pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
  1216. /* is already managed object */
  1217. mono_mb_patch_short_branch (mb, pos_ccw);
  1218. mono_mb_emit_ldloc (mb, ccw_obj);
  1219. if (klass && klass != mono_defaults.object_class)
  1220. mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
  1221. mono_mb_emit_stloc (mb, 3);
  1222. mono_mb_patch_short_branch (mb, pos_end);
  1223. /* need to call Release to follow COM rules of ownership */
  1224. mono_mb_emit_ldloc (mb, ret_ptr);
  1225. mono_mb_emit_managed_call (mb, marshal_release, NULL);
  1226. mono_mb_emit_byte (mb, CEE_POP);
  1227. /* case if null */
  1228. mono_mb_patch_short_branch (mb, pos_null);
  1229. break;
  1230. }
  1231. case MARSHAL_ACTION_MANAGED_CONV_IN: {
  1232. int ccw_obj;
  1233. guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
  1234. ccw_obj = mono_mb_add_local (mb, mono_get_object_type ());
  1235. klass = mono_class_from_mono_type_internal (t);
  1236. conv_arg = mono_mb_add_local (mb, m_class_get_byval_arg (klass));
  1237. *conv_arg_type = mono_get_int_type ();
  1238. mono_mb_emit_byte (mb, CEE_LDNULL);
  1239. mono_mb_emit_stloc (mb, conv_arg);
  1240. if (t->attrs & PARAM_ATTRIBUTE_OUT)
  1241. break;
  1242. mono_mb_emit_ldarg (mb, argnum);
  1243. if (t->byref)
  1244. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  1245. pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  1246. mono_mb_emit_ldarg (mb, argnum);
  1247. if (t->byref)
  1248. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  1249. mono_mb_emit_icon (mb, TRUE);
  1250. mono_mb_emit_icall (mb, cominterop_get_ccw_object);
  1251. mono_mb_emit_stloc (mb, ccw_obj);
  1252. mono_mb_emit_ldloc (mb, ccw_obj);
  1253. pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
  1254. mono_mb_emit_ldarg (mb, argnum);
  1255. if (t->byref)
  1256. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  1257. mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
  1258. if (klass && klass != mono_defaults.object_class)
  1259. mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
  1260. mono_mb_emit_stloc (mb, conv_arg);
  1261. pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
  1262. /* is already managed object */
  1263. mono_mb_patch_short_branch (mb, pos_ccw);
  1264. mono_mb_emit_ldloc (mb, ccw_obj);
  1265. if (klass && klass != mono_defaults.object_class)
  1266. mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
  1267. mono_mb_emit_stloc (mb, conv_arg);
  1268. mono_mb_patch_short_branch (mb, pos_end);
  1269. /* case if null */
  1270. mono_mb_patch_short_branch (mb, pos_null);
  1271. break;
  1272. }
  1273. case MARSHAL_ACTION_MANAGED_CONV_OUT: {
  1274. if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
  1275. guint32 pos_null = 0;
  1276. mono_mb_emit_ldarg (mb, argnum);
  1277. mono_mb_emit_byte (mb, CEE_LDC_I4_0);
  1278. mono_mb_emit_byte (mb, CEE_STIND_I);
  1279. mono_mb_emit_ldloc (mb, conv_arg);
  1280. pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  1281. /* to store later */
  1282. mono_mb_emit_ldarg (mb, argnum);
  1283. mono_mb_emit_ldloc (mb, conv_arg);
  1284. if (klass && klass != mono_defaults.object_class) {
  1285. mono_mb_emit_ptr (mb, t);
  1286. mono_mb_emit_icall (mb, cominterop_type_from_handle);
  1287. mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
  1288. }
  1289. else if (spec->native == MONO_NATIVE_IUNKNOWN)
  1290. mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
  1291. else if (spec->native == MONO_NATIVE_IDISPATCH)
  1292. mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
  1293. else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
  1294. mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
  1295. else
  1296. g_assert_not_reached ();
  1297. mono_mb_emit_byte (mb, CEE_STIND_I);
  1298. mono_mb_emit_ldarg (mb, argnum);
  1299. mono_mb_emit_byte (mb, CEE_LDIND_I);
  1300. mono_mb_emit_managed_call (mb, mono_get_addref (), NULL);
  1301. mono_mb_emit_byte (mb, CEE_POP);
  1302. mono_mb_patch_short_branch (mb, pos_null);
  1303. }
  1304. break;
  1305. }
  1306. case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
  1307. guint32 pos_null = 0;
  1308. int ccw_obj;
  1309. ccw_obj = mono_mb_add_local (mb, mono_get_object_type ());
  1310. /* store return value */
  1311. mono_mb_emit_stloc (mb, ccw_obj);
  1312. mono_mb_emit_ldloc (mb, ccw_obj);
  1313. /* if null just break, conv arg was already inited to 0 */
  1314. pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  1315. /* to store later */
  1316. mono_mb_emit_ldloc (mb, ccw_obj);
  1317. if (klass && klass != mono_defaults.object_class) {
  1318. mono_mb_emit_ptr (mb, t);
  1319. mono_mb_emit_icall (mb, cominterop_type_from_handle);
  1320. mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
  1321. }
  1322. else if (spec->native == MONO_NATIVE_IUNKNOWN)
  1323. mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
  1324. else if (spec->native == MONO_NATIVE_IDISPATCH)
  1325. mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
  1326. else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
  1327. mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
  1328. else
  1329. g_assert_not_reached ();
  1330. mono_mb_emit_stloc (mb, 3);
  1331. mono_mb_emit_ldloc (mb, 3);
  1332. mono_mb_emit_managed_call (mb, mono_get_addref (), NULL);
  1333. mono_mb_emit_byte (mb, CEE_POP);
  1334. mono_mb_patch_short_branch (mb, pos_null);
  1335. break;
  1336. }
  1337. default:
  1338. g_assert_not_reached ();
  1339. }
  1340. #endif /* DISABLE_JIT */
  1341. return conv_arg;
  1342. }
  1343. #define MONO_S_OK 0x00000000L
  1344. #define MONO_E_NOINTERFACE 0x80004002L
  1345. #define MONO_E_NOTIMPL 0x80004001L
  1346. #define MONO_E_INVALIDARG 0x80070057L
  1347. #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
  1348. #define MONO_E_DISPID_UNKNOWN (gint32)-1
  1349. int
  1350. ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown *pUnk)
  1351. {
  1352. return mono_IUnknown_AddRef (pUnk);
  1353. }
  1354. int
  1355. ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown *pUnk, gconstpointer riid, gpointer* ppv)
  1356. {
  1357. return mono_IUnknown_QueryInterface (pUnk, riid, ppv);
  1358. }
  1359. int
  1360. ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown *pUnk)
  1361. {
  1362. g_assert (pUnk);
  1363. return mono_IUnknown_Release (pUnk);
  1364. }
  1365. static gboolean
  1366. cominterop_can_support_dispatch (MonoClass* klass)
  1367. {
  1368. if (!mono_class_is_public (klass))
  1369. return FALSE;
  1370. if (!cominterop_com_visible (klass))
  1371. return FALSE;
  1372. return TRUE;
  1373. }
  1374. void*
  1375. ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObjectHandle object, MonoError *error)
  1376. {
  1377. return mono_cominterop_get_com_interface_internal (TRUE, object, NULL, error);
  1378. }
  1379. MonoObjectHandle
  1380. ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk, MonoError *error)
  1381. {
  1382. #ifndef DISABLE_COM
  1383. /* see if it is a CCW */
  1384. return pUnk ? cominterop_get_ccw_handle ((MonoCCWInterface*)pUnk, TRUE) : NULL_HANDLE;
  1385. #else
  1386. g_assert_not_reached ();
  1387. #endif
  1388. }
  1389. void*
  1390. ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObjectHandle object, MonoError *error)
  1391. {
  1392. #ifndef DISABLE_COM
  1393. if (MONO_HANDLE_IS_NULL (object))
  1394. return NULL;
  1395. MonoRealProxyHandle real_proxy;
  1396. if (cominterop_object_is_rcw_handle (object, &real_proxy)) {
  1397. MonoComInteropProxyHandle com_interop_proxy = MONO_HANDLE_CAST (MonoComInteropProxy, real_proxy);
  1398. MonoComObjectHandle com_object = MONO_HANDLE_NEW_GET (MonoComObject, com_interop_proxy, com_object);
  1399. return cominterop_get_interface_checked (com_object, mono_class_get_idispatch_class (), error);
  1400. }
  1401. else if (!cominterop_can_support_dispatch (mono_handle_class (object)) ) {
  1402. cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
  1403. return NULL;
  1404. }
  1405. return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
  1406. #else
  1407. g_assert_not_reached ();
  1408. #endif
  1409. }
  1410. void*
  1411. ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObjectHandle object, MonoReflectionTypeHandle ref_type, MonoError *error)
  1412. {
  1413. #ifndef DISABLE_COM
  1414. g_assert (!MONO_HANDLE_IS_NULL (ref_type));
  1415. MonoType * const type = MONO_HANDLE_GETVAL (ref_type, type);
  1416. g_assert (type);
  1417. MonoClass * klass = mono_type_get_class_internal (type);
  1418. g_assert (klass);
  1419. if (!mono_class_init_checked (klass, error))
  1420. return NULL;
  1421. MonoCustomAttrInfo *cinfo = mono_custom_attrs_from_class_checked (klass, error);
  1422. mono_error_assert_ok (error);
  1423. if (cinfo) {
  1424. MonoReflectionComDefaultInterfaceAttribute *attr = (MonoReflectionComDefaultInterfaceAttribute *)
  1425. mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_com_default_interface_attribute_class (), error);
  1426. mono_error_assert_ok (error); /*FIXME proper error handling*/
  1427. if (attr) {
  1428. MonoType *def_itf = attr->type->type;
  1429. if (def_itf->type == MONO_TYPE_CLASS)
  1430. klass = mono_type_get_class_internal (def_itf);
  1431. }
  1432. if (!cinfo->cached)
  1433. mono_custom_attrs_free (cinfo);
  1434. }
  1435. return cominterop_get_ccw_checked (object, klass, error);
  1436. #else
  1437. g_assert_not_reached ();
  1438. #endif
  1439. }
  1440. MonoBoolean
  1441. ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObjectHandle object, MonoError *error)
  1442. {
  1443. #ifndef DISABLE_COM
  1444. MonoRealProxyHandle real_proxy;
  1445. return (MonoBoolean)cominterop_object_is_rcw_handle (object, &real_proxy);
  1446. #else
  1447. g_assert_not_reached ();
  1448. #endif
  1449. }
  1450. gint32
  1451. ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObjectHandle object, MonoError *error)
  1452. {
  1453. #ifndef DISABLE_COM
  1454. g_assert (!MONO_HANDLE_IS_NULL (object));
  1455. MonoRealProxyHandle real_proxy;
  1456. gboolean const is_rcw = cominterop_object_is_rcw_handle (object, &real_proxy);
  1457. g_assert (is_rcw);
  1458. MonoComInteropProxyHandle proxy = MONO_HANDLE_CAST (MonoComInteropProxy, real_proxy);
  1459. g_assert (!MONO_HANDLE_IS_NULL (proxy));
  1460. if (MONO_HANDLE_GETVAL (proxy, ref_count) == 0)
  1461. return -1;
  1462. gint32 ref_count = mono_atomic_dec_i32 (&MONO_HANDLE_GETVAL (proxy, ref_count));
  1463. g_assert (ref_count >= 0);
  1464. if (ref_count == 0)
  1465. mono_System_ComObject_ReleaseInterfaces (MONO_HANDLE_NEW_GET (MonoComObject, proxy, com_object));
  1466. return ref_count;
  1467. #else
  1468. g_assert_not_reached ();
  1469. #endif
  1470. }
  1471. guint32
  1472. ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethodHandle m, MonoError *error)
  1473. {
  1474. #ifndef DISABLE_COM
  1475. int const slot = cominterop_get_com_slot_for_method (MONO_HANDLE_GETVAL (m, method), error);
  1476. mono_error_assert_ok (error);
  1477. return slot;
  1478. #else
  1479. g_assert_not_reached ();
  1480. #endif
  1481. }
  1482. /* Only used for COM RCWs */
  1483. MonoObjectHandle
  1484. ves_icall_System_ComObject_CreateRCW (MonoReflectionTypeHandle ref_type, MonoError *error)
  1485. {
  1486. MonoDomain * const domain = MONO_HANDLE_DOMAIN (ref_type);
  1487. MonoType * const type = MONO_HANDLE_GETVAL (ref_type, type);
  1488. MonoClass * const klass = mono_class_from_mono_type_internal (type);
  1489. /* Call mono_object_new_alloc_by_vtable instead of mono_object_new_by_vtable
  1490. * because we want to actually create object. mono_object_new_by_vtable checks
  1491. * to see if type is import and creates transparent proxy. This method
  1492. * is called by the corresponding real proxy to create the real RCW.
  1493. * Constructor does not need to be called. Will be called later.
  1494. */
  1495. MonoVTable *vtable = mono_class_vtable_checked (domain, klass, error);
  1496. return_val_if_nok (error, NULL_HANDLE);
  1497. return mono_object_new_alloc_by_vtable (vtable, error);
  1498. }
  1499. static gboolean
  1500. cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
  1501. {
  1502. mono_IUnknown_Release ((MonoIUnknown*)value);
  1503. return TRUE;
  1504. }
  1505. void
  1506. mono_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj)
  1507. {
  1508. g_assert (!MONO_HANDLE_IS_NULL (obj));
  1509. if (!MONO_HANDLE_GETVAL (obj, itf_hash))
  1510. return;
  1511. mono_cominterop_lock ();
  1512. MonoGCHandle gchandle = (MonoGCHandle)g_hash_table_lookup (rcw_hash, MONO_HANDLE_GETVAL (obj, iunknown));
  1513. if (gchandle) {
  1514. mono_gchandle_free_internal (gchandle);
  1515. g_hash_table_remove (rcw_hash, MONO_HANDLE_GETVAL (obj, iunknown));
  1516. }
  1517. g_hash_table_foreach_remove (MONO_HANDLE_GETVAL (obj, itf_hash), cominterop_rcw_interface_finalizer, NULL);
  1518. g_hash_table_destroy (MONO_HANDLE_GETVAL (obj, itf_hash));
  1519. mono_IUnknown_Release (MONO_HANDLE_GETVAL (obj, iunknown));
  1520. MONO_HANDLE_SETVAL (obj, iunknown, MonoIUnknown*, NULL);
  1521. MONO_HANDLE_SETVAL (obj, itf_hash, GHashTable*, NULL);
  1522. mono_cominterop_unlock ();
  1523. }
  1524. void
  1525. ves_icall_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj, MonoError *error)
  1526. {
  1527. mono_System_ComObject_ReleaseInterfaces (obj);
  1528. }
  1529. static gboolean
  1530. cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
  1531. {
  1532. MonoGCHandle gchandle = NULL;
  1533. gchandle = (MonoGCHandle)value;
  1534. if (gchandle) {
  1535. MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target_internal (gchandle);
  1536. if (proxy) {
  1537. if (proxy->com_object->itf_hash) {
  1538. g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
  1539. g_hash_table_destroy (proxy->com_object->itf_hash);
  1540. }
  1541. mono_IUnknown_Release (proxy->com_object->iunknown);
  1542. proxy->com_object->iunknown = NULL;
  1543. proxy->com_object->itf_hash = NULL;
  1544. }
  1545. mono_gchandle_free_internal (gchandle);
  1546. }
  1547. return TRUE;
  1548. }
  1549. void
  1550. mono_cominterop_release_all_rcws (void)
  1551. {
  1552. #ifndef DISABLE_COM
  1553. if (!rcw_hash)
  1554. return;
  1555. mono_cominterop_lock ();
  1556. g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
  1557. g_hash_table_destroy (rcw_hash);
  1558. rcw_hash = NULL;
  1559. mono_cominterop_unlock ();
  1560. #endif
  1561. }
  1562. gpointer
  1563. ves_icall_System_ComObject_GetInterfaceInternal (MonoComObjectHandle obj, MonoReflectionTypeHandle ref_type, MonoBoolean throw_exception, MonoError *error)
  1564. {
  1565. #ifndef DISABLE_COM
  1566. MonoType * const type = MONO_HANDLE_GETVAL (ref_type, type);
  1567. MonoClass * const klass = mono_class_from_mono_type_internal (type);
  1568. if (!mono_class_init_checked (klass, error))
  1569. return NULL;
  1570. ERROR_DECL (error_ignored);
  1571. gpointer const itf = cominterop_get_interface_checked (obj, klass, throw_exception ? error : error_ignored);
  1572. mono_error_cleanup (error_ignored);
  1573. return itf;
  1574. #else
  1575. g_assert_not_reached ();
  1576. #endif
  1577. }
  1578. void
  1579. ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy *volatile* proxy_handle)
  1580. {
  1581. #ifndef DISABLE_COM
  1582. MonoGCHandle gchandle = mono_gchandle_new_weakref_internal ((MonoObject*)*proxy_handle, FALSE);
  1583. mono_cominterop_lock ();
  1584. if (!rcw_hash)
  1585. rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
  1586. g_hash_table_insert (rcw_hash, pUnk, gchandle);
  1587. mono_cominterop_unlock ();
  1588. #else
  1589. g_assert_not_reached ();
  1590. #endif
  1591. }
  1592. void
  1593. ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk, MonoComInteropProxy *volatile* proxy_handle)
  1594. {
  1595. *proxy_handle = NULL;
  1596. #ifndef DISABLE_COM
  1597. MonoGCHandle gchandle = NULL;
  1598. mono_cominterop_lock ();
  1599. if (rcw_hash)
  1600. gchandle = (MonoGCHandle)g_hash_table_lookup (rcw_hash, pUnk);
  1601. mono_cominterop_unlock ();
  1602. if (!gchandle)
  1603. return;
  1604. MonoComInteropProxy *proxy = (MonoComInteropProxy*)mono_gchandle_get_target_internal (gchandle);
  1605. // proxy_handle is assumed to be on the stack, so no barrier is needed.
  1606. *proxy_handle = proxy;
  1607. /* proxy is null means we need to free up old RCW */
  1608. if (!proxy) {
  1609. mono_gchandle_free_internal (gchandle);
  1610. g_hash_table_remove (rcw_hash, pUnk);
  1611. }
  1612. #else
  1613. g_assert_not_reached ();
  1614. #endif
  1615. }
  1616. /**
  1617. * cominterop_get_ccw_object:
  1618. * @ccw_entry: a pointer to the CCWEntry
  1619. * @verify: verify ccw_entry is in fact a ccw
  1620. *
  1621. * Returns: the corresponding object for the CCW
  1622. */
  1623. static MonoGCHandle
  1624. cominterop_get_ccw_gchandle (MonoCCWInterface* ccw_entry, gboolean verify)
  1625. {
  1626. /* no CCW's exist yet */
  1627. if (!ccw_interface_hash)
  1628. return 0;
  1629. MonoCCW * const ccw = verify ? (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry) : ccw_entry->ccw;
  1630. g_assert (verify || ccw);
  1631. return ccw ? ccw->gc_handle : 0;
  1632. }
  1633. static MonoObjectHandle
  1634. cominterop_get_ccw_handle (MonoCCWInterface* ccw_entry, gboolean verify)
  1635. {
  1636. MonoGCHandle const gchandle = cominterop_get_ccw_gchandle (ccw_entry, verify);
  1637. return gchandle ? mono_gchandle_get_target_handle (gchandle) : NULL_HANDLE;
  1638. }
  1639. static MonoObject*
  1640. cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
  1641. {
  1642. MonoGCHandle const gchandle = cominterop_get_ccw_gchandle (ccw_entry, verify);
  1643. return gchandle ? mono_gchandle_get_target_internal (gchandle) : NULL;
  1644. }
  1645. static MonoDomain*
  1646. cominterop_get_domain_for_appdomain (MonoAppDomain *ad_raw)
  1647. {
  1648. HANDLE_FUNCTION_ENTER ();
  1649. MONO_HANDLE_DCL (MonoAppDomain, ad);
  1650. MonoDomain * result = MONO_HANDLE_GETVAL (ad, data);
  1651. HANDLE_FUNCTION_RETURN_VAL (result);
  1652. }
  1653. static MonoObject*
  1654. cominterop_set_ccw_object_domain (MonoObject *object, MonoDomain **prev_domain)
  1655. {
  1656. MonoDomain *current = mono_domain_get (), *obj_domain;
  1657. if (mono_object_class (object) == mono_defaults.appdomain_class)
  1658. obj_domain = cominterop_get_domain_for_appdomain ((MonoAppDomain *)object);
  1659. else
  1660. obj_domain = mono_object_domain (object);
  1661. if (obj_domain != current) {
  1662. *prev_domain = current;
  1663. mono_domain_set_internal_with_options (obj_domain, FALSE);
  1664. }
  1665. else
  1666. *prev_domain = NULL;
  1667. return object;
  1668. }
  1669. static void
  1670. cominterop_restore_domain (MonoDomain *domain)
  1671. {
  1672. if (!domain)
  1673. return;
  1674. mono_domain_set_internal_with_options (domain, FALSE);
  1675. }
  1676. static void
  1677. cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
  1678. {
  1679. MonoMethodSignature *sig, *csig;
  1680. MonoImage *method_klass_image = m_class_get_image (method->klass);
  1681. sig = mono_method_signature_internal (method);
  1682. /* we copy the signature, so that we can modify it */
  1683. /* FIXME: which to use? */
  1684. csig = mono_metadata_signature_dup_full (method_klass_image, sig);
  1685. /* csig = mono_metadata_signature_dup (sig); */
  1686. /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
  1687. #ifdef HOST_WIN32
  1688. csig->call_convention = MONO_CALL_STDCALL;
  1689. #else
  1690. csig->call_convention = MONO_CALL_C;
  1691. #endif
  1692. csig->hasthis = 0;
  1693. csig->pinvoke = 1;
  1694. m->image = method_klass_image;
  1695. m->piinfo = NULL;
  1696. m->retobj_var = 0;
  1697. m->sig = sig;
  1698. m->csig = csig;
  1699. }
  1700. static MonoMarshalSpec*
  1701. cominterop_get_ccw_default_mspec (const MonoType *param_type)
  1702. {
  1703. MonoMarshalVariant elem_type;
  1704. MonoMarshalNative native;
  1705. MonoMarshalSpec *result;
  1706. switch (param_type->type) {
  1707. case MONO_TYPE_OBJECT:
  1708. native = MONO_NATIVE_STRUCT;
  1709. break;
  1710. case MONO_TYPE_STRING:
  1711. native = MONO_NATIVE_BSTR;
  1712. break;
  1713. case MONO_TYPE_CLASS:
  1714. native = MONO_NATIVE_INTERFACE;
  1715. break;
  1716. case MONO_TYPE_BOOLEAN:
  1717. native = MONO_NATIVE_VARIANTBOOL;
  1718. break;
  1719. case MONO_TYPE_SZARRAY:
  1720. /* object[] -> SAFEARRAY(VARIANT) */
  1721. native = MONO_NATIVE_SAFEARRAY;
  1722. if (param_type->data.array->eklass == mono_defaults.object_class)
  1723. elem_type = MONO_VARIANT_VARIANT;
  1724. else
  1725. return NULL;
  1726. break;
  1727. default:
  1728. return NULL;
  1729. }
  1730. result = g_new0 (MonoMarshalSpec, 1);
  1731. result->native = native;
  1732. if (native == MONO_NATIVE_SAFEARRAY)
  1733. result->data.safearray_data.elem_type = elem_type;
  1734. return result;
  1735. }
  1736. static MonoClass*
  1737. cominterop_get_default_iface (MonoClass *klass)
  1738. {
  1739. if (mono_class_is_interface (klass))
  1740. return klass;
  1741. ERROR_DECL (error);
  1742. MonoCustomAttrInfo *cinfo = mono_custom_attrs_from_class_checked (klass, error);
  1743. mono_error_assert_ok (error);
  1744. if (!cinfo)
  1745. return mono_class_get_idispatch_class ();
  1746. MonoClassInterfaceAttribute *class_attr = (MonoClassInterfaceAttribute *)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_class_interface_attribute_class (), error);
  1747. MonoClass *ret;
  1748. if (class_attr)
  1749. {
  1750. if (class_attr->intType == 0) {
  1751. ret = mono_defaults.object_class;
  1752. for (guint16 i = 0; i < m_class_get_interface_count (klass); i++) {
  1753. MonoClass *iface = m_class_get_interfaces (klass) [i];
  1754. if (cominterop_com_visible (iface)) {
  1755. ret = iface;
  1756. break;
  1757. }
  1758. }
  1759. }
  1760. else if (class_attr->intType == 1)
  1761. ret = mono_class_get_idispatch_class ();
  1762. else
  1763. ret = klass;
  1764. } else
  1765. ret = mono_class_get_idispatch_class ();
  1766. if (!cinfo->cached)
  1767. mono_custom_attrs_free (cinfo);
  1768. return ret;
  1769. }
  1770. static gboolean
  1771. cominterop_class_method_is_visible (MonoMethod *method)
  1772. {
  1773. guint16 flags = method->flags;
  1774. if ((flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) != METHOD_ATTRIBUTE_PUBLIC)
  1775. return FALSE;
  1776. if (flags & METHOD_ATTRIBUTE_STATIC)
  1777. return FALSE;
  1778. if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME)
  1779. return FALSE;
  1780. if (!mono_cominterop_method_com_visible (method))
  1781. return FALSE;
  1782. /* if the method is an override, ignore it and use the original definition */
  1783. if ((flags & METHOD_ATTRIBUTE_VIRTUAL) && !(flags & METHOD_ATTRIBUTE_NEW_SLOT))
  1784. return FALSE;
  1785. return TRUE;
  1786. }
  1787. static gpointer
  1788. cominterop_get_ccw_method (MonoClass *iface, MonoMethod *method, MonoError *error)
  1789. {
  1790. int param_index = 0;
  1791. MonoMethodBuilder *mb;
  1792. MonoMarshalSpec ** mspecs;
  1793. MonoMethod *wrapper_method, *adjust_method;
  1794. MonoMethodSignature* sig_adjusted;
  1795. MonoMethodSignature* sig = mono_method_signature_internal (method);
  1796. gboolean const preserve_sig = (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) != 0;
  1797. EmitMarshalContext m;
  1798. mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
  1799. adjust_method = cominterop_get_managed_wrapper_adjusted (method);
  1800. sig_adjusted = mono_method_signature_internal (adjust_method);
  1801. mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
  1802. mono_method_get_marshal_info (method, mspecs);
  1803. /* move managed args up one */
  1804. for (param_index = sig->param_count; param_index >= 1; param_index--) {
  1805. int mspec_index = param_index+1;
  1806. mspecs [mspec_index] = mspecs [param_index];
  1807. if (mspecs[mspec_index] == NULL) {
  1808. mspecs[mspec_index] = cominterop_get_ccw_default_mspec (sig_adjusted->params[param_index]);
  1809. } else {
  1810. /* increase SizeParamIndex since we've added a param */
  1811. if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
  1812. sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
  1813. if (mspecs[mspec_index]->data.array_data.param_num != -1)
  1814. mspecs[mspec_index]->data.array_data.param_num++;
  1815. }
  1816. }
  1817. /* first arg is IntPtr for interface */
  1818. mspecs [1] = NULL;
  1819. /* move return spec to last param */
  1820. if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
  1821. if (mspecs [0] == NULL)
  1822. mspecs[0] = cominterop_get_ccw_default_mspec (sig_adjusted->params[sig_adjusted->param_count-1]);
  1823. mspecs [sig_adjusted->param_count] = mspecs [0];
  1824. mspecs [0] = NULL;
  1825. }
  1826. #ifndef DISABLE_JIT
  1827. /* skip visiblity since we call internal methods */
  1828. mb->skip_visibility = TRUE;
  1829. #endif
  1830. cominterop_setup_marshal_context (&m, adjust_method);
  1831. m.mb = mb;
  1832. mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
  1833. mono_cominterop_lock ();
  1834. wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
  1835. mono_cominterop_unlock ();
  1836. gpointer ret = mono_compile_method_checked (wrapper_method, error);
  1837. mono_mb_free (mb);
  1838. for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
  1839. if (mspecs [param_index])
  1840. mono_metadata_free_marshal_spec (mspecs [param_index]);
  1841. g_free (mspecs);
  1842. return ret;
  1843. }
  1844. /**
  1845. * cominterop_get_ccw_checked:
  1846. * @object: a pointer to the object
  1847. * @itf: interface type needed
  1848. * @error: set on error
  1849. *
  1850. * Returns: a value indicating if the object is a
  1851. * Runtime Callable Wrapper (RCW) for a COM object.
  1852. * On failure returns NULL and sets @error.
  1853. */
  1854. static gpointer
  1855. cominterop_get_ccw_checked (MonoObjectHandle object, MonoClass* itf, MonoError *error)
  1856. {
  1857. int i, j;
  1858. MonoCCW *ccw = NULL;
  1859. MonoCCWInterface* ccw_entry = NULL;
  1860. gpointer *vtable = NULL;
  1861. MonoClass* iface = NULL;
  1862. int start_slot = 3;
  1863. int method_count = 0;
  1864. GList *ccw_list, *ccw_list_item;
  1865. MonoCustomAttrInfo *cinfo = NULL;
  1866. if (MONO_HANDLE_IS_NULL (object))
  1867. return NULL;
  1868. MonoClass* klass = mono_handle_class (object);
  1869. mono_cominterop_lock ();
  1870. if (!ccw_hash)
  1871. ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
  1872. if (!ccw_interface_hash)
  1873. ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
  1874. ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)));
  1875. mono_cominterop_unlock ();
  1876. ccw_list_item = ccw_list;
  1877. while (ccw_list_item) {
  1878. MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
  1879. if (mono_gchandle_target_equal (ccw_iter->gc_handle, object)) {
  1880. ccw = ccw_iter;
  1881. break;
  1882. }
  1883. ccw_list_item = g_list_next(ccw_list_item);
  1884. }
  1885. if (!ccw) {
  1886. ccw = g_new0 (MonoCCW, 1);
  1887. #ifdef HOST_WIN32
  1888. ccw->free_marshaler = 0;
  1889. #endif
  1890. ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
  1891. ccw->ref_count = 0;
  1892. /* just alloc a weak handle until we are addref'd*/
  1893. ccw->gc_handle = mono_gchandle_new_weakref_from_handle (object);
  1894. if (!ccw_list) {
  1895. ccw_list = g_list_alloc ();
  1896. ccw_list->data = ccw;
  1897. }
  1898. else
  1899. ccw_list = g_list_append (ccw_list, ccw);
  1900. mono_cominterop_lock ();
  1901. g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)), ccw_list);
  1902. mono_cominterop_unlock ();
  1903. /* register for finalization to clean up ccw */
  1904. mono_object_register_finalizer_handle (object);
  1905. }
  1906. cinfo = mono_custom_attrs_from_class_checked (itf, error);
  1907. mono_error_assert_ok (error);
  1908. if (cinfo) {
  1909. MONO_STATIC_POINTER_INIT (MonoClass, coclass_attribute)
  1910. coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
  1911. MONO_STATIC_POINTER_INIT_END (MonoClass, coclass_attribute)
  1912. if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
  1913. g_assert(m_class_get_interface_count (itf) && m_class_get_interfaces (itf)[0]);
  1914. itf = m_class_get_interfaces (itf)[0];
  1915. }
  1916. if (!cinfo->cached)
  1917. mono_custom_attrs_free (cinfo);
  1918. }
  1919. iface = cominterop_get_default_iface(itf);
  1920. if (iface == mono_class_get_iunknown_class ()) {
  1921. start_slot = 3;
  1922. }
  1923. else if (iface == mono_class_get_idispatch_class ()) {
  1924. start_slot = 7;
  1925. }
  1926. else if (mono_class_is_interface (iface)) {
  1927. method_count += mono_class_get_method_count (iface);
  1928. start_slot = cominterop_get_com_slot_begin (iface);
  1929. }
  1930. else {
  1931. /* auto-dual object */
  1932. start_slot = 7;
  1933. MonoClass *klass_iter;
  1934. for (klass_iter = iface; klass_iter; klass_iter = m_class_get_parent (klass_iter)) {
  1935. int mcount = mono_class_get_method_count (klass_iter);
  1936. if (mcount && !m_class_get_methods (klass_iter))
  1937. mono_class_setup_methods (klass_iter);
  1938. for (i = 0; i < mcount; ++i) {
  1939. MonoMethod *method = m_class_get_methods (klass_iter) [i];
  1940. if (cominterop_class_method_is_visible (method))
  1941. ++method_count;
  1942. }
  1943. /* FIXME: accessors for public fields */
  1944. }
  1945. }
  1946. ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
  1947. if (!ccw_entry) {
  1948. int vtable_index = method_count-1+start_slot;
  1949. vtable = (void **)mono_image_alloc0 (m_class_get_image (klass), sizeof (gpointer)*(method_count+start_slot));
  1950. vtable [0] = (gpointer)cominterop_ccw_queryinterface;
  1951. vtable [1] = (gpointer)cominterop_ccw_addref;
  1952. vtable [2] = (gpointer)cominterop_ccw_release;
  1953. if (start_slot == 7) {
  1954. vtable [3] = (gpointer)cominterop_ccw_get_type_info_count;
  1955. vtable [4] = (gpointer)cominterop_ccw_get_type_info;
  1956. vtable [5] = (gpointer)cominterop_ccw_get_ids_of_names;
  1957. vtable [6] = (gpointer)cominterop_ccw_invoke;
  1958. }
  1959. if (mono_class_is_interface (iface)) {
  1960. if (method_count && !m_class_get_methods (iface))
  1961. mono_class_setup_methods (iface);
  1962. for (i = method_count - 1; i >= 0; i--) {
  1963. vtable [vtable_index--] = cominterop_get_ccw_method (iface, m_class_get_methods (iface) [i], error);
  1964. return_val_if_nok (error, NULL);
  1965. }
  1966. }
  1967. else {
  1968. /* Auto-dual object. The methods on an auto-dual interface are
  1969. * exposed starting from the innermost parent (i.e. Object) and
  1970. * proceeding outwards. The methods within each interfaces are
  1971. * exposed in the following order:
  1972. *
  1973. * 1. Virtual methods
  1974. * 2. Interface methods
  1975. * 3. Nonvirtual methods
  1976. * 4. Fields (get, then put)
  1977. *
  1978. * Interface methods are exposed in the order that the interface
  1979. * was declared. Child interface methods are exposed before parents.
  1980. *
  1981. * Because we need to expose superclass methods starting from the
  1982. * innermost parent, we expose methods in reverse order, so that
  1983. * we can just iterate using m_class_get_parent (). */
  1984. mono_class_setup_vtable (iface);
  1985. MonoClass *klass_iter;
  1986. for (klass_iter = iface; klass_iter; klass_iter = m_class_get_parent (klass_iter)) {
  1987. mono_class_setup_vtable (klass_iter);
  1988. /* 3. Nonvirtual methods */
  1989. for (i = mono_class_get_method_count (klass_iter) - 1; i >= 0; i--) {
  1990. MonoMethod *method = m_class_get_methods (klass_iter) [i];
  1991. if (cominterop_class_method_is_visible (method) && !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
  1992. vtable [vtable_index--] = cominterop_get_ccw_method (iface, method, error);
  1993. return_val_if_nok (error, NULL);
  1994. }
  1995. }
  1996. /* 2. Interface methods */
  1997. GPtrArray *ifaces = mono_class_get_implemented_interfaces (klass_iter, error);
  1998. mono_error_assert_ok (error);
  1999. if (ifaces) {
  2000. for (i = ifaces->len - 1; i >= 0; i--) {
  2001. MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
  2002. int offset = mono_class_interface_offset (iface, ic);
  2003. g_assert (offset >= 0);
  2004. for (j = mono_class_get_method_count (ic) - 1; j >= 0; j--) {
  2005. MonoMethod *method = m_class_get_methods (ic) [j];
  2006. vtable [vtable_index--] = cominterop_get_ccw_method (iface, m_class_get_vtable (iface) [offset + method->slot], error);
  2007. if (!is_ok (error)) {
  2008. g_ptr_array_free (ifaces, TRUE);
  2009. return NULL;
  2010. }
  2011. }
  2012. }
  2013. g_ptr_array_free (ifaces, TRUE);
  2014. }
  2015. /* 1. Virtual methods */
  2016. for (i = mono_class_get_method_count (klass_iter) - 1; i >= 0; i--) {
  2017. MonoMethod *method = m_class_get_methods (klass_iter) [i];
  2018. if (cominterop_class_method_is_visible (method) && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
  2019. && !cominterop_get_method_interface (method)) {
  2020. vtable [vtable_index--] = cominterop_get_ccw_method (iface, m_class_get_vtable (iface) [method->slot], error);
  2021. return_val_if_nok (error, NULL);
  2022. }
  2023. }
  2024. }
  2025. }
  2026. ccw_entry = g_new0 (MonoCCWInterface, 1);
  2027. ccw_entry->ccw = ccw;
  2028. ccw_entry->vtable = vtable;
  2029. g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
  2030. g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
  2031. }
  2032. return ccw_entry;
  2033. }
  2034. /**
  2035. * cominterop_get_ccw:
  2036. * @object: a pointer to the object
  2037. * @itf: interface type needed
  2038. *
  2039. * Returns: a value indicating if the object is a
  2040. * Runtime Callable Wrapper (RCW) for a COM object
  2041. */
  2042. static gpointer
  2043. cominterop_get_ccw (MonoObject* object_raw, MonoClass* itf)
  2044. {
  2045. HANDLE_FUNCTION_ENTER ();
  2046. ERROR_DECL (error);
  2047. MONO_HANDLE_DCL (MonoObject, object);
  2048. gpointer const ccw_entry = cominterop_get_ccw_checked (object, itf, error);
  2049. mono_error_set_pending_exception (error);
  2050. HANDLE_FUNCTION_RETURN_VAL (ccw_entry);
  2051. }
  2052. static gboolean
  2053. mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
  2054. {
  2055. g_hash_table_remove (ccw_interface_hash, value);
  2056. g_assert (value);
  2057. g_free (value);
  2058. return TRUE;
  2059. }
  2060. /**
  2061. * mono_marshal_free_ccw:
  2062. * \param object the mono object
  2063. * \returns whether the object had a CCW
  2064. */
  2065. static gboolean
  2066. mono_marshal_free_ccw_handle (MonoObjectHandle object)
  2067. {
  2068. /* no ccw's were created */
  2069. if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
  2070. return FALSE;
  2071. mono_cominterop_lock ();
  2072. GList *ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)));
  2073. mono_cominterop_unlock ();
  2074. if (!ccw_list)
  2075. return FALSE;
  2076. /* need to cache orig list address to remove from hash_table if empty */
  2077. GList * const ccw_list_orig = ccw_list;
  2078. for (GList* ccw_list_item = ccw_list; ccw_list_item; ) {
  2079. MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
  2080. gboolean is_null = FALSE;
  2081. gboolean is_equal = FALSE;
  2082. mono_gchandle_target_is_null_or_equal (ccw_iter->gc_handle, object, &is_null, &is_equal);
  2083. /* Looks like the GC NULLs the weakref handle target before running the
  2084. * finalizer. So if we get a NULL target, destroy the CCW as well.
  2085. * Unless looking up the object from the CCW shows it not the right object.
  2086. */
  2087. gboolean destroy_ccw = is_null || is_equal;
  2088. if (is_null) {
  2089. MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
  2090. MonoGCHandle gchandle = NULL;
  2091. if (!(ccw_entry && (gchandle = cominterop_get_ccw_gchandle (ccw_entry, FALSE)) && mono_gchandle_target_equal (gchandle, object)))
  2092. destroy_ccw = FALSE;
  2093. }
  2094. if (destroy_ccw) {
  2095. /* remove all interfaces */
  2096. g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
  2097. g_hash_table_destroy (ccw_iter->vtable_hash);
  2098. /* get next before we delete */
  2099. ccw_list_item = g_list_next (ccw_list_item);
  2100. /* remove ccw from list */
  2101. ccw_list = g_list_remove (ccw_list, ccw_iter);
  2102. #ifdef HOST_WIN32
  2103. mono_IUnknown_Release (ccw_iter->free_marshaler);
  2104. #endif
  2105. g_free (ccw_iter);
  2106. }
  2107. else
  2108. ccw_list_item = g_list_next (ccw_list_item);
  2109. }
  2110. /* if list is empty remove original address from hash */
  2111. if (g_list_length (ccw_list) == 0)
  2112. g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)));
  2113. else if (ccw_list != ccw_list_orig)
  2114. g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)), ccw_list);
  2115. return TRUE;
  2116. }
  2117. gboolean
  2118. mono_marshal_free_ccw (MonoObject* object_raw)
  2119. {
  2120. /* no ccw's were created */
  2121. if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
  2122. return FALSE;
  2123. HANDLE_FUNCTION_ENTER ();
  2124. MONO_HANDLE_DCL (MonoObject, object);
  2125. gboolean const result = mono_marshal_free_ccw_handle (object);
  2126. HANDLE_FUNCTION_RETURN_VAL (result);
  2127. }
  2128. /**
  2129. * cominterop_get_managed_wrapper_adjusted:
  2130. * @method: managed COM Interop method
  2131. *
  2132. * Returns: the generated method to call with signature matching
  2133. * the unmanaged COM Method signature
  2134. */
  2135. static MonoMethod *
  2136. cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
  2137. {
  2138. MonoMethod *res = NULL;
  2139. MonoMethodBuilder *mb;
  2140. MonoMarshalSpec **mspecs;
  2141. MonoMethodSignature *sig, *sig_native;
  2142. MonoExceptionClause *main_clause = NULL;
  2143. int hr = 0, retval = 0;
  2144. int pos_leave, domain_var;
  2145. int i;
  2146. gboolean const preserve_sig = (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) != 0;
  2147. MonoType *int_type = mono_get_int_type ();
  2148. MONO_STATIC_POINTER_INIT (MonoMethod, get_hr_for_exception)
  2149. ERROR_DECL (error);
  2150. get_hr_for_exception = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetHRForException", -1, 0, error);
  2151. mono_error_assert_ok (error);
  2152. MONO_STATIC_POINTER_INIT_END (MonoMethod, get_hr_for_exception)
  2153. sig = mono_method_signature_internal (method);
  2154. /* create unmanaged wrapper */
  2155. mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
  2156. sig_native = cominterop_method_signature (method);
  2157. mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
  2158. mono_method_get_marshal_info (method, mspecs);
  2159. /* move managed args up one */
  2160. for (i = sig->param_count; i >= 1; i--)
  2161. mspecs [i+1] = mspecs [i];
  2162. /* first arg is IntPtr for interface */
  2163. mspecs [1] = NULL;
  2164. /* move return spec to last param */
  2165. if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
  2166. mspecs [sig_native->param_count] = mspecs [0];
  2167. mspecs [0] = NULL;
  2168. #ifndef DISABLE_JIT
  2169. if (!preserve_sig) {
  2170. if (!MONO_TYPE_IS_VOID (sig->ret))
  2171. retval = mono_mb_add_local (mb, sig->ret);
  2172. hr = mono_mb_add_local (mb, mono_get_int32_type ());
  2173. }
  2174. else if (!MONO_TYPE_IS_VOID (sig->ret))
  2175. hr = mono_mb_add_local (mb, sig->ret);
  2176. /* try */
  2177. main_clause = g_new0 (MonoExceptionClause, 1);
  2178. main_clause->try_offset = mono_mb_get_label (mb);
  2179. domain_var = mono_mb_add_local (mb, int_type);
  2180. /* the CCW -> object conversion */
  2181. mono_mb_emit_ldarg (mb, 0);
  2182. mono_mb_emit_icon (mb, FALSE);
  2183. mono_mb_emit_icall (mb, cominterop_get_ccw_object);
  2184. /* Object is left on stack */
  2185. mono_mb_emit_ldloc_addr (mb, domain_var);
  2186. mono_mb_emit_icall (mb, cominterop_set_ccw_object_domain);
  2187. for (i = 0; i < sig->param_count; i++)
  2188. mono_mb_emit_ldarg (mb, i+1);
  2189. mono_mb_emit_managed_call (mb, method, NULL);
  2190. if (!MONO_TYPE_IS_VOID (sig->ret)) {
  2191. if (!preserve_sig) {
  2192. mono_mb_emit_stloc (mb, retval);
  2193. mono_mb_emit_ldarg (mb, sig_native->param_count - 1);
  2194. const int pos_null = mono_mb_emit_branch (mb, CEE_BRFALSE);
  2195. mono_mb_emit_ldarg (mb, sig_native->param_count - 1);
  2196. mono_mb_emit_ldloc (mb, retval);
  2197. MonoClass *rclass = mono_class_from_mono_type_internal (sig->ret);
  2198. if (m_class_is_valuetype (rclass)) {
  2199. mono_mb_emit_op (mb, CEE_STOBJ, rclass);
  2200. } else {
  2201. mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
  2202. }
  2203. mono_mb_patch_branch (mb, pos_null);
  2204. } else
  2205. mono_mb_emit_stloc (mb, hr);
  2206. }
  2207. pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
  2208. /* Main exception catch */
  2209. main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
  2210. main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
  2211. main_clause->data.catch_class = mono_defaults.object_class;
  2212. /* handler code */
  2213. main_clause->handler_offset = mono_mb_get_label (mb);
  2214. if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
  2215. mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
  2216. mono_mb_emit_stloc (mb, hr);
  2217. }
  2218. else {
  2219. mono_mb_emit_byte (mb, CEE_POP);
  2220. }
  2221. mono_mb_emit_branch (mb, CEE_LEAVE);
  2222. main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
  2223. /* end catch */
  2224. mono_mb_set_clauses (mb, 1, main_clause);
  2225. mono_mb_patch_branch (mb, pos_leave);
  2226. if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
  2227. mono_mb_emit_ldloc (mb, hr);
  2228. mono_mb_emit_ldloc (mb, domain_var);
  2229. mono_mb_emit_icall (mb, cominterop_restore_domain);
  2230. mono_mb_emit_byte (mb, CEE_RET);
  2231. #endif /* DISABLE_JIT */
  2232. mono_cominterop_lock ();
  2233. res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
  2234. mono_cominterop_unlock ();
  2235. mono_mb_free (mb);
  2236. for (i = sig_native->param_count; i >= 0; i--)
  2237. mono_metadata_free_marshal_spec (mspecs [i]);
  2238. g_free (mspecs);
  2239. return res;
  2240. }
  2241. static gboolean
  2242. cominterop_class_guid_equal (const guint8* guid, MonoClass* klass)
  2243. {
  2244. guint8 klass_guid [16];
  2245. if (cominterop_class_guid (klass, klass_guid))
  2246. return !memcmp (guid, klass_guid, sizeof (klass_guid));
  2247. return FALSE;
  2248. }
  2249. static int STDCALL
  2250. cominterop_ccw_addref_impl (MonoCCWInterface* ccwe);
  2251. static int STDCALL
  2252. cominterop_ccw_addref (MonoCCWInterface* ccwe)
  2253. {
  2254. int result;
  2255. gpointer dummy;
  2256. gpointer orig_domain = mono_threads_attach_coop (mono_domain_get (), &dummy);
  2257. MONO_ENTER_GC_UNSAFE;
  2258. result = cominterop_ccw_addref_impl (ccwe);
  2259. MONO_EXIT_GC_UNSAFE;
  2260. mono_threads_detach_coop (orig_domain, &dummy);
  2261. return result;
  2262. }
  2263. static int STDCALL
  2264. cominterop_ccw_addref_impl (MonoCCWInterface* ccwe)
  2265. {
  2266. MONO_REQ_GC_UNSAFE_MODE;
  2267. MonoCCW* ccw = ccwe->ccw;
  2268. g_assert (ccw);
  2269. g_assert (ccw->gc_handle);
  2270. gint32 const ref_count = mono_atomic_inc_i32 ((gint32*)&ccw->ref_count);
  2271. if (ref_count == 1) {
  2272. MonoGCHandle oldhandle = ccw->gc_handle;
  2273. g_assert (oldhandle);
  2274. /* since we now have a ref count, alloc a strong handle*/
  2275. ccw->gc_handle = mono_gchandle_from_handle (mono_gchandle_get_target_handle (oldhandle), FALSE);
  2276. mono_gchandle_free_internal (oldhandle);
  2277. }
  2278. return ref_count;
  2279. }
  2280. static int STDCALL
  2281. cominterop_ccw_release_impl (MonoCCWInterface* ccwe);
  2282. static int STDCALL
  2283. cominterop_ccw_release (MonoCCWInterface* ccwe)
  2284. {
  2285. int result;
  2286. gpointer dummy;
  2287. gpointer orig_domain = mono_threads_attach_coop (mono_domain_get (), &dummy);
  2288. MONO_ENTER_GC_UNSAFE;
  2289. result = cominterop_ccw_release_impl (ccwe);
  2290. MONO_EXIT_GC_UNSAFE;
  2291. mono_threads_detach_coop (orig_domain, &dummy);
  2292. return result;
  2293. }
  2294. static int STDCALL
  2295. cominterop_ccw_release_impl (MonoCCWInterface* ccwe)
  2296. {
  2297. MONO_REQ_GC_UNSAFE_MODE;
  2298. MonoCCW* ccw = ccwe->ccw;
  2299. g_assert (ccw);
  2300. g_assert (ccw->ref_count > 0);
  2301. gint32 const ref_count = mono_atomic_dec_i32 ((gint32*)&ccw->ref_count);
  2302. if (ref_count == 0) {
  2303. /* allow gc of object */
  2304. MonoGCHandle oldhandle = ccw->gc_handle;
  2305. g_assert (oldhandle);
  2306. ccw->gc_handle = mono_gchandle_new_weakref_from_handle (mono_gchandle_get_target_handle (oldhandle));
  2307. mono_gchandle_free_internal (oldhandle);
  2308. }
  2309. return ref_count;
  2310. }
  2311. #ifdef HOST_WIN32
  2312. static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
  2313. /* All ccw objects are free threaded */
  2314. static int
  2315. cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObjectHandle object, gpointer* ppv, MonoError *error)
  2316. {
  2317. if (!ccw->free_marshaler) {
  2318. gpointer const tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
  2319. return_val_if_nok (error, MONO_E_NOINTERFACE);
  2320. int const ret = CoCreateFreeThreadedMarshaler ((LPUNKNOWN)tunk, (LPUNKNOWN*)&ccw->free_marshaler);
  2321. }
  2322. return ccw->free_marshaler ? mono_IUnknown_QueryInterface (ccw->free_marshaler, &MONO_IID_IMarshal, ppv)
  2323. : MONO_E_NOINTERFACE;
  2324. }
  2325. #endif
  2326. static int STDCALL
  2327. cominterop_ccw_queryinterface_impl (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv);
  2328. static int STDCALL
  2329. cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv)
  2330. {
  2331. int result;
  2332. gpointer dummy;
  2333. gpointer orig_domain = mono_threads_attach_coop (mono_domain_get (), &dummy);
  2334. MONO_ENTER_GC_UNSAFE;
  2335. result = cominterop_ccw_queryinterface_impl (ccwe, riid, ppv);
  2336. MONO_EXIT_GC_UNSAFE;
  2337. mono_threads_detach_coop (orig_domain, &dummy);
  2338. return result;
  2339. }
  2340. static int STDCALL
  2341. cominterop_ccw_queryinterface_impl (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv)
  2342. {
  2343. MONO_REQ_GC_UNSAFE_MODE;
  2344. ERROR_DECL (error);
  2345. GPtrArray *ifaces;
  2346. MonoClass *itf = NULL;
  2347. int i;
  2348. MonoCCW* ccw = ccwe->ccw;
  2349. MonoClass* klass_iter = NULL;
  2350. MonoObjectHandle object = mono_gchandle_get_target_handle (ccw->gc_handle);
  2351. g_assert (!MONO_HANDLE_IS_NULL (object));
  2352. MonoClass* const klass = mono_handle_class (object);
  2353. if (ppv)
  2354. *ppv = NULL;
  2355. if (!mono_domain_get ())
  2356. mono_thread_attach_external_native_thread (mono_get_root_domain (), FALSE);
  2357. /* handle IUnknown special */
  2358. if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
  2359. *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
  2360. mono_error_assert_ok (error);
  2361. /* remember to addref on QI */
  2362. cominterop_ccw_addref_impl ((MonoCCWInterface *)*ppv);
  2363. return MONO_S_OK;
  2364. }
  2365. /* handle IDispatch special */
  2366. if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
  2367. if (!cominterop_can_support_dispatch (klass))
  2368. return MONO_E_NOINTERFACE;
  2369. *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
  2370. mono_error_assert_ok (error);
  2371. /* remember to addref on QI */
  2372. cominterop_ccw_addref_impl ((MonoCCWInterface *)*ppv);
  2373. return MONO_S_OK;
  2374. }
  2375. #ifdef HOST_WIN32
  2376. /* handle IMarshal special */
  2377. if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
  2378. int const res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, error);
  2379. mono_error_assert_ok (error);
  2380. return res;
  2381. }
  2382. #endif
  2383. klass_iter = klass;
  2384. while (klass_iter && klass_iter != mono_defaults.object_class) {
  2385. ifaces = mono_class_get_implemented_interfaces (klass_iter, error);
  2386. mono_error_assert_ok (error);
  2387. if (ifaces) {
  2388. for (i = 0; i < ifaces->len; ++i) {
  2389. MonoClass *ic = NULL;
  2390. ic = (MonoClass *)g_ptr_array_index (ifaces, i);
  2391. if (cominterop_class_guid_equal (riid, ic)) {
  2392. itf = ic;
  2393. break;
  2394. }
  2395. }
  2396. g_ptr_array_free (ifaces, TRUE);
  2397. }
  2398. if (itf)
  2399. break;
  2400. klass_iter = m_class_get_parent (klass_iter);
  2401. }
  2402. if (itf) {
  2403. *ppv = cominterop_get_ccw_checked (object, itf, error);
  2404. if (!is_ok (error)) {
  2405. mono_error_cleanup (error); /* FIXME don't swallow the error */
  2406. return MONO_E_NOINTERFACE;
  2407. }
  2408. /* remember to addref on QI */
  2409. cominterop_ccw_addref_impl ((MonoCCWInterface *)*ppv);
  2410. return MONO_S_OK;
  2411. }
  2412. return MONO_E_NOINTERFACE;
  2413. }
  2414. static int STDCALL
  2415. cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
  2416. {
  2417. if(!pctinfo)
  2418. return MONO_E_INVALIDARG;
  2419. *pctinfo = 1;
  2420. return MONO_S_OK;
  2421. }
  2422. static int STDCALL
  2423. cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
  2424. {
  2425. return MONO_E_NOTIMPL;
  2426. }
  2427. static int STDCALL
  2428. cominterop_ccw_get_ids_of_names_impl (MonoCCWInterface* ccwe, gpointer riid,
  2429. gunichar2** rgszNames, guint32 cNames,
  2430. guint32 lcid, gint32 *rgDispId);
  2431. static int STDCALL
  2432. cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
  2433. gunichar2** rgszNames, guint32 cNames,
  2434. guint32 lcid, gint32 *rgDispId)
  2435. {
  2436. int result;
  2437. gpointer dummy;
  2438. gpointer orig_domain = mono_threads_attach_coop (mono_domain_get(), &dummy);
  2439. MONO_ENTER_GC_UNSAFE;
  2440. result = cominterop_ccw_get_ids_of_names_impl (ccwe, riid, rgszNames, cNames, lcid, rgDispId);
  2441. MONO_EXIT_GC_UNSAFE;
  2442. mono_threads_detach_coop (orig_domain, &dummy);
  2443. return result;
  2444. }
  2445. static int STDCALL
  2446. cominterop_ccw_get_ids_of_names_impl (MonoCCWInterface* ccwe, gpointer riid,
  2447. gunichar2** rgszNames, guint32 cNames,
  2448. guint32 lcid, gint32 *rgDispId)
  2449. {
  2450. MONO_REQ_GC_UNSAFE_MODE;
  2451. ERROR_DECL (error);
  2452. MonoCustomAttrInfo *cinfo = NULL;
  2453. int i,ret = MONO_S_OK;
  2454. MonoMethod* method;
  2455. gchar* methodname;
  2456. MonoClass *klass = NULL;
  2457. MonoCCW* ccw = ccwe->ccw;
  2458. MonoObject* object = mono_gchandle_get_target_internal (ccw->gc_handle);
  2459. /* Handle DispIdAttribute */
  2460. MONO_STATIC_POINTER_INIT (MonoClass, ComDispIdAttribute)
  2461. ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
  2462. MONO_STATIC_POINTER_INIT_END (MonoClass, ComDispIdAttribute)
  2463. g_assert (object);
  2464. klass = mono_object_class (object);
  2465. if (!mono_domain_get ())
  2466. mono_thread_attach_external_native_thread (mono_get_root_domain (), FALSE);
  2467. for (i=0; i < cNames; i++) {
  2468. methodname = mono_unicode_to_external (rgszNames[i]);
  2469. method = mono_class_get_method_from_name_checked(klass, methodname, -1, 0, error);
  2470. if (method && is_ok (error)) {
  2471. cinfo = mono_custom_attrs_from_method_checked (method, error);
  2472. mono_error_assert_ok (error); /* FIXME what's reasonable to do here */
  2473. if (cinfo) {
  2474. MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, error);
  2475. mono_error_assert_ok (error); /*FIXME proper error handling*/;
  2476. if (result)
  2477. rgDispId[i] = *(gint32*)mono_object_unbox_internal (result);
  2478. else
  2479. rgDispId[i] = (gint32)method->token;
  2480. if (!cinfo->cached)
  2481. mono_custom_attrs_free (cinfo);
  2482. }
  2483. else
  2484. rgDispId[i] = (gint32)method->token;
  2485. } else {
  2486. mono_error_cleanup (error);
  2487. error_init (error); /* reuse for next iteration */
  2488. rgDispId[i] = MONO_E_DISPID_UNKNOWN;
  2489. ret = MONO_E_DISP_E_UNKNOWNNAME;
  2490. }
  2491. }
  2492. return ret;
  2493. }
  2494. static int STDCALL
  2495. cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
  2496. gpointer riid, guint32 lcid,
  2497. guint16 wFlags, gpointer pDispParams,
  2498. gpointer pVarResult, gpointer pExcepInfo,
  2499. guint32 *puArgErr)
  2500. {
  2501. return MONO_E_NOTIMPL;
  2502. }
  2503. #ifndef HOST_WIN32
  2504. typedef mono_bstr (STDCALL *SysAllocStringLenFunc)(const gunichar* str, guint32 len);
  2505. typedef guint32 (STDCALL *SysStringLenFunc)(mono_bstr_const bstr);
  2506. typedef void (STDCALL *SysFreeStringFunc)(mono_bstr_const str);
  2507. static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
  2508. static SysStringLenFunc sys_string_len_ms = NULL;
  2509. static SysFreeStringFunc sys_free_string_ms = NULL;
  2510. typedef struct tagSAFEARRAYBOUND {
  2511. ULONG cElements;
  2512. LONG lLbound;
  2513. }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
  2514. #define VT_VARIANT 12
  2515. typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
  2516. typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
  2517. typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
  2518. typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
  2519. typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
  2520. typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
  2521. typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
  2522. static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
  2523. static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
  2524. static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
  2525. static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
  2526. static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
  2527. static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
  2528. static SafeArrayCreateFunc safe_array_create_ms = NULL;
  2529. static gboolean
  2530. init_com_provider_ms (void)
  2531. {
  2532. static gboolean initialized = FALSE;
  2533. char *error_msg;
  2534. MonoDl *module = NULL;
  2535. const char* scope = "liboleaut32.so";
  2536. if (initialized) {
  2537. // Barrier here prevents reads of sys_alloc_string_len_ms etc.
  2538. // from being reordered before initialized.
  2539. mono_memory_barrier ();
  2540. return TRUE;
  2541. }
  2542. module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
  2543. if (error_msg) {
  2544. g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
  2545. g_assert_not_reached ();
  2546. return FALSE;
  2547. }
  2548. error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
  2549. if (error_msg) {
  2550. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
  2551. g_assert_not_reached ();
  2552. return FALSE;
  2553. }
  2554. error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
  2555. if (error_msg) {
  2556. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
  2557. g_assert_not_reached ();
  2558. return FALSE;
  2559. }
  2560. error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
  2561. if (error_msg) {
  2562. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
  2563. g_assert_not_reached ();
  2564. return FALSE;
  2565. }
  2566. error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
  2567. if (error_msg) {
  2568. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
  2569. g_assert_not_reached ();
  2570. return FALSE;
  2571. }
  2572. error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
  2573. if (error_msg) {
  2574. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
  2575. g_assert_not_reached ();
  2576. return FALSE;
  2577. }
  2578. error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
  2579. if (error_msg) {
  2580. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
  2581. g_assert_not_reached ();
  2582. return FALSE;
  2583. }
  2584. error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
  2585. if (error_msg) {
  2586. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
  2587. g_assert_not_reached ();
  2588. return FALSE;
  2589. }
  2590. error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
  2591. if (error_msg) {
  2592. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
  2593. g_assert_not_reached ();
  2594. return FALSE;
  2595. }
  2596. error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
  2597. if (error_msg) {
  2598. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
  2599. g_assert_not_reached ();
  2600. return FALSE;
  2601. }
  2602. error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
  2603. if (error_msg) {
  2604. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
  2605. g_assert_not_reached ();
  2606. return FALSE;
  2607. }
  2608. mono_memory_barrier ();
  2609. initialized = TRUE;
  2610. return TRUE;
  2611. }
  2612. #endif // WIN32
  2613. #endif // DISABLE_COM
  2614. // This function is used regardless of the BSTR type, so cast the return value
  2615. // Inputted string length, in bytes, should include the null terminator
  2616. // Returns the start of the string itself
  2617. static gpointer
  2618. mono_bstr_alloc (size_t str_byte_len)
  2619. {
  2620. // Allocate string length plus pointer-size integer to store the length, aligned to 16 bytes
  2621. size_t alloc_size = str_byte_len + SIZEOF_VOID_P;
  2622. alloc_size += (16 - 1);
  2623. alloc_size &= ~(16 - 1);
  2624. gpointer ret = g_malloc0 (alloc_size);
  2625. return ret ? (char *)ret + SIZEOF_VOID_P : NULL;
  2626. }
  2627. static void
  2628. mono_bstr_set_length (gunichar2 *bstr, int slen)
  2629. {
  2630. *((guint32 *)bstr - 1) = slen * sizeof (gunichar2);
  2631. }
  2632. static mono_bstr
  2633. default_ptr_to_bstr (const gunichar2* ptr, int slen)
  2634. {
  2635. // In Mono, historically BSTR was allocated with a guaranteed size prefix of 4 bytes regardless of platform.
  2636. // Presumably this is due to the BStr documentation page, which indicates that behavior and then directs you to call
  2637. // SysAllocString on Windows to handle the allocation for you. Unfortunately, this is not actually how it works:
  2638. // The allocation pre-string is pointer-sized, and then only 4 bytes are used for the length regardless. Additionally,
  2639. // the total length is also aligned to a 16-byte boundary. This preserves the old behavior on legacy and fixes it for
  2640. // netcore moving forward.
  2641. #ifdef ENABLE_NETCORE
  2642. mono_bstr const s = (mono_bstr)mono_bstr_alloc ((slen + 1) * sizeof (gunichar2));
  2643. if (s == NULL)
  2644. return NULL;
  2645. #else
  2646. /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
  2647. guint32 * const ret = (guint32 *)g_malloc ((slen + 1) * sizeof (gunichar2) + sizeof (guint32));
  2648. if (ret == NULL)
  2649. return NULL;
  2650. mono_bstr const s = (mono_bstr)(ret + 1);
  2651. #endif
  2652. mono_bstr_set_length (s, slen);
  2653. if (ptr)
  2654. memcpy (s, ptr, slen * sizeof (gunichar2));
  2655. s [slen] = 0;
  2656. return s;
  2657. }
  2658. /* PTR can be NULL */
  2659. mono_bstr
  2660. mono_ptr_to_bstr (const gunichar2* ptr, int slen)
  2661. {
  2662. #ifdef HOST_WIN32
  2663. #if HAVE_API_SUPPORT_WIN32_BSTR
  2664. return SysAllocStringLen (ptr, slen);
  2665. #else
  2666. return default_ptr_to_bstr (ptr, slen);
  2667. #endif
  2668. #else
  2669. #ifndef DISABLE_COM
  2670. if (com_provider == MONO_COM_DEFAULT) {
  2671. #endif
  2672. return default_ptr_to_bstr (ptr, slen);
  2673. #ifndef DISABLE_COM
  2674. }
  2675. else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
  2676. guint32 const len = slen;
  2677. gunichar* const str = ptr ? g_utf16_to_ucs4 (ptr, len, NULL, NULL, NULL) : NULL;
  2678. mono_bstr const ret = sys_alloc_string_len_ms (str, len);
  2679. g_free (str);
  2680. return ret;
  2681. }
  2682. else {
  2683. g_assert_not_reached();
  2684. }
  2685. #endif
  2686. #endif
  2687. }
  2688. char *
  2689. mono_ptr_to_ansibstr (const char *ptr, size_t slen)
  2690. {
  2691. // FIXME: should this behave differently without DISABLE_COM?
  2692. char *s = (char *)mono_bstr_alloc ((slen + 1) * sizeof(char));
  2693. if (s == NULL)
  2694. return NULL;
  2695. *((guint32 *)s - 1) = slen * sizeof (char);
  2696. if (ptr)
  2697. memcpy (s, ptr, slen * sizeof (char));
  2698. s [slen] = 0;
  2699. return s;
  2700. }
  2701. MonoStringHandle
  2702. mono_string_from_bstr_checked (mono_bstr_const bstr, MonoError *error)
  2703. {
  2704. if (!bstr)
  2705. return NULL_HANDLE_STRING;
  2706. #ifdef HOST_WIN32
  2707. #if HAVE_API_SUPPORT_WIN32_BSTR
  2708. return mono_string_new_utf16_handle (mono_domain_get (), bstr, SysStringLen ((BSTR)bstr), error);
  2709. #else
  2710. return mono_string_new_utf16_handle (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof (gunichar2), error);
  2711. #endif /* HAVE_API_SUPPORT_WIN32_BSTR */
  2712. #else
  2713. #ifndef DISABLE_COM
  2714. if (com_provider == MONO_COM_DEFAULT)
  2715. #endif
  2716. return mono_string_new_utf16_handle (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof (gunichar2), error);
  2717. #ifndef DISABLE_COM
  2718. else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
  2719. glong written = 0;
  2720. // FIXME mono_string_new_utf32_handle to combine g_ucs4_to_utf16 and mono_string_new_utf16_handle.
  2721. gunichar2* utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
  2722. MonoStringHandle res = mono_string_new_utf16_handle (mono_domain_get (), utf16, written, error);
  2723. g_free (utf16);
  2724. return res;
  2725. } else {
  2726. g_assert_not_reached ();
  2727. }
  2728. #endif // DISABLE_COM
  2729. #endif // HOST_WIN32
  2730. }
  2731. MonoString *
  2732. mono_string_from_bstr (/*mono_bstr_const*/gpointer bstr)
  2733. {
  2734. // FIXME gcmode
  2735. HANDLE_FUNCTION_ENTER ();
  2736. ERROR_DECL (error);
  2737. MonoStringHandle result = mono_string_from_bstr_checked ((mono_bstr_const)bstr, error);
  2738. mono_error_cleanup (error);
  2739. HANDLE_FUNCTION_RETURN_OBJ (result);
  2740. }
  2741. MonoStringHandle
  2742. mono_string_from_bstr_icall_impl (mono_bstr_const bstr, MonoError *error)
  2743. {
  2744. return mono_string_from_bstr_checked (bstr, error);
  2745. }
  2746. MONO_API void
  2747. mono_free_bstr (/*mono_bstr_const*/gpointer bstr)
  2748. {
  2749. if (!bstr)
  2750. return;
  2751. #ifdef HOST_WIN32
  2752. #if HAVE_API_SUPPORT_WIN32_BSTR
  2753. SysFreeString ((BSTR)bstr);
  2754. #else
  2755. g_free (((char *)bstr) - 4);
  2756. #endif /* HAVE_API_SUPPORT_WIN32_BSTR */
  2757. #else
  2758. #ifndef DISABLE_COM
  2759. if (com_provider == MONO_COM_DEFAULT) {
  2760. #endif
  2761. #ifdef ENABLE_NETCORE
  2762. g_free (((char *)bstr) - SIZEOF_VOID_P);
  2763. #else // In Mono, historically BSTR was allocated with a guaranteed size prefix of 4 bytes regardless of platform
  2764. g_free (((char *)bstr) - 4);
  2765. #endif
  2766. #ifndef DISABLE_COM
  2767. } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
  2768. sys_free_string_ms ((mono_bstr_const)bstr);
  2769. } else {
  2770. g_assert_not_reached ();
  2771. }
  2772. #endif // DISABLE_COM
  2773. #endif // HOST_WIN32
  2774. }
  2775. // FIXME There are multiple caches of "GetObjectForNativeVariant".
  2776. G_GNUC_UNUSED
  2777. static MonoMethod*
  2778. mono_get_Marshal_GetObjectForNativeVariant (void)
  2779. {
  2780. MONO_STATIC_POINTER_INIT (MonoMethod, get_object_for_native_variant)
  2781. ERROR_DECL (error);
  2782. get_object_for_native_variant = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1, 0, error);
  2783. mono_error_assert_ok (error);
  2784. MONO_STATIC_POINTER_INIT_END (MonoMethod, get_object_for_native_variant)
  2785. g_assert (get_object_for_native_variant);
  2786. return get_object_for_native_variant;
  2787. }
  2788. // FIXME There are multiple caches of "GetNativeVariantForObject".
  2789. G_GNUC_UNUSED
  2790. static MonoMethod*
  2791. mono_get_Marshal_GetNativeVariantForObject (void)
  2792. {
  2793. MONO_STATIC_POINTER_INIT (MonoMethod, get_native_variant_for_object)
  2794. ERROR_DECL (error);
  2795. get_native_variant_for_object = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetNativeVariantForObject", 2, 0, error);
  2796. mono_error_assert_ok (error);
  2797. MONO_STATIC_POINTER_INIT_END (MonoMethod, get_native_variant_for_object)
  2798. g_assert (get_native_variant_for_object);
  2799. return get_native_variant_for_object;
  2800. }
  2801. G_GNUC_UNUSED
  2802. static MonoMethod*
  2803. mono_get_Array_SetValueImpl (void)
  2804. {
  2805. MONO_STATIC_POINTER_INIT (MonoMethod, set_value_impl)
  2806. ERROR_DECL (error);
  2807. set_value_impl = mono_class_get_method_from_name_checked (mono_defaults.array_class, "SetValueImpl", 2, 0, error);
  2808. mono_error_assert_ok (error);
  2809. MONO_STATIC_POINTER_INIT_END (MonoMethod, set_value_impl)
  2810. g_assert (set_value_impl);
  2811. return set_value_impl;
  2812. }
  2813. #ifndef DISABLE_COM
  2814. // FIXME There are multiple caches of "Clear".
  2815. G_GNUC_UNUSED
  2816. static MonoMethod*
  2817. mono_get_Variant_Clear (void)
  2818. {
  2819. MONO_STATIC_POINTER_INIT (MonoMethod, variant_clear)
  2820. ERROR_DECL (error);
  2821. variant_clear = mono_class_get_method_from_name_checked (mono_class_get_variant_class (), "Clear", 0, 0, error);
  2822. mono_error_assert_ok (error);
  2823. MONO_STATIC_POINTER_INIT_END (MonoMethod, variant_clear)
  2824. g_assert (variant_clear);
  2825. return variant_clear;
  2826. }
  2827. /* SAFEARRAY marshalling */
  2828. int
  2829. mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
  2830. MonoMarshalSpec *spec,
  2831. int conv_arg, MonoType **conv_arg_type,
  2832. MarshalAction action)
  2833. {
  2834. MonoMethodBuilder *mb = m->mb;
  2835. #ifndef DISABLE_JIT
  2836. switch (action) {
  2837. case MARSHAL_ACTION_CONV_IN: {
  2838. if ((t->attrs & (PARAM_ATTRIBUTE_IN | PARAM_ATTRIBUTE_OUT)) == PARAM_ATTRIBUTE_OUT)
  2839. break;
  2840. /* Generates IL code for the following algorithm:
  2841. SafeArray safearray; // safearray_var
  2842. IntPtr indices; // indices_var
  2843. int empty; // empty_var
  2844. if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
  2845. if (!empty) {
  2846. int index=0; // index_var
  2847. do { // label3
  2848. variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
  2849. mono_marshal_safearray_set_value (safearray, indices, elem);
  2850. ++index;
  2851. }
  2852. while (mono_marshal_safearray_next (safearray, indices));
  2853. } // label2
  2854. mono_marshal_safearray_free_indices (indices);
  2855. } // label1
  2856. */
  2857. int safearray_var, indices_var, empty_var, elem_var, index_var;
  2858. guint32 label1 = 0, label2 = 0, label3 = 0;
  2859. MonoType *int_type = mono_get_int_type ();
  2860. conv_arg = safearray_var = mono_mb_add_local (mb, mono_get_object_type ());
  2861. indices_var = mono_mb_add_local (mb, int_type);
  2862. empty_var = mono_mb_add_local (mb, int_type);
  2863. if (t->byref) {
  2864. mono_mb_emit_ldarg (mb, argnum);
  2865. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  2866. } else
  2867. mono_mb_emit_ldarg (mb, argnum);
  2868. mono_mb_emit_ldloc_addr (mb, safearray_var);
  2869. mono_mb_emit_ldloc_addr (mb, indices_var);
  2870. mono_mb_emit_ldloc_addr (mb, empty_var);
  2871. mono_mb_emit_icall (mb, mono_marshal_safearray_create);
  2872. label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  2873. mono_mb_emit_ldloc (mb, empty_var);
  2874. label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
  2875. index_var = mono_mb_add_local (mb, mono_get_int32_type ());
  2876. mono_mb_emit_byte (mb, CEE_LDC_I4_0);
  2877. mono_mb_emit_stloc (mb, index_var);
  2878. label3 = mono_mb_get_label (mb);
  2879. MONO_STATIC_POINTER_INIT (MonoMethod, get_value_impl)
  2880. ERROR_DECL (error);
  2881. get_value_impl = mono_class_get_method_from_name_checked (mono_defaults.array_class, "GetValueImpl", 1, 0, error);
  2882. mono_error_assert_ok (error);
  2883. MONO_STATIC_POINTER_INIT_END (MonoMethod, get_value_impl)
  2884. g_assert (get_value_impl);
  2885. if (t->byref) {
  2886. mono_mb_emit_ldarg (mb, argnum);
  2887. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  2888. } else
  2889. mono_mb_emit_ldarg (mb, argnum);
  2890. mono_mb_emit_ldloc (mb, index_var);
  2891. mono_mb_emit_managed_call (mb, get_value_impl, NULL);
  2892. elem_var = mono_mb_add_local (mb, m_class_get_byval_arg (mono_class_get_variant_class ()));
  2893. mono_mb_emit_ldloc_addr (mb, elem_var);
  2894. mono_mb_emit_managed_call (mb, mono_get_Marshal_GetNativeVariantForObject (), NULL);
  2895. mono_mb_emit_ldloc (mb, safearray_var);
  2896. mono_mb_emit_ldloc (mb, indices_var);
  2897. mono_mb_emit_ldloc_addr (mb, elem_var);
  2898. mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
  2899. mono_mb_emit_ldloc_addr (mb, elem_var);
  2900. mono_mb_emit_managed_call (mb, mono_get_Variant_Clear (), NULL);
  2901. mono_mb_emit_add_to_local (mb, index_var, 1);
  2902. mono_mb_emit_ldloc (mb, safearray_var);
  2903. mono_mb_emit_ldloc (mb, indices_var);
  2904. mono_mb_emit_icall (mb, mono_marshal_safearray_next);
  2905. mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
  2906. mono_mb_patch_short_branch (mb, label2);
  2907. mono_mb_emit_ldloc (mb, indices_var);
  2908. mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
  2909. mono_mb_patch_short_branch (mb, label1);
  2910. break;
  2911. }
  2912. case MARSHAL_ACTION_PUSH:
  2913. if (t->byref)
  2914. mono_mb_emit_ldloc_addr (mb, conv_arg);
  2915. else
  2916. mono_mb_emit_ldloc (mb, conv_arg);
  2917. break;
  2918. case MARSHAL_ACTION_CONV_OUT: {
  2919. if (t->attrs & PARAM_ATTRIBUTE_OUT) {
  2920. /* Generates IL code for the following algorithm:
  2921. Array result; // result_var
  2922. IntPtr indices; // indices_var
  2923. int empty; // empty_var
  2924. bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
  2925. if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
  2926. if (!empty) {
  2927. int index=0; // index_var
  2928. do { // label3
  2929. if (!byValue || (index < parameter.Length)) {
  2930. object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
  2931. result.SetValueImpl(elem, index);
  2932. }
  2933. ++index;
  2934. }
  2935. while (mono_marshal_safearray_next(safearray, indices));
  2936. } // label2
  2937. mono_marshal_safearray_end(safearray, indices);
  2938. } // label1
  2939. if (!byValue)
  2940. return result;
  2941. */
  2942. int result_var, indices_var, empty_var, elem_var, index_var;
  2943. guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
  2944. gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
  2945. MonoType *object_type = mono_get_object_type ();
  2946. MonoType *int_type = mono_get_int_type ();
  2947. result_var = mono_mb_add_local (mb, object_type);
  2948. indices_var = mono_mb_add_local (mb, int_type);
  2949. empty_var = mono_mb_add_local (mb, int_type);
  2950. mono_mb_emit_ldloc (mb, conv_arg);
  2951. mono_mb_emit_ldloc_addr (mb, result_var);
  2952. mono_mb_emit_ldloc_addr (mb, indices_var);
  2953. mono_mb_emit_ldloc_addr (mb, empty_var);
  2954. mono_mb_emit_ldarg (mb, argnum);
  2955. if (byValue)
  2956. mono_mb_emit_byte (mb, CEE_LDC_I4_0);
  2957. else
  2958. mono_mb_emit_byte (mb, CEE_LDC_I4_1);
  2959. mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
  2960. label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  2961. mono_mb_emit_ldloc (mb, empty_var);
  2962. label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
  2963. index_var = mono_mb_add_local (mb, int_type);
  2964. mono_mb_emit_byte (mb, CEE_LDC_I4_0);
  2965. mono_mb_emit_stloc (mb, index_var);
  2966. label3 = mono_mb_get_label (mb);
  2967. if (byValue) {
  2968. mono_mb_emit_ldloc (mb, index_var);
  2969. mono_mb_emit_ldarg (mb, argnum);
  2970. mono_mb_emit_byte (mb, CEE_LDLEN);
  2971. label4 = mono_mb_emit_branch (mb, CEE_BGE);
  2972. }
  2973. mono_mb_emit_ldloc (mb, conv_arg);
  2974. mono_mb_emit_ldloc (mb, indices_var);
  2975. mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
  2976. elem_var = mono_mb_add_local (mb, object_type);
  2977. mono_mb_emit_managed_call (mb, mono_get_Marshal_GetObjectForNativeVariant (), NULL);
  2978. mono_mb_emit_stloc (mb, elem_var);
  2979. mono_mb_emit_ldloc (mb, result_var);
  2980. mono_mb_emit_ldloc (mb, elem_var);
  2981. mono_mb_emit_ldloc (mb, index_var);
  2982. mono_mb_emit_managed_call (mb, mono_get_Array_SetValueImpl (), NULL);
  2983. if (byValue)
  2984. mono_mb_patch_short_branch (mb, label4);
  2985. mono_mb_emit_add_to_local (mb, index_var, 1);
  2986. mono_mb_emit_ldloc (mb, conv_arg);
  2987. mono_mb_emit_ldloc (mb, indices_var);
  2988. mono_mb_emit_icall (mb, mono_marshal_safearray_next);
  2989. mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
  2990. mono_mb_patch_short_branch (mb, label2);
  2991. mono_mb_emit_ldloc (mb, conv_arg);
  2992. mono_mb_emit_ldloc (mb, indices_var);
  2993. mono_mb_emit_icall (mb, mono_marshal_safearray_end);
  2994. mono_mb_patch_short_branch (mb, label1);
  2995. if (!byValue) {
  2996. mono_mb_emit_ldarg (mb, argnum);
  2997. mono_mb_emit_ldloc (mb, result_var);
  2998. mono_mb_emit_byte (mb, CEE_STIND_REF);
  2999. }
  3000. }
  3001. break;
  3002. }
  3003. case MARSHAL_ACTION_MANAGED_CONV_IN: {
  3004. if ((t->attrs & (PARAM_ATTRIBUTE_IN | PARAM_ATTRIBUTE_OUT)) == PARAM_ATTRIBUTE_OUT)
  3005. break;
  3006. /* Generates IL code for the following algorithm:
  3007. Array result; // result_var
  3008. IntPtr indices; // indices_var
  3009. int empty; // empty_var
  3010. if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, NULL, TRUE)) {
  3011. if (!empty) {
  3012. int index=0; // index_var
  3013. do { // label3
  3014. object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
  3015. result.SetValueImpl(elem, index);
  3016. ++index;
  3017. }
  3018. while (mono_marshal_safearray_next(safearray, indices));
  3019. } // label2
  3020. mono_marshal_safearray_free_indices(indices);
  3021. } // label1
  3022. */
  3023. int result_var, indices_var, empty_var, elem_var, index_var;
  3024. guint32 label1 = 0, label2 = 0, label3 = 0;
  3025. MonoType *object_type = mono_get_object_type ();
  3026. MonoType *int_type = mono_get_int_type ();
  3027. result_var = mono_mb_add_local (mb, object_type);
  3028. indices_var = mono_mb_add_local (mb, int_type);
  3029. empty_var = mono_mb_add_local (mb, int_type);
  3030. mono_mb_emit_ldarg (mb, argnum);
  3031. mono_mb_emit_ldloc_addr (mb, result_var);
  3032. mono_mb_emit_ldloc_addr (mb, indices_var);
  3033. mono_mb_emit_ldloc_addr (mb, empty_var);
  3034. mono_mb_emit_byte (mb, CEE_LDC_I4_0);
  3035. mono_mb_emit_byte (mb, CEE_CONV_I);
  3036. mono_mb_emit_byte (mb, CEE_LDC_I4_1);
  3037. mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
  3038. label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  3039. mono_mb_emit_ldloc (mb, empty_var);
  3040. label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
  3041. index_var = mono_mb_add_local (mb, int_type);
  3042. mono_mb_emit_byte (mb, CEE_LDC_I4_0);
  3043. mono_mb_emit_stloc (mb, index_var);
  3044. label3 = mono_mb_get_label (mb);
  3045. mono_mb_emit_ldarg (mb, argnum);
  3046. mono_mb_emit_ldloc (mb, indices_var);
  3047. mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
  3048. elem_var = mono_mb_add_local (mb, object_type);
  3049. mono_mb_emit_managed_call (mb, mono_get_Marshal_GetObjectForNativeVariant (), NULL);
  3050. mono_mb_emit_stloc (mb, elem_var);
  3051. mono_mb_emit_ldloc (mb, result_var);
  3052. mono_mb_emit_ldloc (mb, elem_var);
  3053. mono_mb_emit_ldloc (mb, index_var);
  3054. mono_mb_emit_managed_call (mb, mono_get_Array_SetValueImpl (), NULL);
  3055. mono_mb_emit_add_to_local (mb, index_var, 1);
  3056. mono_mb_emit_ldarg (mb, argnum);
  3057. mono_mb_emit_ldloc (mb, indices_var);
  3058. mono_mb_emit_icall (mb, mono_marshal_safearray_next);
  3059. mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
  3060. mono_mb_patch_short_branch (mb, label2);
  3061. mono_mb_emit_ldloc (mb, indices_var);
  3062. mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
  3063. mono_mb_patch_short_branch (mb, label1);
  3064. mono_mb_emit_ldloc (mb, result_var);
  3065. mono_mb_emit_stloc (mb, conv_arg);
  3066. break;
  3067. }
  3068. default:
  3069. g_assert_not_reached ();
  3070. }
  3071. #endif /* DISABLE_JIT */
  3072. return conv_arg;
  3073. }
  3074. #ifdef HOST_WIN32
  3075. #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
  3076. static guint32
  3077. mono_marshal_win_safearray_get_dim (gpointer safearray)
  3078. {
  3079. return SafeArrayGetDim ((SAFEARRAY*)safearray);
  3080. }
  3081. #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
  3082. static guint32
  3083. mono_marshal_win_safearray_get_dim (gpointer safearray)
  3084. {
  3085. g_unsupported_api ("SafeArrayGetDim");
  3086. SetLastError (ERROR_NOT_SUPPORTED);
  3087. return MONO_E_NOTIMPL;
  3088. }
  3089. #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
  3090. static guint32
  3091. mono_marshal_safearray_get_dim (gpointer safearray)
  3092. {
  3093. return mono_marshal_win_safearray_get_dim (safearray);
  3094. }
  3095. #else /* HOST_WIN32 */
  3096. static guint32
  3097. mono_marshal_safearray_get_dim (gpointer safearray)
  3098. {
  3099. guint32 result=0;
  3100. if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
  3101. result = safe_array_get_dim_ms (safearray);
  3102. } else {
  3103. g_assert_not_reached ();
  3104. }
  3105. return result;
  3106. }
  3107. #endif /* HOST_WIN32 */
  3108. #ifdef HOST_WIN32
  3109. #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
  3110. static int
  3111. mono_marshal_win_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
  3112. {
  3113. return SafeArrayGetLBound ((SAFEARRAY*)psa, nDim, plLbound);
  3114. }
  3115. #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
  3116. static int
  3117. mono_marshal_win_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
  3118. {
  3119. g_unsupported_api ("SafeArrayGetLBound");
  3120. SetLastError (ERROR_NOT_SUPPORTED);
  3121. return MONO_E_NOTIMPL;
  3122. }
  3123. #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
  3124. static int
  3125. mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
  3126. {
  3127. return mono_marshal_win_safe_array_get_lbound (psa, nDim, plLbound);
  3128. }
  3129. #else /* HOST_WIN32 */
  3130. static int
  3131. mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
  3132. {
  3133. int result=MONO_S_OK;
  3134. if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
  3135. result = safe_array_get_lbound_ms (psa, nDim, plLbound);
  3136. } else {
  3137. g_assert_not_reached ();
  3138. }
  3139. return result;
  3140. }
  3141. #endif /* HOST_WIN32 */
  3142. #ifdef HOST_WIN32
  3143. #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
  3144. static int
  3145. mono_marshal_win_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
  3146. {
  3147. return SafeArrayGetUBound ((SAFEARRAY*)psa, nDim, plUbound);
  3148. }
  3149. #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
  3150. static int
  3151. mono_marshal_win_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
  3152. {
  3153. g_unsupported_api ("SafeArrayGetUBound");
  3154. SetLastError (ERROR_NOT_SUPPORTED);
  3155. return MONO_E_NOTIMPL;
  3156. }
  3157. #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
  3158. static int
  3159. mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
  3160. {
  3161. return mono_marshal_win_safe_array_get_ubound (psa, nDim, plUbound);
  3162. }
  3163. #else /* HOST_WIN32 */
  3164. static int
  3165. mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
  3166. {
  3167. int result=MONO_S_OK;
  3168. if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
  3169. result = safe_array_get_ubound_ms (psa, nDim, plUbound);
  3170. } else {
  3171. g_assert_not_reached ();
  3172. }
  3173. return result;
  3174. }
  3175. #endif /* HOST_WIN32 */
  3176. /* This is an icall */
  3177. static gboolean
  3178. mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
  3179. {
  3180. ERROR_DECL (error);
  3181. int dim;
  3182. uintptr_t *sizes;
  3183. intptr_t *bounds;
  3184. MonoClass *aklass;
  3185. int i;
  3186. gboolean bounded = FALSE;
  3187. #ifndef HOST_WIN32
  3188. // If not on windows, check that the MS provider is used as it is
  3189. // required for SAFEARRAY support.
  3190. // If SAFEARRAYs are not supported, returning FALSE from this
  3191. // function will prevent the other mono_marshal_safearray_xxx functions
  3192. // from being called.
  3193. if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
  3194. return FALSE;
  3195. }
  3196. #endif
  3197. (*(int*)empty) = TRUE;
  3198. if (safearray != NULL) {
  3199. dim = mono_marshal_safearray_get_dim (safearray);
  3200. if (dim > 0) {
  3201. *indices = g_malloc (dim * sizeof(int));
  3202. sizes = g_newa (uintptr_t, dim);
  3203. bounds = g_newa (intptr_t, dim);
  3204. for (i=0; i<dim; ++i) {
  3205. glong lbound, ubound;
  3206. int cursize;
  3207. int hr;
  3208. hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
  3209. if (hr < 0) {
  3210. cominterop_set_hr_error (error, hr);
  3211. if (mono_error_set_pending_exception (error))
  3212. return FALSE;
  3213. }
  3214. if (lbound != 0)
  3215. bounded = TRUE;
  3216. hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
  3217. if (hr < 0) {
  3218. cominterop_set_hr_error (error, hr);
  3219. if (mono_error_set_pending_exception (error))
  3220. return FALSE;
  3221. }
  3222. cursize = ubound-lbound+1;
  3223. sizes [i] = cursize;
  3224. bounds [i] = lbound;
  3225. ((int*)*indices) [i] = lbound;
  3226. if (cursize != 0)
  3227. (*(int*)empty) = FALSE;
  3228. }
  3229. if (allocateNewArray) {
  3230. aklass = mono_class_create_bounded_array (mono_defaults.object_class, dim, bounded);
  3231. *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, error);
  3232. if (mono_error_set_pending_exception (error))
  3233. return FALSE;
  3234. } else {
  3235. *result = (MonoArray *)parameter;
  3236. }
  3237. }
  3238. }
  3239. return TRUE;
  3240. }
  3241. /* This is an icall */
  3242. #ifdef HOST_WIN32
  3243. #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
  3244. static int
  3245. mono_marshal_win_safearray_get_value (gpointer safearray, gpointer indices, gpointer *result)
  3246. {
  3247. return SafeArrayPtrOfIndex ((SAFEARRAY*)safearray, (LONG*)indices, result);
  3248. }
  3249. #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
  3250. static int
  3251. mono_marshal_win_safearray_get_value (gpointer safearray, gpointer indices, gpointer *result)
  3252. {
  3253. ERROR_DECL (error);
  3254. g_unsupported_api ("SafeArrayPtrOfIndex");
  3255. mono_error_set_not_supported (error, G_UNSUPPORTED_API, "SafeArrayPtrOfIndex");
  3256. mono_error_set_pending_exception (error);
  3257. SetLastError (ERROR_NOT_SUPPORTED);
  3258. return MONO_E_NOTIMPL;
  3259. }
  3260. #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
  3261. static gpointer
  3262. mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
  3263. {
  3264. ERROR_DECL (error);
  3265. gpointer result;
  3266. int hr = mono_marshal_win_safearray_get_value (safearray, indices, &result);
  3267. if (hr < 0) {
  3268. cominterop_set_hr_error (error, hr);
  3269. mono_error_set_pending_exception (error);
  3270. result = NULL;
  3271. }
  3272. return result;
  3273. }
  3274. #else /* HOST_WIN32 */
  3275. static gpointer
  3276. mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
  3277. {
  3278. ERROR_DECL (error);
  3279. gpointer result;
  3280. if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
  3281. int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
  3282. if (hr < 0) {
  3283. cominterop_set_hr_error (error, hr);
  3284. mono_error_set_pending_exception (error);
  3285. return NULL;
  3286. }
  3287. } else {
  3288. g_assert_not_reached ();
  3289. }
  3290. return result;
  3291. }
  3292. #endif /* HOST_WIN32 */
  3293. /* This is an icall */
  3294. static
  3295. gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
  3296. {
  3297. ERROR_DECL (error);
  3298. int i;
  3299. int dim = mono_marshal_safearray_get_dim (safearray);
  3300. gboolean ret= TRUE;
  3301. int *pIndices = (int*) indices;
  3302. int hr;
  3303. for (i=dim-1; i>=0; --i)
  3304. {
  3305. glong lbound, ubound;
  3306. hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
  3307. if (hr < 0) {
  3308. cominterop_set_hr_error (error, hr);
  3309. mono_error_set_pending_exception (error);
  3310. return FALSE;
  3311. }
  3312. if (++pIndices[i] <= ubound) {
  3313. break;
  3314. }
  3315. hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
  3316. if (hr < 0) {
  3317. cominterop_set_hr_error (error, hr);
  3318. mono_error_set_pending_exception (error);
  3319. return FALSE;
  3320. }
  3321. pIndices[i] = lbound;
  3322. if (i == 0)
  3323. ret = FALSE;
  3324. }
  3325. return ret;
  3326. }
  3327. #ifdef HOST_WIN32
  3328. #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
  3329. static void
  3330. mono_marshal_win_safearray_end (gpointer safearray, gpointer indices)
  3331. {
  3332. g_free(indices);
  3333. SafeArrayDestroy ((SAFEARRAY*)safearray);
  3334. }
  3335. #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
  3336. static void
  3337. mono_marshal_win_safearray_end (gpointer safearray, gpointer indices)
  3338. {
  3339. g_free(indices);
  3340. g_unsupported_api ("SafeArrayDestroy");
  3341. SetLastError (ERROR_NOT_SUPPORTED);
  3342. }
  3343. #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
  3344. static void
  3345. mono_marshal_safearray_end (gpointer safearray, gpointer indices)
  3346. {
  3347. mono_marshal_win_safearray_end (safearray, indices);
  3348. }
  3349. #else /* HOST_WIN32 */
  3350. static void
  3351. mono_marshal_safearray_end (gpointer safearray, gpointer indices)
  3352. {
  3353. g_free(indices);
  3354. if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
  3355. safe_array_destroy_ms (safearray);
  3356. } else {
  3357. g_assert_not_reached ();
  3358. }
  3359. }
  3360. #endif /* HOST_WIN32 */
  3361. #ifdef HOST_WIN32
  3362. #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
  3363. static gboolean
  3364. mono_marshal_win_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
  3365. {
  3366. *newsafearray = SafeArrayCreate (VT_VARIANT, cDims, rgsabound);
  3367. return TRUE;
  3368. }
  3369. #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
  3370. static gboolean
  3371. mono_marshal_win_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
  3372. {
  3373. g_unsupported_api ("SafeArrayCreate");
  3374. SetLastError (ERROR_NOT_SUPPORTED);
  3375. *newsafearray = NULL;
  3376. return FALSE;
  3377. }
  3378. #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
  3379. static gboolean
  3380. mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
  3381. {
  3382. return mono_marshal_win_safearray_create_internal (cDims, rgsabound, newsafearray);
  3383. }
  3384. #else /* HOST_WIN32 */
  3385. static gboolean
  3386. mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
  3387. {
  3388. *newsafearray = safe_array_create_ms (VT_VARIANT, cDims, rgsabound);
  3389. return TRUE;
  3390. }
  3391. #endif /* HOST_WIN32 */
  3392. static gboolean
  3393. mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
  3394. {
  3395. #ifndef HOST_WIN32
  3396. // If not on windows, check that the MS provider is used as it is
  3397. // required for SAFEARRAY support.
  3398. // If SAFEARRAYs are not supported, returning FALSE from this
  3399. // function will prevent the other mono_marshal_safearray_xxx functions
  3400. // from being called.
  3401. if (com_provider != MONO_COM_MS || !init_com_provider_ms ()) {
  3402. return FALSE;
  3403. }
  3404. #endif
  3405. int const max_array_length = mono_array_length_internal (input);
  3406. int const dim = m_class_get_rank (mono_object_class (input));
  3407. *indices = g_malloc (dim * sizeof (int));
  3408. SAFEARRAYBOUND * const bounds = g_newa (SAFEARRAYBOUND, dim);
  3409. (*(int*)empty) = (max_array_length == 0);
  3410. if (dim > 1) {
  3411. for (int i = 0; i < dim; ++i) {
  3412. ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
  3413. bounds [i].cElements = input->bounds [i].length;
  3414. }
  3415. } else {
  3416. ((int*)*indices) [0] = 0;
  3417. bounds [0].cElements = max_array_length;
  3418. bounds [0].lLbound = 0;
  3419. }
  3420. return mono_marshal_safearray_create_internal (dim, bounds, newsafearray);
  3421. }
  3422. /* This is an icall */
  3423. #ifdef HOST_WIN32
  3424. #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
  3425. static int
  3426. mono_marshal_win_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
  3427. {
  3428. return SafeArrayPutElement ((SAFEARRAY*)safearray, (LONG*)indices, value);
  3429. }
  3430. #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
  3431. static int
  3432. mono_marshal_win_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
  3433. {
  3434. ERROR_DECL (error);
  3435. g_unsupported_api ("SafeArrayPutElement");
  3436. mono_error_set_not_supported (error, G_UNSUPPORTED_API, "SafeArrayPutElement");
  3437. mono_error_set_pending_exception (error);
  3438. SetLastError (ERROR_NOT_SUPPORTED);
  3439. return MONO_E_NOTIMPL;
  3440. }
  3441. #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
  3442. #endif /* HOST_WIN32 */
  3443. static void
  3444. mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
  3445. {
  3446. ERROR_DECL (error);
  3447. #ifdef HOST_WIN32
  3448. int const hr = mono_marshal_win_safearray_set_value (safearray, indices, value);
  3449. #else
  3450. int hr = 0;
  3451. if (com_provider == MONO_COM_MS && init_com_provider_ms ())
  3452. hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
  3453. else
  3454. g_assert_not_reached ();
  3455. #endif
  3456. if (hr < 0) {
  3457. cominterop_set_hr_error (error, hr);
  3458. mono_error_set_pending_exception (error);
  3459. }
  3460. }
  3461. static
  3462. void mono_marshal_safearray_free_indices (gpointer indices)
  3463. {
  3464. g_free (indices);
  3465. }
  3466. #else /* DISABLE_COM */
  3467. void
  3468. mono_cominterop_cleanup (void)
  3469. {
  3470. }
  3471. void
  3472. mono_cominterop_release_all_rcws (void)
  3473. {
  3474. }
  3475. gboolean
  3476. mono_marshal_free_ccw (MonoObject* object)
  3477. {
  3478. return FALSE;
  3479. }
  3480. #ifdef HOST_WIN32
  3481. int
  3482. ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown *pUnk)
  3483. {
  3484. return mono_IUnknown_AddRef (pUnk);
  3485. }
  3486. int
  3487. ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown *pUnk)
  3488. {
  3489. g_assert (pUnk);
  3490. return mono_IUnknown_Release (pUnk);
  3491. }
  3492. int
  3493. ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown *pUnk, gconstpointer riid, gpointer* ppv)
  3494. {
  3495. return mono_IUnknown_QueryInterface (pUnk, riid, ppv);
  3496. }
  3497. #else /* HOST_WIN32 */
  3498. int
  3499. ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown *pUnk)
  3500. {
  3501. g_assert_not_reached ();
  3502. return 0;
  3503. }
  3504. int
  3505. ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown *pUnk)
  3506. {
  3507. g_assert_not_reached ();
  3508. return 0;
  3509. }
  3510. int
  3511. ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown *pUnk, gconstpointer riid, gpointer* ppv)
  3512. {
  3513. g_assert_not_reached ();
  3514. return 0;
  3515. }
  3516. #endif /* HOST_WIN32 */
  3517. #endif /* DISABLE_COM */
  3518. #ifndef ENABLE_NETCORE
  3519. MonoStringHandle
  3520. ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (mono_bstr_const ptr, MonoError *error)
  3521. {
  3522. if (ptr == NULL) {
  3523. mono_error_set_argument_null (error, "ptr", NULL);
  3524. return NULL_HANDLE_STRING;
  3525. }
  3526. return mono_string_from_bstr_checked (ptr, error);
  3527. }
  3528. #endif
  3529. mono_bstr
  3530. ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (const gunichar2* ptr, int len)
  3531. {
  3532. return mono_ptr_to_bstr (ptr, len);
  3533. }
  3534. void
  3535. ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (mono_bstr_const ptr)
  3536. {
  3537. mono_free_bstr ((gpointer)ptr);
  3538. }
  3539. void*
  3540. mono_cominterop_get_com_interface (MonoObject *object_raw, MonoClass *ic, MonoError *error)
  3541. {
  3542. HANDLE_FUNCTION_ENTER ();
  3543. MONO_HANDLE_DCL (MonoObject, object);
  3544. void* const result = mono_cominterop_get_com_interface_internal (FALSE, object, ic, error);
  3545. HANDLE_FUNCTION_RETURN_VAL (result);
  3546. }
  3547. static void*
  3548. mono_cominterop_get_com_interface_internal (gboolean icall, MonoObjectHandle object, MonoClass *ic, MonoError *error)
  3549. {
  3550. // Common code for mono_cominterop_get_com_interface and
  3551. // ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal,
  3552. // which are almost identical.
  3553. #ifndef DISABLE_COM
  3554. if (MONO_HANDLE_IS_NULL (object))
  3555. return NULL;
  3556. MonoRealProxyHandle real_proxy;
  3557. if (cominterop_object_is_rcw_handle (object, &real_proxy)) {
  3558. MonoClass *klass = NULL;
  3559. klass = mono_handle_class (object);
  3560. if (!mono_class_is_transparent_proxy (klass)) {
  3561. g_assertf (!icall, "Class is not transparent");
  3562. mono_error_set_invalid_operation (error, "Class is not transparent");
  3563. return NULL;
  3564. }
  3565. if (MONO_HANDLE_IS_NULL (real_proxy)) {
  3566. g_assertf (!icall, "RealProxy is null");
  3567. mono_error_set_invalid_operation (error, "RealProxy is null");
  3568. return NULL;
  3569. }
  3570. klass = mono_handle_class (real_proxy);
  3571. if (klass != mono_class_get_interop_proxy_class ()) {
  3572. g_assertf (!icall, "Object is not a proxy");
  3573. mono_error_set_invalid_operation (error, "Object is not a proxy");
  3574. return NULL;
  3575. }
  3576. MonoComInteropProxyHandle com_interop_proxy = MONO_HANDLE_CAST (MonoComInteropProxy, real_proxy);
  3577. MonoComObjectHandle com_object = MONO_HANDLE_NEW_GET (MonoComObject, com_interop_proxy, com_object);
  3578. if (MONO_HANDLE_IS_NULL (com_object)) {
  3579. g_assertf (!icall, "Proxy points to null COM object");
  3580. mono_error_set_invalid_operation (error, "Proxy points to null COM object");
  3581. return NULL;
  3582. }
  3583. if (icall)
  3584. return MONO_HANDLE_GETVAL (com_object, iunknown);
  3585. return cominterop_get_interface_checked (com_object, ic, error);
  3586. }
  3587. else {
  3588. if (icall)
  3589. ic = mono_class_get_iunknown_class ();
  3590. return cominterop_get_ccw_checked (object, ic, error);
  3591. }
  3592. #else
  3593. g_assert_not_reached ();
  3594. #endif
  3595. }
  3596. gboolean
  3597. mono_cominterop_is_interface (MonoClass* klass)
  3598. {
  3599. #ifndef DISABLE_COM
  3600. ERROR_DECL (error);
  3601. MonoCustomAttrInfo* cinfo = NULL;
  3602. gboolean ret = FALSE;
  3603. int i;
  3604. cinfo = mono_custom_attrs_from_class_checked (klass, error);
  3605. mono_error_assert_ok (error);
  3606. if (cinfo) {
  3607. for (i = 0; i < cinfo->num_attrs; ++i) {
  3608. MonoClass *ctor_class = cinfo->attrs [i].ctor->klass;
  3609. if (mono_class_has_parent (ctor_class, mono_class_get_interface_type_attribute_class ())) {
  3610. ret = TRUE;
  3611. break;
  3612. }
  3613. }
  3614. if (!cinfo->cached)
  3615. mono_custom_attrs_free (cinfo);
  3616. }
  3617. return ret;
  3618. #else
  3619. g_assert_not_reached ();
  3620. #endif
  3621. }