From e3bed19e79b537b7861e16931fb4e509c8281097 Mon Sep 17 00:00:00 2001
From: Matt Nadareski
+ /// Set this value for all components belonging to a feature to prevent the feature from being run-from-network or
+ /// run-from-source. Note that if a feature has no components, the feature always shows run-from-source and
+ /// run-from-my-computer as valid options.
+ ///
+ /// Set this bit for all components belonging to a feature to prevent the feature from being run-from-my-computer.
+ /// Note that if a feature has no components, the feature always shows run-from-source and run-from-my-computer
+ /// as valid options.
+ ///
+ /// If the Value field of the corresponding record in the Registry table is null, the Name field in that record
+ /// must not contain "+", "-", or "*". For more information, see the description of the Name field in Registry
+ /// table.
+ /// Setting this bit is recommended for registry entries written to the HKCU hive. This ensures the installer
+ /// writes the necessary HKCU registry entries when there are multiple users on the same machine.
+ /// Use this flag only for components that are being registered by the Registry table. Do not use this flag for + /// components registered by the AppId, Class, Extension, ProgId, MIME, and Verb tables. + ///
+ /// If this is a 64-bit component replacing a 32-bit component, set this bit and assign a new GUID in the + /// ComponentId column. + ///
+ /// If this bit is set, the Windows Installer calls the RegDisableReflectionKey on each key being accessed by the component. + /// This bit is available with Windows Installer version 4.0 and is ignored on 32-bit systems. + ///
+ /// If a subsequent patch is installed, marked with the SupersedeEarlier flag in its MsiPatchSequence + /// table to supersede the first patch, Windows Installer 4.5 can unregister and uninstall components marked with the + /// UninstallOnSupersedence value. If the component is not marked with this bit, installation of a superseding patch can leave + /// behind an unused component on the computer. + ///
+ /// A component shared by two or more features, some of which are set to FavorLocal and some to FavorSource,
+ /// is installed locally. Components marked
+ /// A component shared by two or more features, some of which are set to FavorLocal and some to FavorSource,
+ /// is installed to run locally. Components marked
+ /// Omit this attribute and the feature state is determined according to DisallowAdvertise and + /// FavorLocal and FavorSource. + ///
To guarantee that the child feature's state always follows the state of its parent, even when the + /// child and parent are initially set to absent in the SelectionTree control, you must include both + /// FollowParent and UIDisallowAbsent in the attributes of the child feature.
+ ///Note that if you set FollowParent without setting UIDisallowAbsent, the installer cannot force + /// the child feature out of the absent state. In this case, the child feature matches the parent's + /// installation state only if the child is set to something other than absent.
+ ///Set FollowParent and UIDisallowAbsent to ensure a child feature follows the state of the parent feature.
+ ///+ /// If the feature is listed by the ADDDEFAULT property this bit is ignored and the feature state is determined + /// according to FavorLocal and FavorSource. + ///
Omit this attribute and the feature state is determined according to DisallowAdvertise and FavorLocal + /// and FavorSource.
+ ///+ /// Note that this bit works only with features that are listed by the ADVERTISE property. + ///
Set this attribute and if the listed feature is not a parent or child, the feature is installed according to + /// FavorLocal and FavorSource.
+ ///Set this attribute for the parent of a listed feature and the parent is installed.
+ ///Set this attribute for the child of a listed feature and the state of the child is Absent.
+ ///Omit this attribute and if the listed feature is not a parent or child, the feature state is Advertise.
+ ///Omit this attribute and if the listed feature is a parent or child, the state of both features is Advertise.
+ ///+ /// Omit this attribute and the user interface displays an option to change the feature state to Absent. + ///
Set FollowParent and UIDisallowAbsent to ensure a child feature follows the state of the parent feature.
+ ///Setting this attribute not only affects the UI, but also forces the feature to the install state whether + /// the feature is visible in the UI or not.
+ ///
+ /// Examples:
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Win32 MSI API: + /// MsiGetComponentState + ///
+ /// Win32 MSI APIs: + /// MsiGetComponentState, + /// MsiSetComponentState + ///
+ /// Win32 MSI API: + /// MsiEnumComponentCosts + ///
+ /// Win32 MSI API: + /// MsiEnumComponents + ///
+ /// Win32 MSI API: + /// MsiEnumComponentsEx + ///
+ /// Win32 MSI API: + /// MsiGetProductCode + ///
+ /// Because clients are not ordered, any new component has an arbitrary index. + /// This means that the property may return clients in any order. + ///
+ /// Win32 MSI API: + /// MsiEnumClients, + /// MsiEnumClientsEx + ///
+ /// Win32 MSI API: + /// MsiGetComponentPath, + /// MsiGetComponentPathEx + ///
+ /// If the component is a registry key, the registry roots are represented numerically. + /// For example, a registry path of "HKEY_CURRENT_USER\SOFTWARE\Microsoft" would be returned + /// as "01:\SOFTWARE\Microsoft". The registry roots returned are defined as follows: + /// HKEY_CLASSES_ROOT=00, HKEY_CURRENT_USER=01, HKEY_LOCAL_MACHINE=02, HKEY_USERS=03, + /// HKEY_PERFORMANCE_DATA=04 + ///
+ /// Win32 MSI APIs: + /// MsiGetComponentPath, + /// MsiGetComponentPathEx, + /// MsiLocateComponent + ///
+ /// Because qualifiers are not ordered, any new qualifier has an arbitrary index, + /// meaning the function can return qualifiers in any order. + ///
+ /// Win32 MSI API: + /// MsiEnumComponentQualifiers + ///
+ /// Win32 MSI API: + /// MsiEnumComponentQualifiers + ///
+ /// A custom action method must be defined as public and static,
+ /// take a single
+ /// The
+ /// The client can use the following procedure for data access:
+ ///
+ ///
+ /// Because this constructor initiates database access, it cannot be used with a + /// running installation. + ///
+ /// The Database object should be
+ /// Win32 MSI API: + /// MsiOpenDatabase + ///
+ /// When a database is opened as the output of another database, the summary information stream + /// of the output database is actually a read-only mirror of the original database and thus cannot + /// be changed. Additionally, it is not persisted with the database. To create or modify the + /// summary information for the output database it must be closed and re-opened. + ///
+ /// The Database object should be
+ /// The database is opened in
+ /// Win32 MSI API: + /// MsiOpenDatabase + ///
+ /// Because this constructor initiates database access, it cannot be used with a + /// running installation. + ///
+ /// The database object should be
+ /// A database opened in
+ /// Win32 MSI API: + /// MsiOpenDatabase + ///
+ /// Win32 MSI API: + /// MsiGetDatabaseState + ///
+ /// Getting or setting the code page is a slow operation because it involves an export or import + /// of the codepage data to/from a temporary file. + ///
+ /// The object returned from this property does not need to be explicitly persisted or closed. + /// Any modifications will be automatically saved when the database is committed. + ///
+ /// Win32 MSI API: + /// MsiGetSummaryInformation + ///
+ /// This method is only provided for interop purposes. A Database object
+ /// should normally be obtained from
+ /// Once an item is scheduled, it cannot be unscheduled. + ///
+ /// The items cannot be deleted if the Database object is auto-disposed by the + /// garbage collector; the handle must be explicitly closed. + ///
+ /// Files which are read-only or otherwise locked cannot be deleted, + /// but they will not cause an exception to be thrown. + ///
+ /// Merge does not copy over embedded cabinet files or embedded transforms from the + /// reference database into the target database. Embedded data streams that are listed in the + /// Binary table or Icon table are copied from the reference database to the target database. + /// Storage embedded in the reference database are not copied to the target database. + ///
+ /// The Merge method merges the data of two databases. These databases must have the same + /// codepage. The merge fails if any tables or rows in the databases conflict. A conflict exists + /// if the data in any row in the first database differs from the data in the corresponding row + /// of the second database. Corresponding rows are in the same table of both databases and have + /// the same primary key in both databases. The tables of non-conflicting databases must have + /// the same number of primary keys, same number of columns, same column types, same column names, + /// and the same data in rows with identical primary keys. Temporary columns however don't matter + /// in the column count and corresponding tables can have a different number of temporary columns + /// without creating conflict as long as the persistent columns match. + ///
+ /// If the number, type, or name of columns in corresponding tables are different, the + /// schema of the two databases are incompatible and the installer will stop processing tables + /// and the merge fails. The installer checks that the two databases have the same schema before + /// checking for row merge conflicts. If the schemas are incompatible, the databases have be + /// modified. + ///
+ /// If the data in particular rows differ, this is a row merge conflict, the merge fails + /// and creates a new table with the specified name. The first column of this table is the name + /// of the table having the conflict. The second column gives the number of rows in the table + /// having the conflict. + ///
+ /// Win32 MSI API: + /// MsiDatabaseMerge + ///
+ /// MsiDatabaseMerge does not copy over embedded cabinet files or embedded transforms from + /// the reference database into the target database. Embedded data streams that are listed in + /// the Binary table or Icon table are copied from the reference database to the target database. + /// Storage embedded in the reference database are not copied to the target database. + ///
+ /// The Merge method merges the data of two databases. These databases must have the same + /// codepage. The merge fails if any tables or rows in the databases conflict. A conflict exists + /// if the data in any row in the first database differs from the data in the corresponding row + /// of the second database. Corresponding rows are in the same table of both databases and have + /// the same primary key in both databases. The tables of non-conflicting databases must have + /// the same number of primary keys, same number of columns, same column types, same column names, + /// and the same data in rows with identical primary keys. Temporary columns however don't matter + /// in the column count and corresponding tables can have a different number of temporary columns + /// without creating conflict as long as the persistent columns match. + ///
+ /// If the number, type, or name of columns in corresponding tables are different, the + /// schema of the two databases are incompatible and the installer will stop processing tables + /// and the merge fails. The installer checks that the two databases have the same schema before + /// checking for row merge conflicts. If the schemas are incompatible, the databases have be + /// modified. + ///
+ /// Win32 MSI API: + /// MsiDatabaseMerge + ///
+ /// To check whether a table exists regardless of persistence,
+ /// use
+ /// Win32 MSI API: + /// MsiDatabaseIsTablePersistent + ///
+ /// To check whether a column exists regardless of persistence,
+ /// use
+ /// For a database open in
+ /// For a database open in
+ /// For a database open in
+ /// Win32 MSI API: + /// MsiDatabaseCommit + ///
+ /// Win32 MSI API: + /// MsiDatabaseExport + ///
+ /// Win32 MSI API: + /// MsiDatabaseImport + ///
+ /// The directory will be created if it does not already exist. + ///
+ /// Win32 MSI API: + /// MsiDatabaseExport + ///
+ /// Win32 MSI API: + /// MsiDatabaseImport + ///
+ /// This method is equivalent to directly calling the
+ /// The Record object should be
+ /// Win32 MSI API: + /// MsiCreateRecord + ///
+ /// The
+ /// The View object should be
+ /// Win32 MSI API: + /// MsiDatabaseOpenView + ///
+ /// The
+ /// Win32 MSI APIs: + /// MsiDatabaseOpenView, + /// MsiViewExecute + ///
+ /// Win32 MSI APIs: + /// MsiDatabaseOpenView, + /// MsiViewExecute + ///
+ /// The
+ /// Multiple rows columns will be collapsed into a single one-dimensional list. + ///
+ /// Win32 MSI APIs: + /// MsiDatabaseOpenView, + /// MsiViewExecute, + /// MsiViewFetch + ///
+ /// Multiple rows columns will be collapsed into a single one-dimensional list. + ///
+ /// Win32 MSI APIs: + /// MsiDatabaseOpenView, + /// MsiViewExecute, + /// MsiViewFetch + ///
+ /// The
+ /// Multiple rows columns will be collapsed into a single one-dimensional list. + ///
+ /// Win32 MSI APIs: + /// MsiDatabaseOpenView, + /// MsiViewExecute, + /// MsiViewFetch + ///
+ /// Multiple rows columns will be collapsed into a single one-dimensional list. + ///
+ /// Win32 MSI APIs: + /// MsiDatabaseOpenView, + /// MsiViewExecute, + /// MsiViewFetch + ///
+ /// The
+ /// Multiple rows columns will be collapsed into a single on-dimensional list. + ///
+ /// Win32 MSI APIs: + /// MsiDatabaseOpenView, + /// MsiViewExecute, + /// MsiViewFetch + ///
+ /// Multiple rows columns will be collapsed into a single on-dimensional list. + ///
+ /// Win32 MSI APIs: + /// MsiDatabaseOpenView, + /// MsiViewExecute, + /// MsiViewFetch + ///
+ /// The
+ /// Win32 MSI APIs: + /// MsiDatabaseOpenView, + /// MsiViewExecute, + /// MsiViewFetch + ///
+ /// Win32 MSI APIs: + /// MsiDatabaseOpenView, + /// MsiViewExecute, + /// MsiViewFetch + ///
+ /// A transform can add non-primary key columns to the end of a table. A transform cannot + /// be created that adds primary key columns to a table. A transform cannot be created that + /// changes the order, names, or definitions of columns. + ///
+ /// If the transform is to be applied during an installation you must use the
+ ///
+ /// Win32 MSI API: + /// MsiDatabaseGenerateTransform + ///
+ /// Win32 MSI API: + /// MsiCreateTransformSummaryInfo + ///
+ /// Win32 MSI API: + /// MsiDatabaseApplyTransform + ///
+ /// Win32 MSI API: + /// MsiDatabaseApplyTransform + ///
+ /// Win32 MSI API: + /// MsiDatabaseApplyTransform + ///
Ff{QpFqHB#Fl6vDFhuh*Fj(+0Fu3wDFv#&SFlh5JFtG43 zFbMK7FudYrVEE33%)r1c%)qc$h=Jjh5Cg+vAqIvGLJSO@LJSPkgcum|g%}uWgcul-gcul> z3o|gx5@uj17G_{b6J}uO6=q;)5N2SA6lP%X5oTccC&a+;QHX)zi4X(Bbs+`@eh~%+ zCJ_b(14RY~4kHFb1_K5|aO#0_j2KiH;4;Pxb_k9MLk@yt$}k nrTI7SRl5FBF$ zab~z46NV53$CRNC!7&4uvm8bYAfwG0ZXjeV7=9r*mJIqVP}4xJjzDk>8Tt_%BZk8W zjxob$1jhtirhx4+WH4n2V1=7z#!!pkm@{lea4ZU0mCc=$B^M7 zf@8$+AHgwZu;7FmV9a2`P=?@`GHgR|%ozS5IOYuIpmqS*3C0W-3^_ oo(Y2i z!!0D9A%iG4)GiYSBZdG3$C#lE!7*Xjir| DsXD>GpzKyXYMb|W}u4E&&y2$UL48O#~l5F87J zJqV5^!y6dKjKP3GSO99Y8G|8%ErMgjkc;3LGt5D7Oc+ifIHnB05F9fGbwRjk<_uv7 zjs-(If@8^W5ymlRFksLYg6c76Fa#G=;K(y)Fk-ljkTGU35r!)>0hd=$Wu^=&B5)Zq zh8zUPoMAbFW5I9{!Lek}7lrDvU@&0FL2wKimLWJs4A&qWP?9xb_<-OTGf0Yo4FJiQ zFt{T)rVMQejv2!)1jn4=FM?yiAR`Vpz>>il#sL)&l?aY0!&U^xg5eT^W6AIa#sOt% zMG2^Bpn}p8!7*Y8MsSQ7k`NpdhAITdlwlcyW5#eF!7*p}gWy;&=u5)wv1EvYaX_Ka zjo=tE971r67=9o)#td3gPy;|&ItIZpWmt~jm@%A0aLgH)rQv!k7z_{`ONMM12b7 GlFBt z5Q^X!F)T)Kj2ZqSI3^4{a&QAo8I%zmGX@g`$DAP+!LeW{L2xV?w!t`{9Q+Q!F=Y6M z;21Fo$wTciV=!jWL~u+PA`u)@hE4>>jA1o`W6rP>!LeXC2IGJ-ZJYwsXi%m-j^G$E z{6%n#84@9F1Y-ts1`~!h1jm%&2!dnA@Cd=NWcUW-fU>5R64V|G21AB;1jmS>4#ELN zydlFB1jmTsA%p{p9YcnX2#yhhoHE!nkc=@yFoXjNLPLfo1jmSBC4ytj@BzUwVc_Lb z0h<8QWXhn7;FvM^A~@y@tq6_JHgF*s^~^?+oI z8D=6lCJg5g98-pG2#y(ph9+E(IYTjmW5KWw!Lej`4C8=GJ9RCn9#DX!AUH-0OAs7m zhI j7-I7STj5FBF$ zPF<)0Mhqql<_L}{!y5$0jDb}TuFRZ42Enmlh(&NL8LD6$P}w;f!7*fbjNlkCu r8N*cs$DF~@46et5p%}rjWLOB}fHL$e1jmrU!W^o{ zjKPSZ3c)dE*nr@eGTcRQ%oyY>;Cjp%d=MN9hGGQAl3_NC1Ik+`5gbDX4oj#3pw^Ei zgaaxC4H>c!93zG~2#ztsF$Bki;V*(?$`E1&HVtHe8ABL?W6scn;8-xMM{q0|?!q{r zteI*JH2{<~Zy-2E42m{z8Dj=#1jmG7I)Y=$@BzUwW3aG=>oI4Tgy2{(JV0 uc ku4c21!r29utQ72#zU3pch=mjA0{!W6tmf!LeWv_J%97 zWC(z9K>2hgf@8?=4Z$&Dko1A-F=sGlNI-B*7*-=VrVN)595aSr2#z^}r7zq73x-$( z$CBX?j04KU%zjX1pr()^f@8$siQpJB6eBn$4D%5jQ-*U0ju`{9Kio8P24w`tg25lb zv1G`HaV!}O7}g;;h73;;93uw)0H|q}48{yW2#yKETLj0HK_d{Z%#0x!!7*oOL~tw^ zHXt~b41XXTko|@XHbGzmKpZ26d<4gsVH$#C!mt6sF=aT9;FvM|L2%3&6oTQVSujK* zIF<}GFb=2~T!`QpGMqwij2PY^IF<|wAyCsm1(!d9W5Q62;FvSqM{q0{{v$Y+4A!Ag z1B@Ar7;+FCV}>ONjtRqg1jm%&7lLEPpb-W)z?{Jy!LeXif#6s&NQOg|fl8MS1jmqJ zKZ0Y#@B+axW{{15>oH;ILU2qO)_^$1;ITDBh9?M)5kpEO0|TQ{a7KPnNpfjPu|i&c zi9&H{K|y{|NotBhQl&ykMyi5;upXm?XI@!iPG*XNo~NIuLSk}BW`3TPLbOpVqmFZa zX-*1QXHjZ#eok4cLP26lhC*6?kwS4sYEF(qT7FJSY7t1W9;0S>QD#YIUOL2_w9K4T zD}`v|SStm{!U~1dqN4mFh{5_WXDK)rr6z(b1gTVTOU%qkP0_=v!6h{(l?V;$t{~gM zrWU29XBL;F7J-~rQdy9ykdv8Ilvq>=bu~g^X&!#1^1-R#z){G}EG`C_1_}p6nCUS} zd#6_7l#F*tErIIKPg5u=&C3HBkyubrtdIuww~j(GJh; P5J@(WUnAR$(iT2fk+mztsg4pTkG1WGK(%u7kFAY_9gAsh4 ;e5Bx+msygTn3Gur@i0tF zerbt9ewspVYHof}r5>Xpnl2DmAu%~QwHOhyXj;%+>71Ac${zUzsd?a_26;dMl!8&y zBE*#%APYb$psox_Ov*`BNX#ipO-!j&NUg{$E-415d`9dlQ}R J}U>==#Ev?0nDaJqnK1O=@^2{=%rjbj 1gfPEYk5Lz^YLJ;A<*5~*;u4$^AmOf!rW`rpWagqNHbYbF ziBJFv_T0o0c$sJ%tE1qPnU|^%Z4%39j;1fXC_gV<0qi}6l6**!nd)C!Qczj~Qwa)P z%; 2s(Rv{%bEe)K2i}G{9c7x+J8E##)Nvs~D9h#{yZm~jQQ7X6wEKbZ# z)l=}xS15s7n4X#kDq}$bg|6QnDg}3)6+9;@B@7wQn1#?#L(&IL zItXhM6-rV;!2+t9z$qHVB)C23CP8ZtJw{73yI?VtnUb1Ul9`s7TBM*JZ5*o(3jg3h zABDow)S^l&aEe1Octi8D^YY8{pt%s2E{swXUVY`{C#De4j9!8Sr52 kU?82&QG%t@hnsTBpO$zW?hi$HN&V}ll!e)-U1tQZ`6u0F2LAqvSkiKWG< zU;(7yG>*kcb*Q@igIrvL6r3V)>vu!5-5FAXLgE2bQ56)W7K6(1{33 43F{2DmtexDuf?Gp{(cs02Bp zF>F=A7c)iBB+O`wrphm0p`a);7nHGK?n+5b%LKLEKut(UiU-$#nfZBo7}{ac2Ch(x z3sRGDWoA%b)?-xh3@*tpN=#3+vI;IqEP<8}3gww48Ibx0RD5Do#V|_{RRE%70u{rF zC3 f+C<|=?%K>DD%GZk!UX;G>kV<}2lC}0$z`o5sD-AVzP#=(Bf%u@gt z=8%8^wU_eLOB8YwOOi7bic-^3i&8;tVz4Z783{5&K^an_#S^gBO2Ie32vjG5+9u#+ zf@EV!Mk1)igU>ET)Di*_7FG(-f;}-M1=1J zHK3(~f^&XBWk^0ar()@JgIeB*=6O+SZhl!RET2b%dUj~NdgE9|-QbcUP%!`s7;u9V zoLHgl6-?zwqYL1US20944#V|Gbc{AaeR6(oZf1!>F{D&P?b1PlP8XrLC_g7BDKR-4 zpK^VKa%et
TvOLd(36jMSo3g>n!9YvDqg$i)gpsi4k8Y6_@z5p5g` zNf*U>j1ef2tfzo530iM~1`+Z~psizwe$YS C>fx`bbEva#;FBE!m+V0CT%Sd1g)yIPF2Ip~SpO zh2)IHy!6y!g{0JEaC;3D9PoZ%W-(|)B@dhfbwN2$k1+*i7&PUAgBT&^h+Hk?gF_Nr zb-;}*Pb^j_NGvW+O;JcJ2FoMrESMra#&$-8k>DhcW=&`wDF1@`dk~+1N6(5ud`O2D z9F=+skdz1-9w%? jKa~g$0_^AW;MIH@ImBYixl00ZH26 z7y@ oLj(gLe&rhi??JQ!63u1W VGe zS*+k!nv=t5<5&XfkAs7!Bp)>JotyzND%vPkp*$lMQ~`rpq_Bnus75ZzPcKR>F4kkT zLe-s|pI4HZR|*=w0BHg1&Vw162~JG~aJ|y7zDxjUust{xRL_^dhR!9xF2z#CG8#id zxfmLypy5k}#FCPt%%sv1&~U7AEM_1vih+#-B~nl^14@yQ7?*$;22Q!41}w-lhzxIN zacYr5GH6&jCpCpp4AyY~8{`PHk5LN|f8g33Y5-P8m?PAJ2EIW`6-qL5AvFMq2Tn#< zTrUlAWo8~Y{zCFy@{3&(OHxBJb5r#g4H2e7n=dJuMXAXp`QT9xtPatIm F|Wuk({4bmRbbP zCZLdkL|jR}LQZ~iVh)4{%J3jLa5Q2wN&%G8!C|TZ%AWZp3W=cBEqI6{4eTKcsAb^k zgS>R`P#GjQ=7aNL22Qh)8-h9c#i?LjVAWU>lqDj~z L|dpD3s*qE94{=rKd7d;8zJm8v#5am|3ilnp;p(smExC za1khNDioy_mSz^Era;2O)7R16)x#%1&&9_FR26|ol|T~);M4({ax{uIinRjgW^k7m z+>`?qo{5=x3W*9}^$N)usma;JrMVz(X{sJ0H@HN~OwY?NN@av*;Y5_e8&u0Eq=5#C zlM|CN^HM>b0Z>;(j}hDp0) E?xYEfBgkpego zGWvjvI#7k89&Hq>4t8T&erX=Ku@18U+~C$z2+07|s^C#|NJWzjnQ8+02~;8IF-Cwx z3^c%z37hUpRe+fS3KxZ9u;mc5P{UK*8R8wil$;!Oh1|qSg``y21f(7#uOB!gLCs !zYya01hVBvO!(Itnm_;7l3~3T)SklGHp OhAH z!E-6mCUAaAYH@N=W&vdO-7Hp*F&$R-I|n(V
TQm|gNf@evwLI(KI28H6p z%3@HN4psuo%Q^~~CB+KK`MCw9pwW5oz%QsS0L|jmGMa#sBsimi8hw?})>uhCBpHC3 zzUT$3aV%pJq%jO~0Vp^?#zE(3KvidcngV!~4^pN;`ks0UsLeJ=I}>66DD==;#wM|h z%HXm9 WV+n{zANIBeOP%((B=7Y8#G4z0%g*aP}vM#U|6{5684EivNxD;iULFOJo zRzo@@jNWD@x=EQO3XsJXMU|iqICMz^wA4;bQOM6zFg5}!gZ4Z@Goaw!A~@NA3SUsH zGxGVPE(SoZ?Lln?&=4wYKnI+7;h8qSh|$;?G})P=03Gvo%gh5UHb{ju?(^~$GC^57 zCkIsU!AcfAMqQ|;pwhfxh>6hFJZOZvC>t{5f>5ps%Oj8^4UXU e+^%tS~RS&vb|r4-U9 zN`=fqLb^1did7tBcmd4j(md!;fF7d;B5#3fY)EYb$uQtqdr)QpWkW`@Fwk@iWK G5CIjuA&2b4cEpkC8sbU|_=BAJ4W1veTLG!T^ V+TwxTej_8qr+8w!>=|!MsM?q13N@;S50<_f& z8Y4;rO$)$lVn~t7m;j0$a5e&kVrH>IZX!6Q6Cp(wsLPj{qN9*hS^|y|q^QaT#||XI z;GH(e98RS|BBEL{g>~ukOBBGl7?kKB%?rpFj-EmQbP6duwG!khW00pzg1`f_uAoIH znR)2}5dRcIS8*v6rxuoi=1M><6Hw8Ynp~1osfXNbgszi;O&P(K>44ix(Buye1BHUb z 7;L1G@L?u3VIL1Gc8-347=rN?L#oRJ7>Jc8 1Opm =@De1@;sJ%U)I`uhLwbyk zpygj+zvQPWWD@5JXx9~%e?8&tbWjU9zX;Sag$!bNx**r`;B;OLUE2q88z>1YWac47 zvI{89B0>keC_y0=JX{7Dl>|k70XWbUN dDX9e|8KB$^3Zb0TvecYnJ;pFc1viNQ zpan`%YI1&2ih@S8QLH9nB(zuoGVquRN{FC%g2p7YjDimf6f1z&is&&K2f&IV@E{hb zSS-p1tx$yc7TjO~#WS>+0#|m7YC#|+@Ls$EW^o2lX8 DXa@r{d<{-yV9)6>I)UODQlez0rYIm{92~G3;4(xLoNBS;8L*S} z7_C8OfJ))iVo>W#JvcQdHMv9`y5 Xg*9#L^s4nVbV^9fLdtPEXJ b3uI$c&P&!umt4|gb+AB^%$){ z{SRnZB JuxQ-)bvX(EiTE=g;fVoy*jXQ1ZbI#um)Bif?NJj)fRrK znc&V_sGqY!UVf263b;|1lUh=eS_H1>5fv7+xQFV54v)c_lu*f>%;FNzXe?^|%xL6{ z;#5%P0_A^rnsv&|1FfF`Cwk~SB%>w)J>U=r>tNKuR0@l`VujK?#LNU}0RrPDMo^lD z4vOa_CZ*;mfc*q&mV%-ZQma?ym#P<~!k6-b>r7A`4~kaEBrQlSOgm`hReEMwDtKi9 zNCK%<1nS#^a#^uLVopweIk^3sQ>l=drcjw*s*nMi0|CuVDHwu_gGx|huFNkjQb0C> zQ5=?fVUtXdWL?ZC>Ihl33=dCm3TCti`4Lf=LJBpAH$lDt7a8C}4`dz4!HAL$5~kAN z#H;`=q9N%I+NlJ!H|3#?YK7FibkM>^kmc}Z6=-Rl8z==sGFm2L)h&G99_$cnER7ye zNe)`H0cr!8#HuqYK?*BSJHj_HFEKr}2<&ncyOa=4$En5| Z4o|a4j^+rqc zAcHfYl_SZike+s8UJ6)MQfg`*Xi^%~_JXDt=J6A=JLm0sg9#m(5QW?@1Ce%`|#Ii)9 zw7Q{22dKb-3~xX~4eZEhlUOT-Xwz8e;#{*>9nfMD@N#DJSRI9Eic?=ls01%=A)d zGZ-{Y03C_}yBSubg3QkZbr+zEL}3XAq#lwV6?_wmiZc?y<#tIvY{(Hgh#e5YlnPn0 zjV+A9qjr!z9H4Lpt$s+%14WWaETgk)ge!E#hXQC|3bGRfBV2XBqxYaH1zPc<7!n9y zt^}%v;Y-6o^%Sf|fsQpn*IMQz=B1Z{2E4$7NsuBPA!Zt@$LLS0k?>$OiPeGDKX4(C zfr;cA2%GM)0WGFOHyS1x4YDGMVk>NEZ-*@%?64zj2gT80M=+>d5Sati;y_wC0?K-z z1v;QEVX;DTMrKY5s2~L`kpwjZ;b|7MU|bJWDT3P#kn$Nist4`wgOWJ3d 9- zfw&X2=%f_7 P7yI^f 7Zr{P*VcbAOcNzKqhf~gFRuBs(Os>sH))^ z%s3X@o6RjqEXf3IuK_RigES?q6?`*68`MBK-#4)WTt4eD`k)#FTNMF{G33BgaD^=Z zFD*zfN=yN*%18lkyMX0&aNc%+&Xpvkrh{rv(AEG*V_Q$bJtsdYF-IY{v?R3xT-!l{ z7}Q*Y&)=lzF`7V40FR$4Kx-CA=UET3umoZt*ofkiM9{80Jw|P)uA JIe(VbbWP?DIPny1I80UB8Vok?8` zni|W5b@4$d7Sy6kEd!0CfOIpOx_~>u3SpV4 Qe;if`$Sp?4d;~$OGwlnN^_DM#lx(-A*bkDap?R4J~Kp 2cGcD&np3W6TBt@v`;7{ADm)96Fs1T*UIFaR8TV-wD=N~@*#^S zKy#F!X<|^?E6In{InYtvqEwJ`^70kZN{hh#VW`P^jD<9FMpAxB1~{TXod8fX6yhd5 zMt6VYm;-IC0(%zZY*3Oe$p 8Ok?`Manv$S#*$x z;4|rP-8jq#H3eKfAvpl*ZC8+sA>DojM3jNUJ`X%zpPUcLY6{4arN?Li)elZ lBhlabs%#<11sRU8E9ZaHUK83q=1SY zFB07XH3Qr?0u2d4+y*KN^%xyN@e36|L?tL=!a@?1xr$Oi#c^T@s1hkI0qKMcjB9{q zy1*m4P&*JS_`q>Pv>6e&V>A`K1OPPGRhgfc0uGcU(CU@MBG5Q9baVsigJ=`b0#a}f zxFE9vJR?v6@*uQ)21(~bQeaVHN@hN21`Jegrx)dy7Jwa$8WluY4b^N4vDqwE0cLY} zND*j+yCh!$x}FafMxfAzjJ`qYN$^kuwAhB1jnL`_HgyBaY7kHAF{(r3A2c-x+R>K? z$}EVqoC2*R^%%_vDTKKQ#oKz2* ?@sloK2=>e4xM(~7S5{sNxK@Dv1iYZ76$c46Az@;B}L?2wRLhHC {?P3!v>vxOYLTWx-R}piy+tBnFb_K`sQhCg7@#!LCHJ3%Y0u)Nq2- zX?l>+OEg_bt}9Q>D}hXNm4jNLMfu5~$c1#hK-D^Q{64cJH5VL|pjLiHszNb%;sZ45 zg{U_&ONvu-(m?eMq5@M0hOV*&ITT(rf?73@@ftlw=+acElR&i@sF?{K7S?0b^2=B7 z_lD&bP-O}k6oKX?NN*6Ll~D(@HyPBT0neN%;8m>0=m1J0;00L0;H{ZR !A6)8^PmG_5chxvr9qyCxDm4d6V_}fPA$=61kXE` z
n4^Hks^ zg|OJi5^8#ko}hq$sld!~pgIxUx&oP)nVg@e0BT}^I7yi$xrqe|#U+(Fp!86p#~2GQ zcR+PCvYDXyLr|j|wbhE0zCmN2=milx*MbMv^%%YIyA-rTB~2j_e4K&~Wd9vBJ0yXY z7M7%fM!Z4Ibx=(v8JY*GUZ9mcbOHl3rJ={D4zdO`H2`l{fV~Y$v(S_QUbv*k=;{co zmOujrFz )$$~3QP;P?66*&7OrGiGz6`+mGVvtk(p$$f;1&QDR@f^^h91wlr z# exmg-0Bg1_jg@NCy$VKp32`L1l{`N;wS@0i|0*Gd;#;@C+X`&aoH_ zX=s7U1F&JBhE8Ul0@#FT)7Xk=(^yzCN-Tj0Lo-ogSz;!5@0Ff{PkthJaX!eDv`lb9 zgh_(6=rOJ*;EJNu g%+d$NL=4k@ESu@6cwiKQhO`H <+R6$$6j>0Ec2oBtdOPt3>q}qd^8` zq~?Gs8qg66pf(A(V8)#!;Z6i80S%>sEG~xa4nm%41dp_Ud ES3KS$36+>3Z=Oz||_AZ0c6xbq09T&*J7xXwWaK #IHHU7K-;;Xops2dAuQN6ptX5 >YJo_A6E`Sk5h+QJQ5UhU9Xh*^r~tJAR&*hhD>52mC >l z_rTH>C>kNT0^%$^Mu>Ys@`(z`kn^rU!)F YWs71L znorQ&iEtxy5J->F6qM*7L*7MDLD1R@aL|D41ZN{?^rXU??0SqEh+qLNC@;#dL=HrR zJ$j6eAQyv1J3)(3AT3Amx)P| yzpBg4OF;+yDpi<3b2jPUT*o|(-alJ gtr&a*$BsowUic!@cemWs2rNM^dAeB!sbTP6XqXa0OgC> ?*!C-Lsx^eX%8Ak;6>%2jvvO_ za`=KZ(83c%ghL_w7(jbs^P$sgAaCh0DkGG@mP%tPf^4<|kEFmhOr?T0GZm>9gE|h7 z_3fD{;EigCvpB(raezu7#B`V*qY=WsV$fV!X%1p{5xDdPkD4XsfU5JN)TI3U5 8U*#h?|3kag|g>1*)7E29o{nJl7(391fJH6kJ)0lE$cloVhSyGTpz z^c0}-P&shJL`MO%Wh@u8xev1M7F>zxDC8zqWTJ|KmSD&QgH9oZ?&!))0fjp#IYH+z z^%$+-#{ ~muEX>7gA!zM!2{o-V#l8R$ zG!_RskrABZpve!ksSmPOLXS}$X(J?LYaF=w2HI{1Y9E2a8JsYT5v3)x5&~6_pv(!b zB%z}$;B8f)+z8UB$Cw=gIy?!Q`#?hzuo#B-G(hglFDg+;NiE39uLPxf=-w^pgnluk zx`w7~kjda_>>`Ck1yqH4jG+B_(CsOX;MFCd5f1PKIjpKQgRU5b)GqmHprz~qIi Y&_`71~O literal 0 HcmV?d00001 diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Errors.txt b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Errors.txt new file mode 100644 index 00000000..ec7c97b1 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Errors.txt @@ -0,0 +1,404 @@ +; Windows Installer Internal Error Messages +; +; Error numbers greater than 2000 are "internal errors" and do not have +; localized strings in msimsg.dll. The messages are provided here +; (in English only) because they can be informative and time-saving +; during developement. +; + +2101=Shortcuts not supported by the OS. +2102=Invalid .INI action: [2] +2103=Could not resolve path for shell folder [2]. +2104=Writing .INI file: [3]: System error: [2] +2105=Shortcut Creation [3] Failed. System error: [2] +2106=Shortcut Deletion [3] Failed. System error: [2] +2107=Error [3] registering type library [2]. +2108=Error [3] unregistering type library [2]. +2109=Section missing for INI action. +2110=Key missing for INI action. +2111=Detection of running apps failed, could not get performance data. Reg operation returned : [2]. +2112=Detection of running apps failed, could not get performance index. Reg operation returned : [2]. +2113=Detection of running apps failed. +2200=Database: [2]. Database object creation failed, mode = [3]. +2201=Database: [2]. Initialization failed, out of memory. +2202=Database: [2]. Data access failed, out of memory. +2203=Database: [2]. Cannot open database file. System error [3]. +2204=Database: [2]. Table already exists: [3] +2205=Database: [2]. Table does not exist: [3] +2206=Database: [2]. Table could not be dropped: [3] +2207=Database: [2]. Intent violation. +2208=Database: [2]. Insufficient parameters for Execute. +2209=Database: [2]. Cursor in invalid state. +2210=Database: [2]. Invalid update data type in column [3] +2211=Database: [2]. Could not create database table [3] +2212=Database: [2]. Database not in writable state. +2213=Database: [2]. Error saving database tables. +2214=Database: [2]. Error writing export file: [3] +2215=Database: [2]. Cannot open import file: [3] +2216=Database: [2]. Import file format error: [3], Line [4] +2217=Database: [2]. Wrong state to CreateOutputDatabase [3]. +2218=Database: [2]. Table name not supplied. +2219=Database: [2]. Invalid Installer database format. +2220=Database: [2]. Invalid row/field data. +2221=Database: [2]. Code page conflict in import file: [3]. +2222=Database: [2]. Transform or merge code page [3] differs from database code page [4]. +2223=Database: [2]. Databases are the same. No transform generated. +2224=Database: [2]. GenerateTransform: Database corrupt. Table: [3] +2225=Database: [2]. Transform: Cannot transform a temporary table. Table: [3] +2226=Database: [2]. Transform failed. +2227=Database: [2]. Invalid identifier '[3]' in SQL query: [4] +2228=Database: [2]. Unknown table '[3]' in SQL query: [4] +2229=Database: [2]. Could not load table '[3]' in SQL query: [4] +2230=Database: [2]. Repeated table '[3]' in SQL query: [4] +2231=Database: [2]. Missing ')' in SQL query: [3] +2232=Database: [2]. Unexpected token '[3]' in SQL query: [4] +2233=Database: [2]. No columns in SELECT clause in SQL query: [3] +2234=Database: [2]. No columns in ORDER BY clause in SQL query: [3] +2235=Database: [2]. Column '[3]' not present or ambiguous in SQL query: [4] +2236=Database: [2]. Invalid operator '[3]' in SQL query: [4] +2237=Database: [2]. Invalid or missing query string: [3] +2238=Database: [2]. Missing FROM clause in SQL query: [3] +2239=Database: [2]. Insufficient values in INSERT SQL stmt. +2240=Database: [2]. Missing update columns in UPDATE SQL stmt. +2241=Database: [2]. Missing insert columns in INSERT SQL stmt. +2242=Database: [2]. Column '[3]' repeated +2243=Database: [2]. No primary columns defined for table creation. +2244=Database: [2]. Invalid type specifier '[3]' in SQL query [4]. +2245=IStorage::Stat failed with error [3] +2246=Database: [2]. Invalid Installer transform format. +2247=Database: [2] Transform stream read/write failure. +2248=Database: [2] GenerateTransform/Merge: Column type in base table doesn't match reference table. Table: [3] Col #: [4] +2249=Database: [2] GenerateTransform: More columns in base table than in reference table. Table: [3] +2250=Database: [2] Transform: Cannot add existing row. Table: [3] +2251=Database: [2] Transform: Cannot delete row that doesn't exist. Table: [3] +2252=Database: [2] Transform: Cannot add existing table. Table: [3] +2253=Database: [2] Transform: Cannot delete table that doesn't exist. Table: [3] +2254=Database: [2] Transform: Cannot update row that doesn't exist. Table: [3] +2255=Database: [2] Transform: Column with this name already exists. Table: [3] Col: [4] +2256=Database: [2] GenerateTransform/Merge: Number of primary keys in base table doesn't match reference table. Table: [3] +2257=Database: [2]. Intent to modify read only table: [3] +2258=Database: [2]. Type mismatch in parameter: [3] +2259=Database: [2] Table(s) Update failed. +2260=Storage CopyTo failed. System error: [3] +2261=Could not remove stream [2]. System error: [3] +2262=Stream does not exist: [2]. System error: [3] +2263=Could not open stream [2]. System error: [3] +2264=Could not remove stream [2]. System error: [3] +2265=Could not commit storage. System error: [3] +2266=Could not rollback storage. System error: [3] +2267=Could not delete storage [2]. System error: [3] +2268=Database: [2]. Merge: There were merge conflicts reported in [3] tables. +2269=Database: [2]. Merge: The column count differed in the '[3]' table of the two databases. +2270=Database: [2]. GenerateTransform/Merge: Column name in base table doesn't match reference table. Table: [3] Col #: [4] +2271=SummaryInformation write for transform failed. +2272=Database: [2]. MergeDatabase will not write any changes because the database is open read-only. +2273=Database: [2]. MergeDatabase: A reference to the base database was passed as the reference database. +2274=Database: [2]. MergeDatabase: Unable to write errors to Error table. Could be due to a non-nullable column in a predefined Error table. +2275=Database: [2]. Specified Modify [3] operation invalid for table joins. +2276=Database: [2]. Code page [3] not supported by the system. +2277=Database: [2]. Failed to save table [3]. +2278=Database: [2]. Exceeded number of expressions limit of 32 in WHERE clause of SQL query: [3]. +2279=Database: [2] Transform: Too many columns in base table [3] +2280=Database: [2]. Could not create column [3] for table [4] +2281=Could not rename stream [2]. System error: [3] +2282=Stream name invalid [2]. +2302=Patch notify: [2] bytes patched to far. +2303=Error getting volume info. GetLastError: [2] +2304=Error getting disk free space. GetLastError: [2]. Volume: [3] +2305=Error waiting for patch thread. GetLastError: [2]. +2306=Could not create thread for patch application. GetLastError: [2]. +2307=Source file key name is null. +2308=Destination File Name is Null +2309=Attempting to patch file [2] when patch already in progress. +2310=Attempting to continue patch when no patch is in progress. +2315=Missing Path Separator: [2] +2318=File does not exist: [2] +2319=Error setting file attribute: [3] GetLastError: [2] +2320=File not writable: [2] +2321=Error creating file: [2] +2322=User canceled +2323=Invalid File Attribute +2324=Could not open file: [3] GetLastError: [2] +2325=Could not get file time for file: [3] GetLastError: [2] +2326=Error in FileToDosDateTime. +2327=Could not remove directory: [3] GetLastError: [2] +2328=Error getting file version info for file: [2] +2329=Error deleting file: [3]. GetLastError: [2] +2330=Error getting file attributes: [3]. GetLastError: [2] +2331=Error loading library [2] or finding entry point [3] +2332=Error getting file attributes. GetLastError: [2] +2333=Error setting file attributes. GetLastError: [2] +2334=Error converting file time to local time for file: [3]. GetLastError: [2] +2335=Path: [2] is not a parent of [3] +2336=Error creating temp file on path: [3]. GetLastError: [2] +2337=Could not close file: [3] GetLastError: [2] +2338=Could not update resource for file: [3] GetLastError: [2] +2339=Could not set file time for file: [3] GetLastError: [2] +2340=Could not update resource for file: [3], Missing Resource +2341=Could not update resource for file: [3], Resource too large +2342=Could not update resource for file: [3] GetLastError: [2] +2343=Specified path is empty. +2344=Could not find required file IMAGEHLP.DLL to validate file:[2] +2345=[2]: File does not contain a valid checksum value. +2347=User ignore +2348=Error attempting to read from cabinet stream. +2349=Copy Resumed With Different Info +2350=FDI Server Error +2351=File key '[2]' not found in cabinet '[3]'. The installation cannot continue. +2352=Couldn't initialize cabinet file server. The required file 'Cabinet.dll' may be missing. +2353=Not a cabinet +2354=Cannot handle cabinet +2355=Corrupt cabinet +2356=Couldn't locate cabinet in stream: [2]. +2357=Cannot set attributes +2358=Error determining whether file is in-use: [3]. GetLastError: [2] +2359=Unable to create the target file - file may be in use. +2360=progress tick. +2361=Need next cabinet. +2362=Folder not found: [2] +2363=Could not enumerate subfolders for folder: [2] +2364=Bad enumeration constant in CreateCopier call. +2365=Could not BindImage exe file [2] +2366=User Failure +2367=User Abort. +2368=Failed to get network resource information. Error [2], network path [3]. Extended error: network provider [5], error code [4], error description [6]. +2370=Invalid CRC checksum value for [2] file.{ Its header says [3] for checksum, its computed value is [4].} +2371=Could not apply patch to file [2]. GetLastError: [3] +2372=Patch file [2] is corrupt or of an invalid format. Attempting to patch file [3]. GetLastError: [4] +2373=File [2] is not a valid patch file. +2374=File [2] is not a valid destination file for patch file [3]. +2375=Unknown patching error: [2]. +2376=Cabinet not found. +2379=Error opening file for read: [3] GetLastError: [2] +2380=Error opening file for write: [3] GetLastError: [2] +2381=Directory does not exist: [2] +2382=Drive not ready: [2] +2401=64-bit registry operation attempted on 32-bit operating system for key [2]. +2402=Out of memory. +2501=Could not create rollback script enumerator +2502=Called InstallFinalize when no install in progress. +2503=Called RunScript when not marked in progress. +2601=Invalid value for property [2]: '[3]' +2602=The [2] table entry '[3]' has no associated entry in the Media table. +2603=Duplicate Table Name [2] +2604=[2] property undefined. +2605=Could not find server [2] in [3] or [4]. +2606=Value of property [2] is not a valid full path: '[3]'. +2607=Media table not found or empty (required for installation of files). +2608=Could not create security descriptor for object. Error: '[2]'. +2609=Attempt to migrate product settings before initialization. +2611=The file [2] is marked as compressed, but the associated media entry does not specify a cabinet. +2612=Stream not found in '[2]' column. Primary key: '[3]'. +2613=RemoveExistingProducts action sequenced incorrectly. +2614=Could not access IStorage object from installation package. +2615=Skipped unregistration of Module [2] due to source resolution failure. +2616=Companion file [2] parent missing. +2617=Shared component [2] not found in Component table. +2618=Isolated application component [2] not found in Component table. +2619=Isolated components [2], [3] not part of same feature. +2620=Key file of isolated application component [2] not in File table. +2621=Resource DLL or Resource ID information for shortcut [2] set incorrectly. +2701=The Component Table exceeds the acceptable tree depth of [2] levels. +2702=A Feature Table record ([2]) references a non-existent parent in the Attributes field. +2703=Property name for root source path not defined: [2] +2704=Root directory property undefined: [2] +2705=Invalid table: [2]; Could not be linked as tree. +2706=Source paths not created. No path exists for entry [2] in Directory Table +2707=Target paths not created. No path exists for entry [2] in Directory Table +2708=No entries found in the file table. +2709=The specified Component name ('[2]') not found in Component Table. +2710=The requested 'Select' state is illegal for this Component. +2711=The specified Feature name ('[2]') not found in Feature Table. +2712=Invalid return from modeless dialog: [3], in action [2]. +2713=Null value in a non-nullable column ('[2]' in '[3]' column of the '[4]' table. +2714=Invalid value for default folder name: [2]. +2715=The specified File key ('[2]') not found in the File Table. +2716=Couldn't create a random subcomponent name for component '[2]'. +2717=Bad action condition or error calling custom action '[2]'. +2718=Missing package name for product code '[2]'. +2719=Neither UNC nor drive letter path found in source '[2]'. +2720=Error opening source list key. Error: '[2]' +2721=Custom action [2] not found in Binary table stream +2722=Custom action [2] not found in File table +2723=Custom action [2] specifies unsupported type +2724=The volume label '[2]' on the media you're running from doesn't match the label '[3]' given in the Media table. This is allowed only if you have only 1 entry in your Media table. +2725=Invalid database tables +2726=Action not found: [2] +2727=The directory entry '[2]' does not exist in the Directory table +2728=Table definition error: [2] +2729=Install engine not initialized. +2730=Bad value in database. Table: '[2]'; Primary key: '[3]'; Column: '[4]' +2731=Selection Manager not initialized. +2732=Directory Manager not initialized. +2733=Bad foreign key ('[2]') in '[3]' column of the '[4]' table. +2734=Invalid Reinstall mode character. +2735=Custom action '[2]' has caused an unhandled exception and has been stopped. This may be the result of an internal error in the custom action, such as an access violation. +2736=Generation of custom action temp file failed: [2] +2737=Could not access custom action [2], entry [3], library [4] +2738=Could not access VBScript runtime for custom action [2] +2739=Could not access JavaScript runtime for custom action [2] +2740=Custom action [2] script error [3], [4]: [5] Line [6], Column [7], [8] +2741=Configuration information for product [2] is corrupt. Invalid info: [2] +2742=Marshaling to Server failed: [2] +2743=Could not execute custom action [2], location: [3], command: [4] +2744=EXE failed called by custom action [2], location: [3], command: [4] +2745=Transform [2] invalid for package [3]. Expected language [4], found language [5]. +2746=Transform [2] invalid for package [3]. Expected product [4], found product [5]. +2747=Transform [2] invalid for package [3]. Expected product version < [4], found product version [5]. +2748=Transform [2] invalid for package [3]. Expected product version <= [4], found product version [5]. +2749=Transform [2] invalid for package [3]. Expected product version == [4], found product version [5]. +2750=Transform [2] invalid for package [3]. Expected product version >= [4], found product version [5]. +2751=Transform [2] invalid for package [3]. Expected product version > [4], found product version [5]. +2752=Could not open transform [2] stored as child storage of package [4]. +2753=The File '[2]' is not marked for installation. +2754=The File '[2]' is not a valid patch file. +2755=Server returned unexpected error [2] attempting to install package [3]. +2756=The property '[2]' was used as a directory property in one or more tables, but no value was ever assigned. +2757=Could not create summary info for transform [2]. +2758=Transform [2] doesn't contain a MSI version. +2759=Transform [2] version [3] incompatible with engine; Min: [4], Max: [5]. +2760=Transform [2] invalid for package [3]. Expected upgrade code [4], found [5]. +2761=Cannot begin transaction. Global mutex not properly initialized. +2762=Cannot write script record. Transaction not started. +2763=Cannot run script. Transaction not started. +2765=Assembly name missing from AssemblyName table : Component: [4]. +2766=The file [2] is an invalid MSI storage file. +2767=No more data{ while enumerating [2]}. +2768=Transform in patch package is invalid. +2769=Custom Action [2] did not close [3] handles. +2770=Cached folder [2] not defined in internal cache folder table. +2771=Upgrade of feature [2] has a missing component. +2772=New upgrade feature [2] must be a leaf feature. +2801=Unknown Message -- Type [2]. No action is taken. +2802=No publisher is found for the event [2]. +2803=Dialog View did not find a record for the dialog [2]. +2804=On activation of the control [3] on dialog [2], failed to evaluate the condition [3]. +2805= +2806=The dialog [2] failed to evaluate the condition [3]. +2807=The action [2] is not recognized. +2808=Default button is ill-defined on dialog [2]. +2809=On the dialog [2] the next control pointers do not form a cycle. There is a pointer from [3] to [4], but there is no further pointer. +2810=On the dialog [2] the next control pointers do not form a cycle. There is a pointer from both [3] and [5] to [4]. +2811=On dialog [2] control [3] has to take focus, but it is unable to do so. +2812=The event [2] is not recognized. +2813=The EndDialog event was called with the argument [2], but the dialog has a parent. +2814=On the dialog [2] the control [3] names a non-existent control [4] as the next control. +2815=ControlCondition table has a row without condition for the dialog [2]. +2816=The EventMapping table refers to an invalid control [4] on dialog [2] for the event [3]. +2817=The event [2] failed to set the attribute for the control [4] on dialog [3]. +2818=In the ControlEvent table EndDialog has an unrecognized argument [2]. +2819=Control [3] on dialog [2] needs a property linked to it. +2820=Attempted to initialize an already initialized handler. +2821=Attempted to initialize an already initialized dialog: [2]. +2822=No other method can be called on dialog [2] until all the controls are added. +2823=Attempted to initialize an already initialized control: [3] on dialog [2]. +2824=The dialog attribute [3] needs a record of at least [2] field(s). +2825=The control attribute [3] needs a record of at least [2] field(s). +2826=Control [3] on dialog [2] extends beyond the boundaries of the dialog [4] by [5] pixels. +2827=The button [4] on the radio button group [3] on dialog [2] extends beyond the boundaries of the group [5] by [6] pixels. +2828=Tried to remove control [3] from dialog [2], but the control is not part of the dialog. +2829=Attempt to use an uninitialized dialog. +2830=Attempt to use an uninitialized control on dialog [2]. +2831=The control [3] on dialog [2] does not support [5] the attribute [4]. +2832=The dialog [2] does not support the attribute [3]. +2833=Control [4] on dialog [3] ignored the message [2]. +2834=The next pointers on the dialog [2] do not form a single loop. +2835=The control [2] was not found on dialog [3]. +2836=The control [3] on the dialog [2] cannot take focus. +2837=The control [3] on dialog [2] wants the win proc to return [4]. +2838=The item [2] in the selection table has itself as a parent. +2839=Setting the property [2] failed. +2840=Error dialog name mismatch. +2841=No OK button was found on the error dialog +2842=No text field was found on the error dialog. +2843=The ErrorString attribute is not supported for standard dialogs. +2844=Cannot execute an error dialog if the error string is not set. +2845=The total width of the buttons exceeds the size of the error dialog. +2846=SetFocus did not find the required control on the error dialog. +2847=The control [3] on dialog [2] has both the icon and the bitmap style set. +2848=Tried to set control [3] as the default button on dialog [2], but the control does not exist. +2849=The control [3] on dialog [2] is of a type, that cannot be integer valued. +2850=Unrecognized volume type. +2851=The data for the icon [2] is not valid. +2852=At least one control has to be added to dialog [2] before it is used. +2853=Dialog [2] is a modeless dialog. The execute method should not be called on it. +2854=On the dialog [2] the control [3] is designated as first active control, but there is no such control. +2855=The radio button group [3] on dialog [2] has fewer than 2 buttons. +2856=Creating a second copy of the dialog [2]. +2857=The directory [2] is mentioned in the selection table but not found. +2858=The data for the bitmap [2] is not valid. +2859=Test error message. +2860=Cancel button is ill-defined on dialog [2]. +2861=The next pointers for the radio buttons on dialog [2] control [3] do not form a cycle. +2862=The attributes for the control [3] on dialog [2] do not define a valid icon size. Setting the size to 16. +2863=The control [3] on dialog [2] needs the icon [4] in size [5]x[5], but that size is not available. Loading the first available size. +2864=The control [3] on dialog [2] received a browse event, but there is no configurable directory for the present selection. Likely cause: browse button is not authored correctly. +2865=Control [3] on billboard [2] extends beyond the boundaries of the billboard [4] by [5] pixels. +2866=The dialog [2] is not allowed to return the argument [3]. +2867=The error dialog property is not set. +2868=The error dialog [2] does not have the error style bit set. +2869=The dialog [2] has the error style bit set, but is not an error dialog. +2870=The help string [4] for control [3] on dialog [2] does not contain the separator character. +2871=The [2] table is out of date: [3] +2872=The argument of the CheckPath control event on dialog [2] is invalid. +2873=On the dialog [2] the control [3] has an invalid string length limit: [4] +2874=Changing the text font to [2] failed. +2875=Changing the text color to [2] failed. +2876=The control [3] on dialog [2] had to truncate the string: [4] +2877=The binary data [2] was not found. +2878=On the dialog [2] the control [3] has a possible value: [4]. This is an invalid or duplicate value. +2879=The control [3] on dialog [2] cannot parse the mask string: [4] +2880=Do not perform the remaining control events. +2881=Initialization failed. +2882=Dialog window class registration failed. +2883=CreateNewDialog failed for the dialog [2]. +2884=Failed to create a window for the dialog [2]! +2885=Failed to create the control [3] on the dialog [2]. +2886=Creating the [2] table failed. +2887=Creating a cursor to the [2] table failed. +2888=Executing the [2] view failed. +2889=Creating the window for the control [3] on dialog [2] failed. +2890=The handler failed in creating an initialized dialog. +2891=Failed to destroy window for dialog [2]. +2892=[2] is an integer only control, [3] is not a valid integer value. +2893=The control [3] on dialog [2] can accept property values that are at most [5] characters long. The value [4] exceeds this limit, and has been truncated. +2894=Loading RichEd20.dll failed. GetLastError() returned: [2] +2895=Freeing RichEd20.dll failed. GetLastError() returned: [2] +2896=Executing action [2] failed. +2897=Failed to create any [2] font on this system. +2898=For [2] text style, the system created a '[3]' font, in [4] character set. +2899=Failed to create [2] text style. GetLastError() returned: [3]. +2901=Invalid parameter to operation [2]: Parameter [3] +2902=Operation [2] called out of sequence. +2903=The file [2] is missing. +2904=Could not BindImage file [2]. +2905=Could not read record from script file [2]. +2906=Missing header in script file [2]. +2907=Could not create secure security descriptor. Error: [2] +2908=Could not register component [2]. +2909=Could not unregister component [2]. +2910=Could not determine user's security id. +2911=Could not remove the folder [2]. +2912=Could not schedule file [2] for removal on reboot. +2919=No cabinet specified for compressed file: [2] +2920=Source directory not specified for file [2]. +2924=Script [2] version unsupported. Script version: [3], minimum version: [4], maximum version: [5]. +2927=ShellFolder id [2] is invalid. +2928=Exceeded maximum number of sources. Skipping source '[2]'. +2929=Could not determine publishing root. Error: [2] +2932=Could not create file [2] from script data. Error: [3] +2933=Could not initialize rollback script [2]. +2934=Could not secure transform [2]. Error [3] +2935=Could not un-secure transform [2]. Error [3] +2936=Could not find transform [2]. +2937=The Windows Installer cannot install a system file protection catalog. Catalog: [2], Error: [3] +2938=The Windows Installer cannot retrieve a system file protection catalog from the cache. Catalog: [2], Error: [3] +2939=The Windows Installer cannot delete a system file protection catalog from the cache. Catalog: [2], Error: [3] +2940=Directory Manager not supplied for source resolution. +2941=Unable to compute the CRC for file [2]. +2942=BindImage action has not been executed on [2] file. +2943=This version of Windows does not support deploying 64-bit packages. The script [2] is for a 64-bit package. +2944=GetProductAssignmentType failed. +2945=Installation of ComPlus App [2] failed with error [3]. +3001=The patches in this list contain incorrect sequencing information: [2][3][4][5][6][7][8][9][10][11][12][13][14][15][16]. 3.0 +3002=Patch [2] contains invalid sequencing information. diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Exceptions.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Exceptions.cs new file mode 100644 index 00000000..1f5e017a --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Exceptions.cs @@ -0,0 +1,576 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.IO; + using System.Text; + using System.Collections.Generic; + using System.Globalization; + using System.Security.Permissions; + using System.Runtime.Serialization; + using System.Diagnostics.CodeAnalysis; + + /// + /// Base class for Windows Installer exceptions. + /// + [Serializable] + public class InstallerException : SystemException + { + private int errorCode; + private object[] errorData; + + ///+ /// Creates a new InstallerException with a specified error message and a reference to the + /// inner exception that is the cause of this exception. + /// + /// The message that describes the error. + /// The exception that is the cause of the current exception. If the + /// innerException parameter is not a null reference (Nothing in Visual Basic), the current exception + /// is raised in a catch block that handles the inner exception. + public InstallerException(string msg, Exception innerException) + : this(0, msg, innerException) + { + } + + ///+ /// Creates a new InstallerException with a specified error message. + /// + /// The message that describes the error. + public InstallerException(string msg) + : this(0, msg) + { + } + + ///+ /// Creates a new InstallerException. + /// + public InstallerException() + : this(0, null) + { + } + + internal InstallerException(int errorCode, string msg, Exception innerException) + : base(msg, innerException) + { + this.errorCode = errorCode; + this.SaveErrorRecord(); + } + + internal InstallerException(int errorCode, string msg) + : this(errorCode, msg, null) + { + } + + ///+ /// Initializes a new instance of the InstallerException class with serialized data. + /// + /// The SerializationInfo that holds the serialized object data about the exception being thrown. + /// The StreamingContext that contains contextual information about the source or destination. + protected InstallerException(SerializationInfo info, StreamingContext context) : base(info, context) + { + if (info == null) + { + throw new ArgumentNullException("info"); + } + + this.errorCode = info.GetInt32("msiErrorCode"); + } + + ///+ /// Gets the system error code that resulted in this exception, or 0 if not applicable. + /// + public int ErrorCode + { + get + { + return this.errorCode; + } + } + + ///+ /// Gets a message that describes the exception. This message may contain detailed + /// formatted error data if it was available. + /// + public override String Message + { + get + { + string msg = base.Message; + using (Record errorRec = this.GetErrorRecord()) + { + if (errorRec != null) + { + string errorMsg = Installer.GetErrorMessage(errorRec, CultureInfo.InvariantCulture); + msg = Combine(msg, errorMsg); + } + } + return msg; + } + } + + ///+ /// Sets the SerializationInfo with information about the exception. + /// + /// The SerializationInfo that holds the serialized object data about the exception being thrown. + /// The StreamingContext that contains contextual information about the source or destination. + [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)] + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new ArgumentNullException("info"); + } + + info.AddValue("msiErrorCode", this.errorCode); + base.GetObjectData(info, context); + } + + ///+ /// Gets extended information about the error, or null if no further information + /// is available. + /// + ///A Record object. Field 1 of the Record contains the installer + /// message code. Other fields contain data specific to the particular error. + ///+ [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public Record GetErrorRecord() + { + return this.errorData != null ? new Record(this.errorData) : null; + } + + internal static Exception ExceptionFromReturnCode(uint errorCode) + { + return ExceptionFromReturnCode(errorCode, null); + } + + internal static Exception ExceptionFromReturnCode(uint errorCode, string msg) + { + msg = Combine(GetSystemMessage(errorCode), msg); + switch (errorCode) + { + case (uint) NativeMethods.Error.FILE_NOT_FOUND: + case (uint) NativeMethods.Error.PATH_NOT_FOUND: return new FileNotFoundException(msg); + + case (uint) NativeMethods.Error.INVALID_PARAMETER: + case (uint) NativeMethods.Error.DIRECTORY: + case (uint) NativeMethods.Error.UNKNOWN_PROPERTY: + case (uint) NativeMethods.Error.UNKNOWN_PRODUCT: + case (uint) NativeMethods.Error.UNKNOWN_FEATURE: + case (uint) NativeMethods.Error.UNKNOWN_COMPONENT: return new ArgumentException(msg); + + case (uint) NativeMethods.Error.BAD_QUERY_SYNTAX: return new BadQuerySyntaxException(msg); + + case (uint) NativeMethods.Error.INVALID_HANDLE_STATE: + case (uint) NativeMethods.Error.INVALID_HANDLE: + InvalidHandleException ihex = new InvalidHandleException(msg); + ihex.errorCode = (int) errorCode; + return ihex; + + case (uint) NativeMethods.Error.INSTALL_USEREXIT: return new InstallCanceledException(msg); + + case (uint) NativeMethods.Error.CALL_NOT_IMPLEMENTED: return new NotImplementedException(msg); + + default: return new InstallerException((int) errorCode, msg); + } + } + + internal static string GetSystemMessage(uint errorCode) + { + const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; + const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; + + StringBuilder buf = new StringBuilder(1024); + uint formatCount = NativeMethods.FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + IntPtr.Zero, + (uint) errorCode, + 0, + buf, + (uint) buf.Capacity, + IntPtr.Zero); + + if (formatCount != 0) + { + return buf.ToString().Trim(); + } + else + { + return null; + } + } + + internal void SaveErrorRecord() + { + // TODO: pass an affinity handle here? + int recordHandle = RemotableNativeMethods.MsiGetLastErrorRecord(0); + if (recordHandle != 0) + { + using (Record errorRec = new Record((IntPtr) recordHandle, true, null)) + { + this.errorData = new object[errorRec.FieldCount]; + for (int i = 0; i < this.errorData.Length; i++) + { + this.errorData[i] = errorRec[i + 1]; + } + } + } + else + { + this.errorData = null; + } + } + + private static string Combine(string msg1, string msg2) + { + if (msg1 == null) return msg2; + if (msg2 == null) return msg1; + return msg1 + " " + msg2; + } + } + + /// + /// If the record is passed to
, it is formatted + /// by looking up the string in the current database. If there is no installation + /// session, the formatted error message may be obtained by a query on the Error table using + /// the error code, followed by a call to . + /// Alternatively, the standard MSI message can by retrieved by calling the + /// method. + /// + /// The following methods and properties may report extended error data: + ///
+ ///
+ ///- + ///
(constructor) - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
(constructor) - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. - + ///
. + /// The Record object should be
d after use. + /// It is best that the handle be closed manually as soon as it is no longer + /// needed, as leaving lots of unused handles open can degrade performance. + /// + /// Win32 MSI API: + /// MsiGetLastErrorRecord + ///
+ /// User Canceled the installation. + /// + [Serializable] + public class InstallCanceledException : InstallerException + { + ///+ /// Creates a new InstallCanceledException with a specified error message and a reference to the + /// inner exception that is the cause of this exception. + /// + /// The message that describes the error. + /// The exception that is the cause of the current exception. If the + /// innerException parameter is not a null reference (Nothing in Visual Basic), the current exception + /// is raised in a catch block that handles the inner exception. + public InstallCanceledException(string msg, Exception innerException) + : base((int) NativeMethods.Error.INSTALL_USEREXIT, msg, innerException) + { + } + + ///+ /// Creates a new InstallCanceledException with a specified error message. + /// + /// The message that describes the error. + public InstallCanceledException(string msg) + : this(msg, null) + { + } + + ///+ /// Creates a new InstallCanceledException. + /// + public InstallCanceledException() + : this(null, null) + { + } + + ///+ /// Initializes a new instance of the InstallCanceledException class with serialized data. + /// + /// The SerializationInfo that holds the serialized object data about the exception being thrown. + /// The StreamingContext that contains contextual information about the source or destination. + protected InstallCanceledException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } + + ///+ /// A bad SQL query string was passed to + [Serializable] + public class BadQuerySyntaxException : InstallerException + { + ///or . + /// + /// Creates a new BadQuerySyntaxException with a specified error message and a reference to the + /// inner exception that is the cause of this exception. + /// + /// The message that describes the error. + /// The exception that is the cause of the current exception. If the + /// innerException parameter is not a null reference (Nothing in Visual Basic), the current exception + /// is raised in a catch block that handles the inner exception. + public BadQuerySyntaxException(string msg, Exception innerException) + : base((int) NativeMethods.Error.BAD_QUERY_SYNTAX, msg, innerException) + { + } + + ///+ /// Creates a new BadQuerySyntaxException with a specified error message. + /// + /// The message that describes the error. + public BadQuerySyntaxException(string msg) + : this(msg, null) + { + } + + ///+ /// Creates a new BadQuerySyntaxException. + /// + public BadQuerySyntaxException() + : this(null, null) + { + } + + ///+ /// Initializes a new instance of the BadQuerySyntaxException class with serialized data. + /// + /// The SerializationInfo that holds the serialized object data about the exception being thrown. + /// The StreamingContext that contains contextual information about the source or destination. + protected BadQuerySyntaxException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } + + ///+ /// A method was called on an invalid installer handle. The handle may have been already closed. + /// + [Serializable] + public class InvalidHandleException : InstallerException + { + ///+ /// Creates a new InvalidHandleException with a specified error message and a reference to the + /// inner exception that is the cause of this exception. + /// + /// The message that describes the error. + /// The exception that is the cause of the current exception. If the + /// innerException parameter is not a null reference (Nothing in Visual Basic), the current exception + /// is raised in a catch block that handles the inner exception. + public InvalidHandleException(string msg, Exception innerException) + : base((int) NativeMethods.Error.INVALID_HANDLE, msg, innerException) + { + } + + ///+ /// Creates a new InvalidHandleException with a specified error message. + /// + /// The message that describes the error. + public InvalidHandleException(string msg) + : this(msg, null) + { + } + + ///+ /// Creates a new InvalidHandleException. + /// + public InvalidHandleException() + : this(null, null) + { + } + + ///+ /// Initializes a new instance of the InvalidHandleException class with serialized data. + /// + /// The SerializationInfo that holds the serialized object data about the exception being thrown. + /// The StreamingContext that contains contextual information about the source or destination. + protected InvalidHandleException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } + + ///+ /// A failure occurred when executing + [Serializable] + public class MergeException : InstallerException + { + private IList. The exception may contain + /// details about the merge conflict. + /// conflictTables; + private IList conflictCounts; + + /// + /// Creates a new MergeException with a specified error message and a reference to the + /// inner exception that is the cause of this exception. + /// + /// The message that describes the error. + /// The exception that is the cause of the current exception. If the + /// innerException parameter is not a null reference (Nothing in Visual Basic), the current exception + /// is raised in a catch block that handles the inner exception. + public MergeException(string msg, Exception innerException) + : base(msg, innerException) + { + } + + ///+ /// Creates a new MergeException with a specified error message. + /// + /// The message that describes the error. + public MergeException(string msg) + : base(msg) + { + } + + ///+ /// Creates a new MergeException. + /// + public MergeException() + : base() + { + } + + internal MergeException(Database db, string conflictsTableName) + : base("Merge failed.") + { + if (conflictsTableName != null) + { + IListconflictTableList = new List (); + IList conflictCountList = new List (); + + using (View view = db.OpenView("SELECT `Table`, `NumRowMergeConflicts` FROM `" + conflictsTableName + "`")) + { + view.Execute(); + + foreach (Record rec in view) using (rec) + { + conflictTableList.Add(rec.GetString(1)); + conflictCountList.Add((int) rec.GetInteger(2)); + } + } + + this.conflictTables = conflictTableList; + this.conflictCounts = conflictCountList; + } + } + + /// + /// Initializes a new instance of the MergeException class with serialized data. + /// + /// The SerializationInfo that holds the serialized object data about the exception being thrown. + /// The StreamingContext that contains contextual information about the source or destination. + protected MergeException(SerializationInfo info, StreamingContext context) : base(info, context) + { + if (info == null) + { + throw new ArgumentNullException("info"); + } + + this.conflictTables = (string[]) info.GetValue("mergeConflictTables", typeof(string[])); + this.conflictCounts = (int[]) info.GetValue("mergeConflictCounts", typeof(int[])); + } + + ///+ /// Gets the number of merge conflicts in each table, corresponding to the tables returned by + /// + public IList. + /// ConflictCounts + { + get + { + return new List (this.conflictCounts); + } + } + + /// + /// Gets the list of tables containing merge conflicts. + /// + public IListConflictTables + { + get + { + return new List (this.conflictTables); + } + } + + /// + /// Gets a message that describes the merge conflits. + /// + public override String Message + { + get + { + StringBuilder msg = new StringBuilder(base.Message); + if (this.conflictTables != null) + { + for (int i = 0; i < this.conflictTables.Count; i++) + { + msg.Append(i == 0 ? " Conflicts: " : ", "); + msg.Append(this.conflictTables[i]); + msg.Append('('); + msg.Append(this.conflictCounts[i]); + msg.Append(')'); + } + } + return msg.ToString(); + } + } + + ///+ /// Sets the SerializationInfo with information about the exception. + /// + /// The SerializationInfo that holds the serialized object data about the exception being thrown. + /// The StreamingContext that contains contextual information about the source or destination. + [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)] + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new ArgumentNullException("info"); + } + + info.AddValue("mergeConflictTables", this.conflictTables); + info.AddValue("mergeConflictCounts", this.conflictCounts); + base.GetObjectData(info, context); + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/ExternalUIHandler.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/ExternalUIHandler.cs new file mode 100644 index 00000000..08f00867 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/ExternalUIHandler.cs @@ -0,0 +1,223 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.Collections; + using System.Runtime.InteropServices; + using System.Diagnostics.CodeAnalysis; + + ///+ /// Defines a callback function that the installer calls for progress notification and error messages. + /// + public delegate MessageResult ExternalUIHandler( + InstallMessage messageType, + string message, + MessageButtons buttons, + MessageIcon icon, + MessageDefaultButton defaultButton); + + ///+ /// [MSI 3.1] Defines a callback function that the installer calls for record-based progress notification and error messages. + /// + public delegate MessageResult ExternalUIRecordHandler( + InstallMessage messageType, + Record messageRecord, + MessageButtons buttons, + MessageIcon icon, + MessageDefaultButton defaultButton); + + internal delegate int NativeExternalUIHandler(IntPtr context, int messageType, [MarshalAs(UnmanagedType.LPWStr)] string message); + + internal delegate int NativeExternalUIRecordHandler(IntPtr context, int messageType, int recordHandle); + + internal class ExternalUIProxy + { + private ExternalUIHandler handler; + + internal ExternalUIProxy(ExternalUIHandler handler) + { + this.handler = handler; + } + + public ExternalUIHandler Handler + { + get { return this.handler; } + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + public int ProxyHandler(IntPtr contextPtr, int messageType, [MarshalAs(UnmanagedType.LPWStr)] string message) + { + try + { + int msgType = messageType & 0x7F000000; + int buttons = messageType & 0x0000000F; + int icon = messageType & 0x000000F0; + int defButton = messageType & 0x00000F00; + + return (int) this.handler( + (InstallMessage) msgType, + message, + (MessageButtons) buttons, + (MessageIcon) icon, + (MessageDefaultButton) defButton); + } + catch + { + return (int) MessageResult.Error; + } + } + } + + internal class ExternalUIRecordProxy + { + private ExternalUIRecordHandler handler; + + internal ExternalUIRecordProxy(ExternalUIRecordHandler handler) + { + this.handler = handler; + } + + public ExternalUIRecordHandler Handler + { + get { return this.handler; } + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + public int ProxyHandler(IntPtr contextPtr, int messageType, int recordHandle) + { + try + { + int msgType = messageType & 0x7F000000; + int buttons = messageType & 0x0000000F; + int icon = messageType & 0x000000F0; + int defButton = messageType & 0x00000F00; + + Record msgRec = (recordHandle != 0 ? Record.FromHandle((IntPtr) recordHandle, false) : null); + using (msgRec) + { + return (int) this.handler( + (InstallMessage) msgType, + msgRec, + (MessageButtons) buttons, + (MessageIcon) icon, + (MessageDefaultButton) defButton); + } + } + catch + { + return (int) MessageResult.Error; + } + } + } + + public static partial class Installer + { + private static IList externalUIHandlers = ArrayList.Synchronized(new ArrayList()); + + ///+ /// Enables an external user-interface handler. This external UI handler is called before the + /// normal internal user-interface handler. The external UI handler has the option to suppress + /// the internal UI by returning a non-zero value to indicate that it has handled the messages. + /// + /// A callback delegate that handles the UI messages + /// Specifies which messages to handle using the external message handler. + /// If the external handler returns a non-zero result, then that message will not be sent to the UI, + /// instead the message will be logged if logging has been enabled. + ///The previously set external handler, or null if there was no previously set handler + ///+ public static ExternalUIHandler SetExternalUI(ExternalUIHandler uiHandler, InstallLogModes messageFilter) + { + NativeExternalUIHandler nativeHandler = null; + if (uiHandler != null) + { + nativeHandler = new ExternalUIProxy(uiHandler).ProxyHandler; + Installer.externalUIHandlers.Add(nativeHandler); + } + NativeExternalUIHandler oldNativeHandler = NativeMethods.MsiSetExternalUI(nativeHandler, (uint) messageFilter, IntPtr.Zero); + if (oldNativeHandler != null && oldNativeHandler.Target is ExternalUIProxy) + { + Installer.externalUIHandlers.Remove(oldNativeHandler); + return ((ExternalUIProxy) oldNativeHandler.Target).Handler; + } + else + { + return null; + } + } + + /// + /// To restore the previous UI handler, a second call is made to SetExternalUI using the + /// ExternalUIHandler returned by the first call to SetExternalUI and specifying + ///
as the message filter. + /// + /// The external user interface handler does not have full control over the external user + /// interface unless
is called with the uiLevel parameter set to + /// . If SetInternalUI is not called, the internal user + /// interface level defaults to . As a result, any message not + /// handled by the external user interface handler is handled by Windows Installer. The initial + /// "Preparing to install..." dialog always appears even if the external user interface + /// handler handles all messages. + /// + /// SetExternalUI should only be called from a bootstrapping application. You cannot call + /// it from a custom action + ///
+ /// Win32 MSI API: + /// MsiSetExternalUI + ///
+ /// [MSI 3.1] Enables a record-based external user-interface handler. This external UI handler is called + /// before the normal internal user-interface handler. The external UI handler has the option to suppress + /// the internal UI by returning a non-zero value to indicate that it has handled the messages. + /// + /// A callback delegate that handles the UI messages + /// Specifies which messages to handle using the external message handler. + /// If the external handler returns a non-zero result, then that message will not be sent to the UI, + /// instead the message will be logged if logging has been enabled. + ///The previously set external handler, or null if there was no previously set handler + ///+ public static ExternalUIRecordHandler SetExternalUI(ExternalUIRecordHandler uiHandler, InstallLogModes messageFilter) + { + NativeExternalUIRecordHandler nativeHandler = null; + if (uiHandler != null) + { + nativeHandler = new ExternalUIRecordProxy(uiHandler).ProxyHandler; + Installer.externalUIHandlers.Add(nativeHandler); + } + NativeExternalUIRecordHandler oldNativeHandler; + uint ret = NativeMethods.MsiSetExternalUIRecord(nativeHandler, (uint) messageFilter, IntPtr.Zero, out oldNativeHandler); + if (ret != 0) + { + Installer.externalUIHandlers.Remove(nativeHandler); + throw InstallerException.ExceptionFromReturnCode(ret); + } + + if (oldNativeHandler != null && oldNativeHandler.Target is ExternalUIRecordProxy) + { + Installer.externalUIHandlers.Remove(oldNativeHandler); + return ((ExternalUIRecordProxy) oldNativeHandler.Target).Handler; + } + else + { + return null; + } + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/FeatureInfo.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/FeatureInfo.cs new file mode 100644 index 00000000..9a1a859a --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/FeatureInfo.cs @@ -0,0 +1,497 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.Text; + using System.Collections; + using System.Collections.Generic; + + /// + /// To restore the previous UI handler, a second call is made to SetExternalUI using the + /// ExternalUIHandler returned by the first call to SetExternalUI and specifying + ///
as the message filter. + /// + /// The external user interface handler does not have full control over the external user + /// interface unless
is called with the uiLevel parameter set to + /// . If SetInternalUI is not called, the internal user + /// interface level defaults to . As a result, any message not + /// handled by the external user interface handler is handled by Windows Installer. The initial + /// "Preparing to install..." dialog always appears even if the external user interface + /// handler handles all messages. + /// + /// SetExternalUI should only be called from a bootstrapping application. You cannot call + /// it from a custom action + ///
+ /// Win32 MSI API: + /// MsiSetExternalUIRecord + ///
+ /// Accessor for information about features within the context of an installation session. + /// + public sealed class FeatureInfoCollection : ICollection+ { + private Session session; + + internal FeatureInfoCollection(Session session) + { + this.session = session; + } + + /// + /// Gets information about a feature within the context of an installation session. + /// + /// name of the feature + ///feature object + public FeatureInfo this[string feature] + { + get + { + return new FeatureInfo(this.session, feature); + } + } + + void ICollection.Add(FeatureInfo item) + { + throw new InvalidOperationException(); + } + + void ICollection .Clear() + { + throw new InvalidOperationException(); + } + + /// + /// Checks if the collection contains a feature. + /// + /// name of the feature + ///true if the feature is in the collection, else false + public bool Contains(string feature) + { + return this.session.Database.CountRows( + "Feature", "`Feature` = '" + feature + "'") == 1; + } + + bool ICollection.Contains(FeatureInfo item) + { + return item != null && this.Contains(item.Name); + } + + /// + /// Copies the features into an array. + /// + /// array that receives the features + /// offset into the array + public void CopyTo(FeatureInfo[] array, int arrayIndex) + { + foreach (FeatureInfo feature in this) + { + array[arrayIndex++] = feature; + } + } + + ///+ /// Gets the number of features defined for the product. + /// + public int Count + { + get + { + return this.session.Database.CountRows("Feature"); + } + } + + bool ICollection.IsReadOnly + { + get + { + return true; + } + } + + bool ICollection .Remove(FeatureInfo item) + { + throw new InvalidOperationException(); + } + + /// + /// Enumerates the features in the collection. + /// + ///an enumerator over all features in the collection + public IEnumeratorGetEnumerator() + { + using (View featureView = this.session.Database.OpenView( + "SELECT `Feature` FROM `Feature`")) + { + featureView.Execute(); + + foreach (Record featureRec in featureView) using (featureRec) + { + string feature = featureRec.GetString(1); + yield return new FeatureInfo(this.session, feature); + } + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + } + + /// + /// Provides access to information about a feature within the context of an installation session. + /// + public class FeatureInfo + { + private Session session; + private string name; + + internal FeatureInfo(Session session, string name) + { + this.session = session; + this.name = name; + } + + ///+ /// Gets the name of the feature (primary key in the Feature table). + /// + public string Name + { + get + { + return this.name; + } + } + + ///+ /// Gets the current install state of the feature. + /// + ///the Session handle is invalid + ///an unknown feature was requested + ///+ public InstallState CurrentState + { + get + { + int installState, actionState; + uint ret = RemotableNativeMethods.MsiGetFeatureState((int) this.session.Handle, this.name, out installState, out actionState); + if (ret != 0) + { + if (ret == (uint) NativeMethods.Error.UNKNOWN_FEATURE) + { + throw InstallerException.ExceptionFromReturnCode(ret, this.name); + } + else + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + if (installState == (int) InstallState.Advertised) + { + return InstallState.Advertised; + } + return (InstallState) installState; + } + } + + /// + /// Win32 MSI API: + /// MsiGetFeatureState + ///
+ /// Gets or sets the action state of the feature. + /// + ///the Session handle is invalid + ///an unknown feature was requested + ///+ public InstallState RequestState + { + get + { + int installState, actionState; + uint ret = RemotableNativeMethods.MsiGetFeatureState((int) this.session.Handle, this.name, out installState, out actionState); + if (ret != 0) + { + if (ret == (uint) NativeMethods.Error.UNKNOWN_FEATURE) + { + throw InstallerException.ExceptionFromReturnCode(ret, this.name); + } + else + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + return (InstallState) actionState; + } + + set + { + uint ret = RemotableNativeMethods.MsiSetFeatureState((int) this.session.Handle, this.name, (int) value); + if (ret != 0) + { + if (ret == (uint) NativeMethods.Error.UNKNOWN_FEATURE) + { + throw InstallerException.ExceptionFromReturnCode(ret, this.name); + } + else + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + } + } + + /// + /// When changing the feature action, the action state of all the Components linked to the changed + /// Feature records are also updated appropriately, based on the new feature Select state. + /// All Features can be configured at once by specifying the keyword ALL instead of a specific feature name. + ///
+ /// Win32 MSI APIs: + /// MsiGetFeatureState, + /// MsiSetFeatureState + ///
+ /// Gets a list of valid installation states for the feature. + /// + ///the Session handle is invalid + ///an unknown feature was requested + ///+ public ICollection + /// Win32 MSI API: + /// MsiGetFeatureValidStates + ///
ValidStates + { + get + { + List states = new List (); + uint installState; + uint ret = RemotableNativeMethods.MsiGetFeatureValidStates((int) this.session.Handle, this.name, out installState); + if (ret != 0) + { + if (ret == (uint) NativeMethods.Error.UNKNOWN_FEATURE) + { + throw InstallerException.ExceptionFromReturnCode(ret, this.name); + } + else + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + for (int i = 1; i <= (int) InstallState.Default; i++) + { + if (((int) installState & (1 << i)) != 0) + { + states.Add((InstallState) i); + } + } + return states.AsReadOnly(); + } + } + + /// + /// Gets or sets the attributes of the feature. + /// + ///the Session handle is invalid + ///an unknown feature was requested + ///+ public FeatureAttributes Attributes + { + get + { + FeatureAttributes attributes; + uint titleBufSize = 0; + uint descBufSize = 0; + uint attr; + uint ret = NativeMethods.MsiGetFeatureInfo( + (int) this.session.Handle, + this.name, + out attr, + null, + ref titleBufSize, + null, + ref descBufSize); + + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + + // Values for attributes that MsiGetFeatureInfo returns are + // double the values in the Attributes column of the Feature Table. + attributes = (FeatureAttributes) (attr >> 1); + + // MsiGetFeatureInfo MSDN documentation indicates + // NOUNSUPPORTEDADVERTISE is 32. Conversion above changes this to 16 + // which is UIDisallowAbsent. MsiGetFeatureInfo isn't documented to + // return an attribute for 'UIDisallowAbsent', so if UIDisallowAbsent + // is set, change it to NoUnsupportedAdvertise which then maps correctly + // to NOUNSUPPORTEDADVERTISE. + if ((attributes & FeatureAttributes.UIDisallowAbsent) == FeatureAttributes.UIDisallowAbsent) + { + attributes &= ~FeatureAttributes.UIDisallowAbsent; + attributes |= FeatureAttributes.NoUnsupportedAdvertise; + } + + return attributes; + } + + set + { + // MsiSetFeatureAttributes doesn't indicate UIDisallowAbsent is valid + // so remove it. + FeatureAttributes attributes = value; + attributes &= ~FeatureAttributes.UIDisallowAbsent; + + // Values for attributes that MsiSetFeatureAttributes uses are + // double the values in the Attributes column of the Feature Table. + uint attr = ((uint) attributes) << 1; + + // MsiSetFeatureAttributes MSDN documentation indicates + // NOUNSUPPORTEDADVERTISE is 32. Conversion above changes this to 64 + // which is undefined. Change this back to 32. + uint noUnsupportedAdvertiseDbl = ((uint)FeatureAttributes.NoUnsupportedAdvertise) << 1; + if ((attr & noUnsupportedAdvertiseDbl) == noUnsupportedAdvertiseDbl) + { + attr &= ~noUnsupportedAdvertiseDbl; + attr |= (uint) FeatureAttributes.NoUnsupportedAdvertise; + } + + uint ret = RemotableNativeMethods.MsiSetFeatureAttributes((int) this.session.Handle, this.name, attr); + + if (ret != (uint)NativeMethods.Error.SUCCESS) + { + if (ret == (uint)NativeMethods.Error.UNKNOWN_FEATURE) + { + throw InstallerException.ExceptionFromReturnCode(ret, this.name); + } + else + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + } + } + + /// + /// Win32 MSI APIs: + /// MsiGetFeatureInfo, + /// MsiSetFeatureAttributes + ///
+ /// Since the lpAttributes paramter of + /// MsiGetFeatureInfo + /// does not contain an equivalent flag for
, this flag will + /// not be retrieved. + /// + /// Since the dwAttributes parameter of + /// MsiSetFeatureAttributes + /// does not contain an equivalent flag for
, the presence + /// of this flag will be ignored. + /// + /// Gets the title of the feature. + /// + ///the Session handle is invalid + ///an unknown feature was requested + ///+ public string Title + { + get + { + StringBuilder titleBuf = new StringBuilder(80); + uint titleBufSize = (uint) titleBuf.Capacity; + uint descBufSize = 0; + uint attr; + uint ret = NativeMethods.MsiGetFeatureInfo( + (int) this.session.Handle, + this.name, + out attr, + titleBuf, + ref titleBufSize, + null, + ref descBufSize); + + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + titleBuf.Capacity = (int) ++titleBufSize; + ret = NativeMethods.MsiGetFeatureInfo( + (int) this.session.Handle, + this.name, + out attr, + titleBuf, + ref titleBufSize, + null, + ref descBufSize); + } + + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + + return titleBuf.ToString(); + } + } + + /// + /// Win32 MSI API: + /// MsiGetFeatureInfo + ///
+ /// Gets the description of the feature. + /// + ///the Session handle is invalid + ///an unknown feature was requested + ///+ public string Description + { + get + { + StringBuilder descBuf = new StringBuilder(256); + uint titleBufSize = 0; + uint descBufSize = (uint) descBuf.Capacity; + uint attr; + uint ret = NativeMethods.MsiGetFeatureInfo( + (int) this.session.Handle, + this.name, + out attr, + null, + ref titleBufSize, + descBuf, + ref descBufSize); + + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + descBuf.Capacity = (int) ++descBufSize; + ret = NativeMethods.MsiGetFeatureInfo( + (int) this.session.Handle, + this.name, + out attr, + null, + ref titleBufSize, + descBuf, + ref descBufSize); + } + + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + + return descBuf.ToString(); + } + } + + /// + /// Win32 MSI API: + /// MsiGetFeatureInfo + ///
+ /// Calculates the disk space required by the feature and its selected children and parent features. + /// + /// If true, the parent features are included in the cost. + /// If true, the child features are included in the cost. + /// Specifies the installation state. + ///The disk space requirement in bytes. + ///+ public long GetCost(bool includeParents, bool includeChildren, InstallState installState) + { + const int MSICOSTTREE_CHILDREN = 1; + const int MSICOSTTREE_PARENTS = 2; + + int cost; + uint ret = RemotableNativeMethods.MsiGetFeatureCost( + (int) this.session.Handle, + this.name, + (includeParents ? MSICOSTTREE_PARENTS : 0) | (includeChildren ? MSICOSTTREE_CHILDREN : 0), + (int) installState, + out cost); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + return cost * 512L; + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/FeatureInstallation.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/FeatureInstallation.cs new file mode 100644 index 00000000..aa8ffe34 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/FeatureInstallation.cs @@ -0,0 +1,174 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.Text; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + + /// + /// Win32 MSI API: + /// MsiGetFeatureCost + ///
+ /// Represents an instance of a feature of an installed product. + /// + public class FeatureInstallation : InstallationPart + { + ///+ /// Creates a new FeatureInstallation instance for a feature of a product. + /// + /// feature name + /// ProductCode GUID + public FeatureInstallation(string featureName, string productCode) + : base(featureName, productCode) + { + if (String.IsNullOrEmpty(featureName)) + { + throw new ArgumentNullException("featureName"); + } + } + + ///+ /// Gets the name of the feature. + /// + public string FeatureName + { + get + { + return this.Id; + } + } + + ///+ /// Gets the installed state of the feature. + /// + ///+ public override InstallState State + { + get + { + int installState = NativeMethods.MsiQueryFeatureState( + this.ProductCode, this.FeatureName); + return (InstallState) installState; + } + } + + /// + /// Win32 MSI API: + /// MsiQueryFeatureState + ///
+ /// Gets the parent of the feature, or null if the feature has no parent (it is a root feature). + /// + ///+ /// Invocation of this property may be slightly costly for products with many features, + /// because it involves an enumeration of all the features in the product. + /// + public FeatureInstallation Parent + { + get + { + StringBuilder featureBuf = new StringBuilder(256); + StringBuilder parentBuf = new StringBuilder(256); + for (uint i = 0; ; i++) + { + uint ret = NativeMethods.MsiEnumFeatures(this.ProductCode, i, featureBuf, parentBuf); + + if (ret != 0) + { + break; + } + + if (featureBuf.ToString() == this.FeatureName) + { + if (parentBuf.Length > 0) + { + return new FeatureInstallation(parentBuf.ToString(), this.ProductCode); + } + else + { + return null; + } + } + } + + return null; + } + } + + ///+ /// Gets the usage metrics for the feature. + /// + ///+ public FeatureInstallation.UsageData Usage + { + get + { + uint useCount; + ushort useDate; + uint ret = NativeMethods.MsiGetFeatureUsage( + this.ProductCode, this.FeatureName, out useCount, out useDate); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + + DateTime lastUsedDate; + if (useCount == 0) + { + lastUsedDate = DateTime.MinValue; + } + else + { + lastUsedDate = new DateTime( + 1980 + (useDate >> 9), + (useDate & 0x01FF) >> 5, + (useDate & 0x001F)); + } + + return new UsageData((int) useCount, lastUsedDate); + } + } + + /// + /// If no usage metrics are recorded, the
value is 0. + /// + /// Win32 MSI API: + /// MsiGetFeatureUsage + ///
+ /// Holds data about the usage of a feature. + /// + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] + public struct UsageData + { + private int useCount; + private DateTime lastUsedDate; + + internal UsageData(int useCount, DateTime lastUsedDate) + { + this.useCount = useCount; + this.lastUsedDate = lastUsedDate; + } + + ///+ /// Gets count of the number of times the feature has been used. + /// + public int UseCount + { + get + { + return this.useCount; + } + } + + ///+ /// Gets the date the feature was last used. + /// + public DateTime LastUsedDate + { + get + { + return this.lastUsedDate; + } + } + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Handle.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Handle.cs new file mode 100644 index 00000000..c3d3625f --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Handle.cs @@ -0,0 +1,154 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + + ///+ /// Base class for Windows Installer handle types (Database, View, Record, SummaryInfo). + /// + ///+ public abstract class InstallerHandle : MarshalByRefObject, IDisposable + { + private NativeMethods.MsiHandle handle; + + /// + /// These classes implement the
interface, because they + /// hold unmanaged resources (MSI handles) that should be properly disposed + /// when no longer needed. + /// + /// Constructs a handle object from a native integer handle. + /// + /// Native integer handle. + /// true to close the handle when this object is disposed or finalized + protected InstallerHandle(IntPtr handle, bool ownsHandle) + { + if (handle == IntPtr.Zero) + { + throw new InvalidHandleException(); + } + + this.handle = new NativeMethods.MsiHandle(handle, ownsHandle); + } + + ///+ /// Gets the native integer handle. + /// + [SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")] + public IntPtr Handle + { + get + { + if (this.IsClosed) + { + throw new InvalidHandleException(); + } + return this.handle; + } + } + + ///+ /// Checks if the handle is closed. When closed, method calls on the handle object may throw an + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public bool IsClosed + { + get + { + return this.handle.IsClosed; + } + } + + ///. + /// + /// Closes the handle. After closing a handle, further method calls may throw an + ///. + /// + /// + /// The finalizer of this class will NOT close the handle if it is still open, + /// because finalization can run on a separate thread from the application, + /// resulting in potential problems if handles are closed from that thread. + /// It is best that the handle be closed manually as soon as it is no longer needed, + /// as leaving lots of unused handles open can degrade performance. + ///
+ /// Win32 MSI API: + /// MsiCloseHandle + ///
+ public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Closes the handle. After closing a handle, further method calls may throw an + ///. + /// + public void Close() + { + this.Dispose(); + } + + /// + /// The finalizer of this class will NOT close the handle if it is still open, + /// because finalization can run on a separate thread from the application, + /// resulting in potential problems if handles are closed from that thread. + /// It is best that the handle be closed manually as soon as it is no longer needed, + /// as leaving lots of unused handles open can degrade performance. + ///
+ /// This method is merely an alias for the
method. + /// + /// Win32 MSI API: + /// MsiCloseHandle + ///
+ /// Tests whether this handle object is equal to another handle object. Two handle objects are equal + /// if their types are the same and their native integer handles are the same. + /// + /// The handle object to compare with the current handle object. + ///true if the specified handle object is equal to the current handle object; otherwise false + public override bool Equals(object obj) + { + return (obj != null && this.GetType() == obj.GetType() && + this.Handle == ((InstallerHandle) obj).Handle); + } + + ///+ /// Gets a hash value for the handle object. + /// + ///A hash code for the handle object. + ///+ public override int GetHashCode() + { + return this.Handle.GetHashCode(); + } + + /// + /// The hash code is derived from the native integer handle. + ///
+ /// Gets an object that can be used internally for safe syncronization. + /// + internal object Sync + { + get + { + return this.handle; + } + } + + ///+ /// Closes the handle. After closing a handle, further method calls may throw an + /// If true, the method has been called directly or indirectly by a user's code, + /// so managed and unmanaged resources will be disposed. If false, the method has been called by the + /// runtime from inside the finalizer, and only unmanaged resources will be disposed. + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + this.handle.Dispose(); + } + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/IEmbeddedUI.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/IEmbeddedUI.cs new file mode 100644 index 00000000..d77c82a9 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/IEmbeddedUI.cs @@ -0,0 +1,67 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System.Diagnostics.CodeAnalysis; + + ///. + /// + /// [MSI 4.5] Interface for an embedded external user interface for an installation. + /// + ///+ /// Classes which implement this interface must have a public constructor that takes no parameters. + /// + public interface IEmbeddedUI + { + ///+ /// Initializes the embedded UI. + /// + /// Handle to the installer which can be used to get and set properties. + /// The handle is only valid for the duration of this method call. + /// Path to the directory that contains all the files from the MsiEmbeddedUI table. + /// On entry, contains the current UI level for the installation. After this + /// method returns, the installer resets the UI level to the returned value of this parameter. + ///True if the embedded UI was successfully initialized; false if the installation + /// should continue without the embedded UI. + ///The installation was canceled by the user. + ///The embedded UI failed to initialize and + /// causes the installation to fail. + ///+ [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")] + bool Initialize(Session session, string resourcePath, ref InstallUIOptions internalUILevel); + + /// + /// Win32 MSI API: + /// InitializeEmbeddedUI + ///
+ /// Processes information and progress messages sent to the user interface. + /// + /// Message type. + /// Record that contains message data. + /// Message buttons. + /// Message box icon. + /// Message box default button. + ///Result of processing the message. + ///+ MessageResult ProcessMessage( + InstallMessage messageType, + Record messageRecord, + MessageButtons buttons, + MessageIcon icon, + MessageDefaultButton defaultButton); + + /// + /// Win32 MSI API: + /// EmbeddedUIHandler + ///
+ /// Shuts down the embedded UI at the end of the installation. + /// + ///+ /// If the installation was canceled during initialization, this method will not be called. + /// If the installation was canceled or failed at any later point, this method will be called at the end. + /// + void Shutdown(); + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/InstallCost.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/InstallCost.cs new file mode 100644 index 00000000..f29612d6 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/InstallCost.cs @@ -0,0 +1,67 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System.Diagnostics.CodeAnalysis; + + ///+ /// Win32 MSI API: + /// ShutdownEmbeddedUI + ///
+ /// Represents a per-drive disk space cost for an installation. + /// + [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] + public struct InstallCost + { + private string driveName; + private long cost; + private long tempCost; + + ///+ /// Creates a new InstallCost object. + /// + /// name of the drive this cost data applies to + /// installation cost on this drive, as a number of bytes + /// temporary disk space required on this drive, as a number of bytes + internal InstallCost(string driveName, long cost, long tempCost) + { + this.driveName = driveName; + this.cost = cost; + this.tempCost = tempCost; + } + + ///+ /// The name of the drive this cost data applies to. + /// + public string DriveName + { + get + { + return this.driveName; + } + } + + ///+ /// The installation cost on this drive, as a number of bytes. + /// + public long Cost + { + get + { + return this.cost; + } + } + + ///+ /// The temporary disk space required on this drive, as a number of bytes. + /// + ///+ public long TempCost + { + get + { + return this.tempCost; + } + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Installation.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Installation.cs new file mode 100644 index 00000000..47ca00a1 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Installation.cs @@ -0,0 +1,100 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.Text; + using System.Globalization; + + /// + /// This temporary space requirement is space needed only for the duration + /// of the installation, over the final footprint on disk. + ///
+ /// Subclasses of this abstract class represent a unique instance of a + /// registered product or patch installation. + /// + public abstract class Installation + { + private string installationCode; + private string userSid; + private UserContexts context; + private SourceList sourceList; + + internal Installation(string installationCode, string userSid, UserContexts context) + { + if (context == UserContexts.Machine) + { + userSid = null; + } + this.installationCode = installationCode; + this.userSid = userSid; + this.context = context; + } + + ///+ /// Gets the user security identifier (SID) under which this product or patch + /// installation is available. + /// + public string UserSid + { + get + { + return this.userSid; + } + } + + ///+ /// Gets the user context of this product or patch installation. + /// + public UserContexts Context + { + get + { + return this.context; + } + } + + ///+ /// Gets the source list of this product or patch installation. + /// + public virtual SourceList SourceList + { + get + { + if (this.sourceList == null) + { + this.sourceList = new SourceList(this); + } + return this.sourceList; + } + } + + ///+ /// Gets a value indicating whether this product or patch is installed on the current system. + /// + public abstract bool IsInstalled + { + get; + } + + internal string InstallationCode + { + get + { + return this.installationCode; + } + } + + internal abstract int InstallationType + { + get; + } + + ///+ /// Gets a property about the product or patch installation. + /// + /// Name of the property being retrieved. + ///+ public abstract string this[string propertyName] + { + get; + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/InstallationPart.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/InstallationPart.cs new file mode 100644 index 00000000..ce5a6a94 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/InstallationPart.cs @@ -0,0 +1,82 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + /// + /// Subclasses of this abstract class represent an instance + /// of a registered feature or component. + /// + public abstract class InstallationPart + { + private string id; + private string productCode; + private string userSid; + private UserContexts context; + + internal InstallationPart(string id, string productCode) + : this(id, productCode, null, UserContexts.None) + { + } + + internal InstallationPart(string id, string productCode, string userSid, UserContexts context) + { + this.id = id; + this.productCode = productCode; + this.userSid = userSid; + this.context = context; + } + + internal string Id + { + get + { + return this.id; + } + } + + internal string ProductCode + { + get + { + return this.productCode; + } + } + + internal string UserSid + { + get + { + return this.userSid; + } + } + + internal UserContexts Context + { + get + { + return this.context; + } + } + + ///+ /// Gets the product that this item is a part of. + /// + public ProductInstallation Product + { + get + { + return this.productCode != null ? + new ProductInstallation(this.productCode, userSid, context) : null; + } + } + + ///+ /// Gets the current installation state of the item. + /// + public abstract InstallState State + { + get; + } + } + +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Installer.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Installer.cs new file mode 100644 index 00000000..8df0aed9 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Installer.cs @@ -0,0 +1,890 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.IO; + using System.Text; + using System.Resources; + using System.Reflection; + using System.Collections.Generic; + using System.Globalization; + using System.Runtime.InteropServices; + using System.Diagnostics.CodeAnalysis; + +///+/// Receives an exception from +/// +/// MSP file path, XML file path, or XML blob that was passed to +///+/// indicating the reason a particular patch is not applicable to a product. +/// +/// exception indicating the reason the patch is not applicable +/// +public delegate void InapplicablePatchHandler(string patch, Exception exception); + +/// +/// If
is an or subclass, then +/// its and +/// properties will indicate a more specific reason the patch was not applicable. +/// +/// The
could also be a FileNotFoundException if the +/// patch string was a file path. +/// +/// Provides static methods for installing and configuring products and patches. +/// +public static partial class Installer +{ + private static bool rebootRequired; + private static bool rebootInitiated; + private static ResourceManager errorResources; + + ///+ /// Indicates whether a system reboot is required after running an installation or configuration operation. + /// + public static bool RebootRequired + { + get + { + return Installer.rebootRequired; + } + } + + ///+ /// Indicates whether a system reboot has been initiated after running an installation or configuration operation. + /// + public static bool RebootInitiated + { + get + { + return Installer.rebootInitiated; + } + } + + ///+ /// Enables the installer's internal user interface. Then this user interface is used + /// for all subsequent calls to user-interface-generating installer functions in this process. + /// + /// Specifies the level of complexity of the user interface + /// Handle to a window, which becomes the owner of any user interface created. + /// A pointer to the previous owner of the user interface is returned. + ///The previous user interface level + ///+ [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")] + public static InstallUIOptions SetInternalUI(InstallUIOptions uiOptions, ref IntPtr windowHandle) + { + return (InstallUIOptions) NativeMethods.MsiSetInternalUI((uint) uiOptions, ref windowHandle); + } + + /// + /// Win32 MSI API: + /// MsiSetInternalUI + ///
+ /// Enables the installer's internal user interface. Then this user interface is used + /// for all subsequent calls to user-interface-generating installer functions in this process. + /// The owner of the user interface does not change. + /// + /// Specifies the level of complexity of the user interface + ///The previous user interface level + ///+ public static InstallUIOptions SetInternalUI(InstallUIOptions uiOptions) + { + return (InstallUIOptions) NativeMethods.MsiSetInternalUI((uint) uiOptions, IntPtr.Zero); + } + + /// + /// Win32 MSI API: + /// MsiSetInternalUI + ///
+ /// Enables logging of the selected message type for all subsequent install sessions in + /// the current process space. + /// + /// One or more mode flags specifying the type of messages to log + /// Full path to the log file. A null path disables logging, + /// in which case the logModes paraneter is ignored. + ///an invalid log mode was specified + ///This method takes effect on any new installation processes. Calling this + /// method from within a custom action will not start logging for that installation. + public static void EnableLog(InstallLogModes logModes, string logFile) + { + Installer.EnableLog(logModes, logFile, false, true); + } + + ///+ /// Enables logging of the selected message type for all subsequent install sessions in + /// the current process space. + /// + /// One or more mode flags specifying the type of messages to log + /// Full path to the log file. A null path disables logging, + /// in which case the logModes paraneter is ignored. + /// If true, the log lines will be appended to any existing file content. + /// If false, the log file will be truncated if it exists. The default is false. + /// If true, the log will be flushed after every line. + /// If false, the log will be flushed every 20 lines. The default is true. + ///an invalid log mode was specified + ///+ public static void EnableLog(InstallLogModes logModes, string logFile, bool append, bool flushEveryLine) + { + uint ret = NativeMethods.MsiEnableLog((uint) logModes, logFile, (append ? (uint) 1 : 0) + (flushEveryLine ? (uint) 2 : 0)); + if (ret != 0 && ret != (uint) NativeMethods.Error.FILE_INVALID) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// This method takes effect on any new installation processes. Calling this + /// method from within a custom action will not start logging for that installation. + ///
+ /// Win32 MSI API: + /// MsiEnableLog + ///
+ /// increments the usage count for a particular feature and returns the installation state for + /// that feature. This method should be used to indicate an application's intent to use a feature. + /// + /// The product code of the product. + /// The feature to be used. + /// Must have the value. + /// The installed state of the feature. + ///+ public static InstallState UseFeature(string productCode, string feature, InstallMode installMode) + { + int installState = NativeMethods.MsiUseFeatureEx(productCode, feature, unchecked ((uint) installMode), 0); + return (InstallState) installState; + } + + /// + /// The UseFeature method should only be used on features known to be published. The application + /// should determine the status of the feature by calling either the FeatureState method or + /// Features method. + ///
+ /// Win32 MSI APIs: + /// MsiUseFeature, + /// MsiUseFeatureEx + ///
+ /// Opens an installer package for use with functions that access the product database and install engine, + /// returning an Session object. + /// + /// Path to the package + /// Specifies whether or not the create a Session object that ignores the + /// computer state and that is incapable of changing the current computer state. A value of false yields + /// the normal behavior. A value of true creates a "safe" Session object that cannot change of the current + /// machine state. + ///A Session object allowing access to the product database and install engine + ///The product could not be opened + ///The installer configuration data is corrupt + ///+ public static Session OpenPackage(string packagePath, bool ignoreMachineState) + { + int sessionHandle; + uint ret = NativeMethods.MsiOpenPackageEx(packagePath, ignoreMachineState ? (uint) 1 : 0, out sessionHandle); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + return new Session((IntPtr) sessionHandle, true); + } + + /// + /// Note that only one Session object can be opened by a single process. OpenPackage cannot be used in a + /// custom action because the active installation is the only session allowed. + ///
+ /// A "safe" Session object ignores the current computer state when opening the package and prevents + /// changes to the current computer state. + ///
+ /// The Session object should be
d after use. + /// It is best that the handle be closed manually as soon as it is no longer + /// needed, as leaving lots of unused handles open can degrade performance. + /// + /// Win32 MSI APIs: + /// MsiOpenPackage, + /// MsiOpenPackageEx + ///
+ /// Opens an installer package for use with functions that access the product database and install engine, + /// returning an Session object. + /// + /// Database used to create the session + /// Specifies whether or not the create a Session object that ignores the + /// computer state and that is incapable of changing the current computer state. A value of false yields + /// the normal behavior. A value of true creates a "safe" Session object that cannot change of the current + /// machine state. + ///A Session object allowing access to the product database and install engine + ///The product could not be opened + ///The installer configuration data is corrupt + ///+ [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public static Session OpenPackage(Database database, bool ignoreMachineState) + { + if (database == null) + { + throw new ArgumentNullException("database"); + } + + return Installer.OpenPackage( + String.Format(CultureInfo.InvariantCulture, "#{0}", database.Handle), + ignoreMachineState); + } + + /// + /// Note that only one Session object can be opened by a single process. OpenPackage cannot be used in a + /// custom action because the active installation is the only session allowed. + ///
+ /// A "safe" Session object ignores the current computer state when opening the package and prevents + /// changes to the current computer state. + ///
+ /// The Session object should be
d after use. + /// It is best that the handle be closed manually as soon as it is no longer + /// needed, as leaving lots of unused handles open can degrade performance. + /// + /// Win32 MSI APIs: + /// MsiOpenPackage, + /// MsiOpenPackageEx + ///
+ /// Opens an installer package for an installed product using the product code. + /// + /// Product code of the installed product + ///A Session object allowing access to the product database and install engine, + /// or null if the specified product is not installed. + ///An unknown product was requested + ///The product could not be opened + ///The installer configuration data is corrupt + ///+ public static Session OpenProduct(string productCode) + { + int sessionHandle; + uint ret = NativeMethods.MsiOpenProduct(productCode, out sessionHandle); + if (ret != 0) + { + if (ret == (uint) NativeMethods.Error.UNKNOWN_PRODUCT) + { + return null; + } + else + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + return new Session((IntPtr) sessionHandle, true); + } + + /// + /// Note that only one Session object can be opened by a single process. OpenProduct cannot be + /// used in a custom action because the active installation is the only session allowed. + ///
+ /// The Session object should be
d after use. + /// It is best that the handle be closed manually as soon as it is no longer + /// needed, as leaving lots of unused handles open can degrade performance. + /// + /// Win32 MSI API: + /// MsiOpenProduct + ///
+ /// Gets the full component path, performing any necessary installation. This method prompts for source if + /// necessary and increments the usage count for the feature. + /// + /// Product code for the product that contains the feature with the necessary component + /// Feature ID of the feature with the necessary component + /// Component code of the necessary component + /// Installation mode; this can also include bits from+ /// Path to the component + ///+ public static string ProvideComponent(string product, string feature, string component, InstallMode installMode) + { + StringBuilder pathBuf = new StringBuilder(512); + uint pathBufSize = (uint) pathBuf.Capacity; + uint ret = NativeMethods.MsiProvideComponent(product, feature, component, unchecked((uint)installMode), pathBuf, ref pathBufSize); + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + pathBuf.Capacity = (int) ++pathBufSize; + ret = NativeMethods.MsiProvideComponent(product, feature, component, unchecked((uint)installMode), pathBuf, ref pathBufSize); + } + + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + return pathBuf.ToString(); + } + + /// + /// Win32 MSI API: + /// MsiProvideComponent + ///
+ /// Gets the full component path for a qualified component that is published by a product and + /// performs any necessary installation. This method prompts for source if necessary and increments + /// the usage count for the feature. + /// + /// Specifies the component ID for the requested component. This may not be the + /// GUID for the component itself but rather a server that provides the correct functionality, as in the + /// ComponentId column of the PublishComponent table. + /// Specifies a qualifier into a list of advertising components (from PublishComponent Table). + /// Installation mode; this can also include bits from+ /// Optional; specifies the product to match that has published the qualified component. + /// Path to the component + ///+ public static string ProvideQualifiedComponent(string component, string qualifier, InstallMode installMode, string product) + { + StringBuilder pathBuf = new StringBuilder(512); + uint pathBufSize = (uint) pathBuf.Capacity; + uint ret = NativeMethods.MsiProvideQualifiedComponentEx(component, qualifier, unchecked((uint)installMode), product, 0, 0, pathBuf, ref pathBufSize); + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + pathBuf.Capacity = (int) ++pathBufSize; + ret = NativeMethods.MsiProvideQualifiedComponentEx(component, qualifier, unchecked((uint)installMode), product, 0, 0, pathBuf, ref pathBufSize); + } + + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + return pathBuf.ToString(); + } + + /// + /// Win32 MSI APIs: + /// MsiProvideQualifiedComponent + /// MsiProvideQualifiedComponentEx + ///
+ /// Gets the full path to a Windows Installer component containing an assembly. This method prompts for a source and + /// increments the usage count for the feature. + /// + /// Assembly name + /// Set to null for global assemblies. For private assemblies, set to the full path of the + /// application configuration file (.cfg file) or executable file (.exe) of the application to which the assembly + /// has been made private. + /// Installation mode; this can also include bits from+ /// True if this is a Win32 assembly, false if it is a .NET assembly + /// Path to the assembly + ///+ public static string ProvideAssembly(string assemblyName, string appContext, InstallMode installMode, bool isWin32Assembly) + { + StringBuilder pathBuf = new StringBuilder(512); + uint pathBufSize = (uint) pathBuf.Capacity; + uint ret = NativeMethods.MsiProvideAssembly(assemblyName, appContext, unchecked ((uint) installMode), (isWin32Assembly ? (uint) 1 : 0), pathBuf, ref pathBufSize); + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + pathBuf.Capacity = (int) ++pathBufSize; + ret = NativeMethods.MsiProvideAssembly(assemblyName, appContext, unchecked ((uint) installMode), (isWin32Assembly ? (uint) 1 : 0), pathBuf, ref pathBufSize); + } + + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + return pathBuf.ToString(); + } + + /// + /// Win32 MSI API: + /// MsiProvideAssembly + ///
+ /// Installs files that are unexpectedly missing. + /// + /// Product code for the product that owns the component to be installed + /// Component to be installed + /// Specifies the way the component should be installed. + ///the user exited the installation + ///+ public static void InstallMissingComponent(string product, string component, InstallState installState) + { + uint ret = NativeMethods.MsiInstallMissingComponent(product, component, (int) installState); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// Win32 MSI API: + /// MsiInstallMissingComponent + ///
+ /// Installs files that are unexpectedly missing. + /// + /// Product code for the product that owns the file to be installed + /// File to be installed + ///the user exited the installation + ///+ public static void InstallMissingFile(string product, string file) + { + uint ret = NativeMethods.MsiInstallMissingFile(product, file); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// Win32 MSI API: + /// MsiInstallMissingFile + ///
+ /// Reinstalls a feature. + /// + /// Product code for the product containing the feature to be reinstalled + /// Feature to be reinstalled + /// Reinstall modes + ///the user exited the installation + ///+ public static void ReinstallFeature(string product, string feature, ReinstallModes reinstallModes) + { + uint ret = NativeMethods.MsiReinstallFeature(product, feature, (uint) reinstallModes); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// Win32 MSI API: + /// MsiReinstallFeature + ///
+ /// Reinstalls a product. + /// + /// Product code for the product to be reinstalled + /// Reinstall modes + ///the user exited the installation + ///+ public static void ReinstallProduct(string product, ReinstallModes reinstallModes) + { + uint ret = NativeMethods.MsiReinstallProduct(product, (uint) reinstallModes); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// Win32 MSI API: + /// MsiReinstallProduct + ///
+ /// Opens an installer package and initializes an install session. + /// + /// path to the patch package + /// command line property settings + ///There was an error installing the product + ///+ public static void InstallProduct(string packagePath, string commandLine) + { + uint ret = NativeMethods.MsiInstallProduct(packagePath, commandLine); + Installer.CheckInstallResult(ret); + } + + /// + /// To completely remove a product, set REMOVE=ALL in
. + /// + /// This method displays the user interface with the current settings and + /// log mode. You can change user interface settings with the
+ /// and functions. You can set the log mode with the + /// function. + /// + /// The
and properties should be + /// tested after calling this method. + /// + /// Win32 MSI API: + /// MsiInstallProduct + ///
+ /// Installs or uninstalls a product. + /// + /// Product code of the product to be configured. + /// Specifies the default installation configuration of the + /// product. Theparameter is ignored and all features + /// are installed if the parameter is set to any other + /// value than . This parameter must be either 0 + /// (install using authored feature levels), 65535 (install all features), or a value + /// between 0 and 65535 to install a subset of available features. + /// Specifies the installation state for the product. + /// Specifies the command line property settings. This should + /// be a list of the format Property=Setting Property=Setting. + /// There was an error configuring the product + ///+ public static void ConfigureProduct(string productCode, int installLevel, InstallState installState, string commandLine) + { + uint ret = NativeMethods.MsiConfigureProductEx(productCode, installLevel, (int) installState, commandLine); + Installer.CheckInstallResult(ret); + } + + /// + /// This method displays the user interface with the current settings and + /// log mode. You can change user interface settings with the
+ /// and functions. You can set the log mode with the + /// function. + /// + /// The
and properties should be + /// tested after calling this method. + /// + /// Win32 MSI APIs: + /// MsiConfigureProduct, + /// MsiConfigureProductEx + ///
+ /// Configures the installed state for a product feature. + /// + /// Product code of the product to be configured. + /// Specifies the feature ID for the feature to be configured. + /// Specifies the installation state for the feature. + ///There was an error configuring the feature + ///+ public static void ConfigureFeature(string productCode, string feature, InstallState installState) + { + uint ret = NativeMethods.MsiConfigureFeature(productCode, feature, (int) installState); + Installer.CheckInstallResult(ret); + } + + /// + /// The
and properties should be + /// tested after calling this method. + /// + /// Win32 MSI API: + /// MsiConfigureFeature + ///
+ /// For each product listed by the patch package as eligible to receive the patch, ApplyPatch invokes + /// an installation and sets the PATCH property to the path of the patch package. + /// + /// path to the patch package + /// optional command line property settings + ///There was an error applying the patch + ///+ public static void ApplyPatch(string patchPackage, string commandLine) + { + Installer.ApplyPatch(patchPackage, null, InstallType.Default, commandLine); + } + + /// + /// The
and properties should be + /// tested after calling this method. + /// + /// Win32 MSI API: + /// MsiApplyPatch + ///
+ /// For each product listed by the patch package as eligible to receive the patch, ApplyPatch invokes + /// an installation and sets the PATCH property to the path of the patch package. + /// + /// path to the patch package + /// path to the product to be patched, if installType + /// is set to+ /// type of installation to patch + /// optional command line property settings + /// There was an error applying the patch + ///+ public static void ApplyPatch(string patchPackage, string installPackage, InstallType installType, string commandLine) + { + uint ret = NativeMethods.MsiApplyPatch(patchPackage, installPackage, (int) installType, commandLine); + Installer.CheckInstallResult(ret); + } + + /// + /// The
and properties should be + /// tested after calling this method. + /// + /// Win32 MSI API: + /// MsiApplyPatch + ///
+ /// Removes one or more patches from a single product. To remove a patch from + /// multiple products, RemovePatches must be called for each product. + /// + /// List of patches to remove. Each patch can be specified by the GUID + /// of the patch or the full path to the patch package. + /// The ProductCode (GUID) of the product from which the patches + /// are removed. This parameter cannot be null. + /// optional command line property settings + ///There was an error removing the patches + ///+ public static void RemovePatches(IList + /// The
and properties should be + /// tested after calling this method. + /// + /// Win32 MSI API: + /// MsiRemovePatches + ///
patches, string productCode, string commandLine) + { + if (patches == null || patches.Count == 0) + { + throw new ArgumentNullException("patches"); + } + + if (productCode == null) + { + throw new ArgumentNullException("productCode"); + } + + StringBuilder patchList = new StringBuilder(); + foreach (string patch in patches) + { + if (patch != null) + { + if (patchList.Length != 0) + { + patchList.Append(';'); + } + + patchList.Append(patch); + } + } + + if (patchList.Length == 0) + { + throw new ArgumentNullException("patches"); + } + + uint ret = NativeMethods.MsiRemovePatches(patchList.ToString(), productCode, (int) InstallType.SingleInstance, commandLine); + Installer.CheckInstallResult(ret); + } + + /// + /// Determines which patches apply to a specified product MSI and in what sequence. + /// + /// Full path to an MSI file that is the target product + /// for the set of patches. + /// An array of strings specifying the patches to be checked. Each item + /// may be the path to an MSP file, the path an XML file, or just an XML blob. + /// Callback to be invoked for each inapplicable patch, reporting the + /// reason the patch is not applicable. This value may be left null if that information is not + /// desired. + ///An array of selected patch strings from + ///, indicating + /// the set of applicable patches. The items are re-ordered to be in the best sequence. + public static IList + /// If an item in
is a file path but does not end in .MSP or .XML, + /// it is assumed to be an MSP file. + /// + /// As this overload uses InstallContext.None, it does not consider the current state of + /// the system. + ///
+ /// Win32 MSI API: + /// MsiDetermineApplicablePatches + ///
DetermineApplicablePatches( + string productPackage, + string[] patches, + InapplicablePatchHandler errorHandler) + { + return DetermineApplicablePatches(productPackage, patches, errorHandler, null, UserContexts.None); + } + + /// + /// Determines which patches apply to a specified product and in what sequence. If + /// the product is installed, this method accounts for patches that have already been applied to + /// the product and accounts for obsolete and superceded patches. + /// + /// The product that is the target for the set of patches. This may be + /// either a ProductCode (GUID) of a product that is currently installed, or the path to a an + /// MSI file. + /// An array of strings specifying the patches to be checked. Each item + /// may be the path to an MSP file, the path an XML file, or just an XML blob. + /// Callback to be invoked for each inapplicable patch, reporting the + /// reason the patch is not applicable. This value may be left null if that information is not + /// desired. + /// Specifies a security identifier (SID) of a user. This parameter restricts + /// the context of enumeration for this user account. This parameter cannot be the special SID + /// strings s-1-1-0 (everyone) or s-1-5-18 (local system). Ifis set to + /// or , then + /// must be null. For the current user context, + /// can be null and can be set to + /// or . + /// Restricts the enumeration to per-user-unmanaged, per-user-managed, + /// or per-machine context, or (if referring to an MSI) to no system context at all. This + /// parameter can be , , + /// , or . + /// An array of selected patch strings from + ///, indicating + /// the set of applicable patches. The items are re-ordered to be in the best sequence. + public static IList + /// If an item in
is a file path but does not end in .MSP or .XML, + /// it is assumed to be an MSP file. + /// + /// Passing an InstallContext of None only analyzes the MSI file; it does not consider the + /// current state of the system. You cannot use InstallContext.None with a ProductCode GUID. + ///
+ /// Win32 MSI APIs: + /// MsiDetermineApplicablePatches + /// MsiDeterminePatchSequence + ///
DetermineApplicablePatches( + string product, + string[] patches, + InapplicablePatchHandler errorHandler, + string userSid, + UserContexts context) + { + if (String.IsNullOrEmpty(product)) + { + throw new ArgumentNullException("product"); + } + + if (patches == null) + { + throw new ArgumentNullException("patches"); + } + + NativeMethods.MsiPatchSequenceData[] sequenceData = new NativeMethods.MsiPatchSequenceData[patches.Length]; + for (int i = 0; i < patches.Length; i++) + { + if (String.IsNullOrEmpty(patches[i])) + { + throw new ArgumentNullException("patches[" + i + "]"); + } + + sequenceData[i].szPatchData = patches[i]; + sequenceData[i].ePatchDataType = GetPatchStringDataType(patches[i]); + sequenceData[i].dwOrder = -1; + sequenceData[i].dwStatus = 0; + } + + uint ret; + if (context == UserContexts.None) + { + ret = NativeMethods.MsiDetermineApplicablePatches(product, (uint) sequenceData.Length, sequenceData); + } + else + { + ret = NativeMethods.MsiDeterminePatchSequence(product, userSid, context, (uint) sequenceData.Length, sequenceData); + } + + if (errorHandler != null) + { + for (int i = 0; i < sequenceData.Length; i++) + { + if (sequenceData[i].dwOrder < 0 && sequenceData[i].dwStatus != 0) + { + errorHandler(sequenceData[i].szPatchData, InstallerException.ExceptionFromReturnCode(sequenceData[i].dwStatus)); + } + } + } + + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + + IList patchSeq = new List (patches.Length); + for (int i = 0; i < sequenceData.Length; i++) + { + for (int j = 0; j < sequenceData.Length; j++) + { + if (sequenceData[j].dwOrder == i) + { + patchSeq.Add(sequenceData[j].szPatchData); + } + } + } + return patchSeq; + } + + /// + /// Applies one or more patches to products that are eligible to receive the patch. + /// For each product listed by the patch package as eligible to receive the patch, ApplyPatch invokes + /// an installation and sets the PATCH property to the path of the patch package. + /// + /// The set of patch packages to be applied. + /// Each item is the full path to an MSP file. + /// Provides the ProductCode of the product being patched. If this parameter + /// is null, the patches are applied to all products that are eligible to receive these patches. + /// optional command line property settings + ///+ public static void ApplyMultiplePatches( + IList + /// Win32 MSI API: + /// MsiApplyMultiplePatches + ///
patchPackages, string productCode, string commandLine) + { + if (patchPackages == null || patchPackages.Count == 0) + { + throw new ArgumentNullException("patchPackages"); + } + + StringBuilder patchList = new StringBuilder(); + foreach (string patch in patchPackages) + { + if (patch != null) + { + if (patchList.Length != 0) + { + patchList.Append(';'); + } + + patchList.Append(patch); + } + } + + if (patchList.Length == 0) + { + throw new ArgumentNullException("patchPackages"); + } + + uint ret = NativeMethods.MsiApplyMultiplePatches(patchList.ToString(), productCode, commandLine); + Installer.CheckInstallResult(ret); + } + + /// + /// Extracts information from a patch that can be used to determine whether the patch + /// applies on a target system. The method returns an XML string that can be provided to + /// + /// Full path to the patch being queried. + ///+ /// instead of the full patch file. + /// XML string containing patch data. + ///+ public static string ExtractPatchXmlData(string patchPath) + { + StringBuilder buf = new StringBuilder(""); + uint bufSize = 0; + uint ret = NativeMethods.MsiExtractPatchXMLData(patchPath, 0, buf, ref bufSize); + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + buf.Capacity = (int) ++bufSize; + ret = NativeMethods.MsiExtractPatchXMLData(patchPath, 0, buf, ref bufSize); + } + + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + return buf.ToString(); + } + + /// + /// Win32 MSI API: + /// MsiExtractPatchXMLData + ///
+ /// [MSI 3.1] Migrates a user's application configuration data to a new SID. + /// + /// Previous user SID that data is to be migrated from + /// New user SID that data is to be migrated to + ///+ public static void NotifySidChange(string oldSid, string newSid) + { + uint ret = NativeMethods.MsiNotifySidChange(oldSid, newSid); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + private static void CheckInstallResult(uint ret) + { + switch (ret) + { + case (uint) NativeMethods.Error.SUCCESS: break; + case (uint) NativeMethods.Error.SUCCESS_REBOOT_REQUIRED: Installer.rebootRequired = true; break; + case (uint) NativeMethods.Error.SUCCESS_REBOOT_INITIATED: Installer.rebootInitiated = true; break; + default: throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + private static int GetPatchStringDataType(string patchData) + { + if (patchData.IndexOf("<", StringComparison.Ordinal) >= 0 && + patchData.IndexOf(">", StringComparison.Ordinal) >= 0) + { + return 2; // XML blob + } + else if (String.Compare(Path.GetExtension(patchData), ".xml", + StringComparison.OrdinalIgnoreCase) == 0) + { + return 1; // XML file path + } + else + { + return 0; // MSP file path + } + } +} +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/InstallerAdvertise.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/InstallerAdvertise.cs new file mode 100644 index 00000000..9da593d9 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/InstallerAdvertise.cs @@ -0,0 +1,270 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.IO; + using System.Text; + using System.Reflection; + using System.Globalization; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + + public static partial class Installer + { + /// + /// Win32 MSI API: + /// MsiNotifySidChange + ///
+ /// Advertises a product to the local computer. + /// + /// Path to the package of the product being advertised + /// True if the product is user-assigned; false if it is machine-assigned. + /// Semi-colon delimited list of transforms to be applied. This parameter may be null. + /// The language to use if the source supports multiple languages + ///the specified package file does not exist + ///+ /// + public static void AdvertiseProduct(string packagePath, bool perUser, string transforms, int locale) + { + if (String.IsNullOrEmpty(packagePath)) + { + throw new ArgumentNullException("packagePath"); + } + + if (!File.Exists(packagePath)) + { + throw new FileNotFoundException(null, packagePath); + } + + uint ret = NativeMethods.MsiAdvertiseProduct(packagePath, new IntPtr(perUser ? 1 : 0), transforms, (ushort) locale); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// Win32 MSI APIs: + /// MsiAdvertiseProduct, + /// MsiAdvertiseProductEx + ///
+ /// Generates an advertise script. The method enables the installer to write to a + /// script the registry and shortcut information used to assign or publish a product. + /// + /// Path to the package of the product being advertised + /// path to script file to be created with the advertise information + /// Semi-colon delimited list of transforms to be applied. This parameter may be null. + /// The language to use if the source supports multiple languages + ///the specified package file does not exist + ///+ /// + public static void GenerateAdvertiseScript(string packagePath, string scriptFilePath, string transforms, int locale) + { + if (String.IsNullOrEmpty(packagePath)) + { + throw new ArgumentNullException("packagePath"); + } + + if (!File.Exists(packagePath)) + { + throw new FileNotFoundException(null, packagePath); + } + + uint ret = NativeMethods.MsiAdvertiseProduct(packagePath, scriptFilePath, transforms, (ushort) locale); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// Win32 MSI APIs: + /// MsiAdvertiseProduct, + /// MsiAdvertiseProductEx + ///
+ /// Generates an advertise script. The method enables the installer to write to a + /// script the registry and shortcut information used to assign or publish a product. + /// + /// Path to the package of the product being advertised + /// path to script file to be created with the advertise information + /// Semi-colon delimited list of transforms to be applied. This parameter may be null. + /// The language to use if the source supports multiple languages + /// Targeted processor architecture. + /// True to install multiple instances through product code changing transform. + /// Advertises a new instance of the product. Requires that theparameter + /// includes the instance transform that changes the product code. + /// + /// + public static void GenerateAdvertiseScript( + string packagePath, + string scriptFilePath, + string transforms, + int locale, + ProcessorArchitecture processor, + bool instance) + { + if (String.IsNullOrEmpty(packagePath)) + { + throw new ArgumentNullException("packagePath"); + } + + if (String.IsNullOrEmpty(scriptFilePath)) + { + throw new ArgumentNullException("scriptFilePath"); + } + + if (!File.Exists(packagePath)) + { + throw new FileNotFoundException(null, packagePath); + } + + uint platform = 0; + switch (processor) + { + case ProcessorArchitecture.X86: platform = (uint) 1; break; + case ProcessorArchitecture.IA64: platform = (uint) 2; break; + case ProcessorArchitecture.Amd64: platform = (uint) 4; break; + } + + uint ret = NativeMethods.MsiAdvertiseProductEx( + packagePath, + scriptFilePath, + transforms, + (ushort) locale, + platform, + instance ? (uint) 1 : 0); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// Win32 MSI APIs: + /// MsiAdvertiseProduct, + /// MsiAdvertiseProductEx + ///
+ /// Copies an advertise script file to the local computer. + /// + /// Path to a script file generated by + ///+ /// Flags controlling advertisement + /// True if specified items are to be removed instead of being created + /// + [SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "flags")] + public static void AdvertiseScript(string scriptFile, int flags, bool removeItems) + { + uint ret = NativeMethods.MsiAdvertiseScript(scriptFile, (uint) flags, IntPtr.Zero, removeItems); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// The process calling this function must be running under the LocalSystem account. To advertise an + /// application for per-user installation to a targeted user, the thread that calls this function must + /// impersonate the targeted user. If the thread calling this function is not impersonating a targeted + /// user, the application is advertised to all users for installation with elevated privileges. + ///
+ /// Processes an advertise script file into the specified locations. + /// + /// Path to a script file generated by + ///+ /// An optional path to a folder in which advertised icon files and transform + /// files are located. If this parameter is null, no icon or transform files are written. + /// True if shortcuts should be created + /// True if specified items are to be removed instead of created + /// + public static void ProcessAdvertiseScript(string scriptFile, string iconFolder, bool shortcuts, bool removeItems) + { + uint ret = NativeMethods.MsiProcessAdvertiseScript(scriptFile, iconFolder, IntPtr.Zero, shortcuts, removeItems); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// The process calling this function must be running under the LocalSystem account. To advertise an + /// application for per-user installation to a targeted user, the thread that calls this function must + /// impersonate the targeted user. If the thread calling this function is not impersonating a targeted + /// user, the application is advertised to all users for installation with elevated privileges. + ///
+ /// Win32 MSI API: + /// MsiProcessAdvertiseScript + ///
+ /// Gets product information for an installer script file. + /// + /// Path to a script file generated by + ///+ /// ProductInstallation stub with advertise-related properties filled in. + ///An invalid product property was requested + ///+ /// Only the following properties will be filled in in the returned object:
+ ///
Other properties will be null. + ///- + ///
- + ///
- + ///
- + ///
- + ///
+ /// Win32 MSI API: + /// MsiGetProductInfoFromScript + ///
+ public static ProductInstallation GetProductInfoFromScript(string scriptFile) + { + if (String.IsNullOrEmpty(scriptFile)) + { + throw new ArgumentNullException("scriptFile"); + } + StringBuilder productCodeBuf = new StringBuilder(40); + ushort lang; + uint ver; + StringBuilder productNameBuf = new StringBuilder(100); + StringBuilder packageNameBuf = new StringBuilder(40); + uint productCodeBufSize = (uint) productCodeBuf.Capacity; + uint productNameBufSize = (uint) productNameBuf.Capacity; + uint packageNameBufSize = (uint) packageNameBuf.Capacity; + uint ret = NativeMethods.MsiGetProductInfoFromScript( + scriptFile, + productCodeBuf, + out lang, + out ver, + productNameBuf, + ref productNameBufSize, + packageNameBuf, + ref packageNameBufSize); + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + productCodeBuf.Capacity = (int) ++productCodeBufSize; + productNameBuf.Capacity = (int) ++productNameBufSize; + packageNameBuf.Capacity = (int) ++packageNameBufSize; + ret = NativeMethods.MsiGetProductInfoFromScript( + scriptFile, + productCodeBuf, + out lang, + out ver, + productNameBuf, + ref productNameBufSize, + packageNameBuf, + ref packageNameBufSize); + } + + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + uint verPart1 = ver >> 24; + uint verPart2 = (ver & 0x00FFFFFF) >> 16; + uint verPart3 = ver & 0x0000FFFF; + Version version = new Version((int) verPart1, (int) verPart2, (int) verPart3); + + IDictionaryprops = new Dictionary (); + props["ProductCode"] = productCodeBuf.ToString(); + props["Language"] = lang.ToString(CultureInfo.InvariantCulture); + props["Version"] = version.ToString(); + props["ProductName"] = productNameBuf.ToString(); + props["PackageName"] = packageNameBuf.ToString(); + return new ProductInstallation(props); + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/InstallerUtils.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/InstallerUtils.cs new file mode 100644 index 00000000..8d9cf0a1 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/InstallerUtils.cs @@ -0,0 +1,472 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.IO; + using System.Text; + using System.Resources; + using System.Reflection; + using System.Collections.Generic; + using System.Globalization; + using System.Runtime.InteropServices; + using System.Diagnostics.CodeAnalysis; + + public static partial class Installer + { + /// + /// Gets the current version of the installer. + /// + public static Version Version + { + get + { + // TODO: Use the extended form of version info to get the 4th component of the verison. + uint[] dllVersionInfo = new uint[5]; + dllVersionInfo[0] = 20; + int hr = NativeMethods.DllGetVersion(dllVersionInfo); + if (hr != 0) + { + Marshal.ThrowExceptionForHR(hr); + } + + return new Version((int) dllVersionInfo[1], (int) dllVersionInfo[2], (int) dllVersionInfo[3]); + } + } + + internal static ResourceManager ErrorResources + { + get + { + if (errorResources == null) + { + errorResources = new ResourceManager(typeof(Installer).Namespace + ".Errors", typeof(Installer).Assembly); + } + return errorResources; + } + } + + ///+ /// Gets a Windows Installer error message in the system default language. + /// + /// The error number. + ///The message string, or null if the error message is not found. + ///+ public static string GetErrorMessage(int errorNumber) + { + return Installer.GetErrorMessage(errorNumber, null); + } + + /// + /// The returned string may have tokens such as [2] and [3] that are meant to be substituted + /// with context-specific values. + ///
+ /// Error numbers greater than 2000 refer to MSI "internal" errors, and are always + /// returned in English. + ///
+ /// Gets a Windows Installer error message in a specified language. + /// + /// The error number. + /// The locale for the message. + ///The message string, or null if the error message or locale is not found. + ///+ [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static string GetErrorMessage(int errorNumber, CultureInfo culture) + { + if (culture == null) + { + culture = CultureInfo.CurrentCulture; + } + + string msg = Installer.ErrorResources.GetString( + errorNumber.ToString(CultureInfo.InvariantCulture.NumberFormat), + culture); + if (msg == null) + { + string msiMsgModule = Path.Combine( + Environment.SystemDirectory, "msimsg.dll"); + msg = Installer.GetMessageFromModule( + msiMsgModule, errorNumber, culture); + } + return msg; + } + + private static string GetMessageFromModule( + string modulePath, int errorNumber, CultureInfo culture) + { + const uint LOAD_LIBRARY_AS_DATAFILE = 2; + const int RT_RCDATA = 10; + + IntPtr msgModule = NativeMethods.LoadLibraryEx( + modulePath, IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE); + if (msgModule == IntPtr.Zero) + { + return null; + } + + try + { + // On pre-Vista systems, the messages are stored as RCDATA resources. + + int lcid = (culture == CultureInfo.InvariantCulture) ? + 0 : culture.LCID; + IntPtr resourceInfo = NativeMethods.FindResourceEx( + msgModule, + new IntPtr(RT_RCDATA), + new IntPtr(errorNumber), + (ushort) lcid); + if (resourceInfo != IntPtr.Zero) + { + IntPtr resourceData = NativeMethods.LoadResource( + msgModule, resourceInfo); + IntPtr resourcePtr = NativeMethods.LockResource(resourceData); + + if (lcid == 0) + { + string msg = Marshal.PtrToStringAnsi(resourcePtr); + return msg; + } + else + { + int len = 0; + while (Marshal.ReadByte(resourcePtr, len) != 0) + { + len++; + } + byte[] msgBytes = new byte[len + 1]; + Marshal.Copy(resourcePtr, msgBytes, 0, msgBytes.Length); + Encoding encoding = Encoding.GetEncoding( + culture.TextInfo.ANSICodePage); + string msg = encoding.GetString(msgBytes); + return msg; + } + } + else + { + // On Vista (and above?), the messages are stored in the module message table. + // They're actually in MUI files, and the redirection happens automatically here. + + const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; + const uint FORMAT_MESSAGE_FROM_HMODULE = 0x00000800; + const uint MESSAGE_OFFSET = 20000; // Not documented, but observed on Vista + + StringBuilder buf = new StringBuilder(1024); + uint formatCount = NativeMethods.FormatMessage( + FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, + msgModule, + (uint) errorNumber + MESSAGE_OFFSET, + (ushort) lcid, + buf, + (uint) buf.Capacity, + IntPtr.Zero); + + return formatCount != 0 ? buf.ToString().Trim() : null; + } + } + finally + { + NativeMethods.FreeLibrary(msgModule); + } + } + + /// + /// The returned string may have tokens such as [2] and [3] that are meant to be substituted + /// with context-specific values. + ///
+ /// Error numbers greater than 2000 refer to MSI "internal" errors, and are always + /// returned in English. + ///
+ /// Gets a formatted Windows Installer error message in the system default language. + /// + /// Error record containing the error number in the first field, and + /// error-specific parameters in the other fields. + ///The message string, or null if the error message is not found. + ///+ public static string GetErrorMessage(Record errorRecord) { return Installer.GetErrorMessage(errorRecord, null); } + + /// + /// Error numbers greater than 2000 refer to MSI "internal" errors, and are always + /// returned in English. + ///
+ /// Gets a formatted Windows Installer error message in a specified language. + /// + /// Error record containing the error number in the first field, and + /// error-specific parameters in the other fields. + /// The locale for the message. + ///The message string, or null if the error message or locale is not found. + ///+ public static string GetErrorMessage(Record errorRecord, CultureInfo culture) + { + if (errorRecord == null) + { + throw new ArgumentNullException("errorRecord"); + } + int errorNumber; + if (errorRecord.FieldCount < 1 || (errorNumber = (int) errorRecord.GetInteger(1)) == 0) + { + throw new ArgumentOutOfRangeException("errorRecord"); + } + + string msg = Installer.GetErrorMessage(errorNumber, culture); + if (msg != null) + { + errorRecord.FormatString = msg; + msg = errorRecord.ToString((IFormatProvider)null); + } + return msg; + } + + /// + /// Error numbers greater than 2000 refer to MSI "internal" errors, and are always + /// returned in English. + ///
+ /// Gets the version string of the path specified using the format that the installer + /// expects to find it in in the database. + /// + /// Path to the file + ///Version string in the "#.#.#.#" format, or an empty string if the file + /// does not contain version information + ///the file does not exist or could not be read + ///+ public static string GetFileVersion(string path) + { + StringBuilder version = new StringBuilder(20); + uint verBufSize = 0, langBufSize = 0; + uint ret = NativeMethods.MsiGetFileVersion(path, version, ref verBufSize, null, ref langBufSize); + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + version.Capacity = (int) ++verBufSize; + ret = NativeMethods.MsiGetFileVersion(path, version, ref verBufSize, null, ref langBufSize); + } + + if (ret != 0 && ret != (uint) NativeMethods.Error.FILE_INVALID) + { + if (ret == (uint) NativeMethods.Error.FILE_NOT_FOUND || + ret == (uint) NativeMethods.Error.ACCESS_DENIED) + { + throw new FileNotFoundException(null, path); + } + else + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + return version.ToString(); + } + + /// + /// Win32 MSI API: + /// MsiGetFileVersion + ///
+ /// Gets the language string of the path specified using the format that the installer + /// expects to find them in in the database. + /// + /// Path to the file + ///Language string in the form of a decimal language ID, or an empty string if the file + /// does not contain a language ID + ///the file does not exist or could not be read + ///+ public static string GetFileLanguage(string path) + { + StringBuilder language = new StringBuilder("", 10); + uint verBufSize = 0, langBufSize = 0; + uint ret = NativeMethods.MsiGetFileVersion(path, null, ref verBufSize, language, ref langBufSize); + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + language.Capacity = (int) ++langBufSize; + ret = NativeMethods.MsiGetFileVersion(path, null, ref verBufSize, language, ref langBufSize); + } + + if (ret != 0 && ret != (uint) NativeMethods.Error.FILE_INVALID) + { + if (ret == (uint) NativeMethods.Error.FILE_NOT_FOUND || + ret == (uint) NativeMethods.Error.ACCESS_DENIED) + { + throw new FileNotFoundException(null, path); + } + else + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + return language.ToString(); + } + + /// + /// Win32 MSI API: + /// MsiGetFileVersion + ///
+ /// Gets a 128-bit hash of the specified file. + /// + /// Path to the file + /// Integer array of length 4 which receives the + /// four 32-bit parts of the hash value. + ///the file does not exist or + /// could not be read + ///+ public static void GetFileHash(string path, int[] hash) + { + if (hash == null) + { + throw new ArgumentNullException("hash"); + } + + uint[] tempHash = new uint[5]; + tempHash[0] = 20; + uint ret = NativeMethods.MsiGetFileHash(path, 0, tempHash); + if (ret != 0) + { + if (ret == (uint) NativeMethods.Error.FILE_NOT_FOUND || + ret == (uint) NativeMethods.Error.ACCESS_DENIED) + { + throw new FileNotFoundException(null, path); + } + else + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + for (int i = 0; i < 4; i++) + { + hash[i] = unchecked ((int) tempHash[i + 1]); + } + } + + /// + /// Win32 MSI API: + /// MsiGetFileHash + ///
+ /// Examines a shortcut and returns its product, feature name, and component if available. + /// + /// Full path to a shortcut + ///ShortcutTarget structure containing target product code, feature, and component code + ///+ public static ShortcutTarget GetShortcutTarget(string shortcut) + { + StringBuilder productBuf = new StringBuilder(40); + StringBuilder featureBuf = new StringBuilder(40); + StringBuilder componentBuf = new StringBuilder(40); + + uint ret = NativeMethods.MsiGetShortcutTarget(shortcut, productBuf, featureBuf, componentBuf); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + return new ShortcutTarget( + productBuf.Length > 0 ? productBuf.ToString() : null, + featureBuf.Length > 0 ? featureBuf.ToString() : null, + componentBuf.Length > 0 ? componentBuf.ToString() : null); + } + + /// + /// Win32 MSI API: + /// MsiGetShortcutTarget + ///
+ /// Verifies that the given file is an installation package. + /// + /// Path to the package + ///True if the file is an installation package; false otherwise. + ///the specified package file does not exist + ///the package file could not be opened + ///+ public static bool VerifyPackage(string packagePath) + { + if (String.IsNullOrEmpty(packagePath)) + { + throw new ArgumentNullException("packagePath"); + } + + if (!File.Exists(packagePath)) + { + throw new FileNotFoundException(null, packagePath); + } + + uint ret = NativeMethods.MsiVerifyPackage(packagePath); + if (ret == (uint) NativeMethods.Error.INSTALL_PACKAGE_INVALID) + { + return false; + } + else if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + return true; + } + + /// + /// Win32 MSI API: + /// MsiVerifyPackage + ///
+ /// [MSI 4.0] Gets the list of files that can be updated by one or more patches. + /// + /// ProductCode (GUID) of the product which is + /// the target of the patches + /// list of file paths of one or more patches to be + /// analyzed + ///List of absolute paths of files that can be updated when the + /// patches are applied on this system. + ///+ public static IList + /// Win32 MSI API: + /// MsiGetPatchFileList + ///
GetPatchFileList(string productCode, IList patches) + { + if (String.IsNullOrEmpty(productCode)) + { + throw new ArgumentNullException("productCode"); + } + + if (patches == null || patches.Count == 0) + { + throw new ArgumentNullException("patches"); + } + + StringBuilder patchList = new StringBuilder(); + foreach (string patch in patches) + { + if (patch != null) + { + if (patchList.Length != 0) + { + patchList.Append(';'); + } + + patchList.Append(patch); + } + } + + if (patchList.Length == 0) + { + throw new ArgumentNullException("patches"); + } + + IntPtr phFileRecords; + uint cFiles; + + uint ret = NativeMethods.MsiGetPatchFileList( + productCode, + patchList.ToString(), + out cFiles, + out phFileRecords); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + + List files = new List (); + + for (uint i = 0; i < cFiles; i++) + { + int hFileRec = Marshal.ReadInt32(phFileRecords, (int) i); + + using (Record fileRec = new Record(hFileRec, true, null)) + { + files.Add(fileRec.GetString(1)); + } + } + + return files; + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/MediaDisk.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/MediaDisk.cs new file mode 100644 index 00000000..7b196b3e --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/MediaDisk.cs @@ -0,0 +1,58 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.Diagnostics.CodeAnalysis; + + /// + /// Represents a media disk source of a product or a patch. + /// + [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] + public struct MediaDisk + { + private int diskId; + private string volumeLabel; + private string diskPrompt; + + ///+ /// Creates a new media disk. + /// + /// + /// + /// + public MediaDisk(int diskId, string volumeLabel, string diskPrompt) + { + this.diskId = diskId; + this.volumeLabel = volumeLabel; + this.diskPrompt = diskPrompt; + } + + ///+ /// Gets or sets the disk id of the media disk. + /// + public int DiskId + { + get { return this.diskId; } + set { this.diskId = value; } + } + + ///+ /// Gets or sets the volume label of the media disk. + /// + public string VolumeLabel + { + get { return this.volumeLabel; } + set { this.volumeLabel = value; } + } + + ///+ /// Gets or sets the disk prompt of the media disk. + /// + public string DiskPrompt + { + get { return this.diskPrompt; } + set { this.diskPrompt = value; } + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/NativeMethods.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/NativeMethods.cs new file mode 100644 index 00000000..6c5b84fd --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/NativeMethods.cs @@ -0,0 +1,311 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ +using System; +using System.Text; +using System.Security.Permissions; +using System.Runtime.InteropServices; +using System.Diagnostics.CodeAnalysis; + +using IStream = System.Runtime.InteropServices.ComTypes.IStream; +using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; +using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG; + +[Guid("0000000b-0000-0000-C000-000000000046")] +[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] +internal interface IStorage +{ + [return: MarshalAs(UnmanagedType.Interface)] + IStream CreateStream([MarshalAs(UnmanagedType.LPWStr)] string wcsName, uint grfMode, uint reserved1, uint reserved2); + [return: MarshalAs(UnmanagedType.Interface)] + IStream OpenStream([MarshalAs(UnmanagedType.LPWStr)] string wcsName, IntPtr reserved1, uint grfMode, uint reserved2); + [return: MarshalAs(UnmanagedType.Interface)] + IStorage CreateStorage([MarshalAs(UnmanagedType.LPWStr)] string wcsName, uint grfMode, uint reserved1, uint reserved2); + [return: MarshalAs(UnmanagedType.Interface)] + IStorage OpenStorage([MarshalAs(UnmanagedType.LPWStr)] string wcsName, IntPtr stgPriority, uint grfMode, IntPtr snbExclude, uint reserved); + void CopyTo(uint ciidExclude, IntPtr rgiidExclude, IntPtr snbExclude, [MarshalAs(UnmanagedType.Interface)] IStorage stgDest); + void MoveElementTo([MarshalAs(UnmanagedType.LPWStr)] string wcsName, [MarshalAs(UnmanagedType.Interface)] IStorage stgDest, [MarshalAs(UnmanagedType.LPWStr)] string wcsNewName, uint grfFlags); + void Commit(uint grfCommitFlags); + void Revert(); + IntPtr EnumElements(uint reserved1, IntPtr reserved2, uint reserved3); + void DestroyElement([MarshalAs(UnmanagedType.LPWStr)] string wcsName); + void RenameElement([MarshalAs(UnmanagedType.LPWStr)] string wcsOldName, [MarshalAs(UnmanagedType.LPWStr)] string wcsNewName); + void SetElementTimes([MarshalAs(UnmanagedType.LPWStr)] string wcsName, ref FILETIME ctime, ref FILETIME atime, ref FILETIME mtime); + void SetClass(ref Guid clsid); + void SetStateBits(uint grfStateBits, uint grfMask); + void Stat(ref STATSTG statstg, uint grfStatFlag); +} + +internal static class NativeMethods +{ + internal enum Error : uint + { + SUCCESS = 0, + FILE_NOT_FOUND = 2, + PATH_NOT_FOUND = 3, + ACCESS_DENIED = 5, + INVALID_HANDLE = 6, + INVALID_DATA = 13, + INVALID_PARAMETER = 87, + OPEN_FAILED = 110, + DISK_FULL = 112, + CALL_NOT_IMPLEMENTED = 120, + BAD_PATHNAME = 161, + NO_DATA = 232, + MORE_DATA = 234, + NO_MORE_ITEMS = 259, + DIRECTORY = 267, + INSTALL_USEREXIT = 1602, + INSTALL_FAILURE = 1603, + FILE_INVALID = 1006, + UNKNOWN_PRODUCT = 1605, + UNKNOWN_FEATURE = 1606, + UNKNOWN_COMPONENT = 1607, + UNKNOWN_PROPERTY = 1608, + INVALID_HANDLE_STATE = 1609, + INSTALL_SOURCE_ABSENT = 1612, + BAD_QUERY_SYNTAX = 1615, + INSTALL_PACKAGE_INVALID = 1620, + FUNCTION_FAILED = 1627, + INVALID_TABLE = 1628, + DATATYPE_MISMATCH = 1629, + CREATE_FAILED = 1631, + SUCCESS_REBOOT_INITIATED = 1641, + SUCCESS_REBOOT_REQUIRED = 3010, + } + + internal enum SourceType : int + { + Unknown = 0, + Network = 1, + Url = 2, + Media = 3, + } + + [Flags] + internal enum STGM : uint + { + DIRECT = 0x00000000, + TRANSACTED = 0x00010000, + SIMPLE = 0x08000000, + + READ = 0x00000000, + WRITE = 0x00000001, + READWRITE = 0x00000002, + + SHARE_DENY_NONE = 0x00000040, + SHARE_DENY_READ = 0x00000030, + SHARE_DENY_WRITE = 0x00000020, + SHARE_EXCLUSIVE = 0x00000010, + + PRIORITY = 0x00040000, + DELETEONRELEASE = 0x04000000, + NOSCRATCH = 0x00100000, + + CREATE = 0x00001000, + CONVERT = 0x00020000, + FAILIFTHERE = 0x00000000, + + NOSNAPSHOT = 0x00200000, + DIRECT_SWMR = 0x00400000, + } + +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern int DllGetVersion(uint[] dvi); + +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSetInternalUI(uint dwUILevel, ref IntPtr phWnd); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSetInternalUI(uint dwUILevel, IntPtr phWnd); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern NativeExternalUIHandler MsiSetExternalUI([MarshalAs(UnmanagedType.FunctionPtr)] NativeExternalUIHandler puiHandler, uint dwMessageFilter, IntPtr pvContext); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiEnableLog(uint dwLogMode, string szLogFile, uint dwLogAttributes); +//[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiEnumProducts(uint iProductIndex, StringBuilder lpProductBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetProductInfo(string szProduct, string szProperty, StringBuilder lpValueBuf, ref uint pcchValueBuf); +//[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiEnumPatches(string szProduct, uint iPatchIndex, StringBuilder lpPatchBuf, StringBuilder lpTransformsBuf, ref uint pcchTransformsBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetPatchInfo(string szPatch, string szAttribute, StringBuilder lpValueBuf, ref uint pcchValueBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiEnumFeatures(string szProduct, uint iFeatureIndex, StringBuilder lpFeatureBuf, StringBuilder lpParentBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern int MsiQueryFeatureState(string szProduct, string szFeature); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern int MsiUseFeatureEx(string szProduct, string szFeature, uint dwInstallMode, uint dwReserved); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern int MsiQueryProductState(string szProduct); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetShortcutTarget(string szShortcut, StringBuilder szProductCode, StringBuilder szFeatureId, StringBuilder szComponentCode); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiProvideComponent(string szProduct, string szFeature, string szComponent, uint dwInstallMode, StringBuilder lpPathBuf, ref uint cchPathBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiProvideQualifiedComponentEx(string szComponent, string szQualifier, uint dwInstallMode, string szProduct, uint dwUnused1, uint dwUnused2, StringBuilder lpPathBuf, ref uint cchPathBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiReinstallFeature(string szFeature, string szProduct, uint dwReinstallMode); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiReinstallProduct(string szProduct, uint dwReinstallMode); +//[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSourceListAddSource(string szProduct, string szUserName, uint dwReserved, string szSource); +//[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSourceListClearAll(string szProduct, string szUserName, uint dwReserved); +//[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSourceListForceResolution(string szProduct, string szUserName, uint dwReserved); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiCollectUserInfo(string szProduct); +//[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern int MsiGetUserInfo(string szProduct, StringBuilder lpUserNameBuf, ref uint cchUserNameBuf, StringBuilder lpOrgNameBuf, ref uint cchOrgNameBuf, StringBuilder lpSerialBuf, ref uint cchSerialBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiOpenPackageEx(string szPackagePath, uint dwOptions, out int hProduct); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiOpenProduct(string szProduct, out int hProduct); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiInstallProduct(string szPackagePath, string szCommandLine); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiConfigureProductEx(string szProduct, int iInstallLevel, int eInstallState, string szCommandLine); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiConfigureFeature(string szProduct, string szFeature, int eInstallState); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiApplyPatch(string szPatchPackage, string szInstallPackage, int eInstallType, string szCommandLine); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiOpenDatabase(string szDatabasePath, IntPtr uiOpenMode, out int hDatabase); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiOpenDatabase(string szDatabasePath, string szPersist, out int hDatabase); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern int MsiGetDatabaseState(int hDatabase); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiDatabaseOpenView(int hDatabase, string szQuery, out int hView); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiDatabaseMerge(int hDatabase, int hDatabaseMerge, string szTableName); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiDatabaseCommit(int hDatabase); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiDatabaseGetPrimaryKeys(int hDatabase, string szTableName, out int hRecord); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiDatabaseIsTablePersistent(int hDatabase, string szTableName); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiDatabaseExport(int hDatabase, string szTableName, string szFolderPath, string szFileName); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiDatabaseImport(int hDatabase, string szFolderPath, string szFileName); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiDatabaseGenerateTransform(int hDatabase, int hDatabaseReference, string szTransformFile, int iReserved1, int iReserved2); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiCreateTransformSummaryInfo(int hDatabase, int hDatabaseReference, string szTransformFile, int iErrorConditions, int iValidation); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiDatabaseApplyTransform(int hDatabase, string szTransformFile, int iErrorConditions); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiViewExecute(int hView, int hRecord); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiViewFetch(int hView, out int hRecord); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiViewModify(int hView, int iModifyMode, int hRecord); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern int MsiViewGetError(int hView, StringBuilder szColumnNameBuffer, ref uint cchBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiViewGetColumnInfo(int hView, uint eColumnInfo, out int hRecord); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern int MsiCreateRecord(uint cParams); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiFormatRecord(int hInstall, int hRecord, StringBuilder szResultBuf, ref uint cchResultBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiRecordClearData(int hRecord); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiRecordGetFieldCount(int hRecord); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool MsiRecordIsNull(int hRecord, uint iField); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern int MsiRecordGetInteger(int hRecord, uint iField); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiRecordGetString(int hRecord, uint iField, StringBuilder szValueBuf, ref uint cchValueBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiRecordSetInteger(int hRecord, uint iField, int iValue); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiRecordSetString(int hRecord, uint iField, string szValue); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiRecordDataSize(int hRecord, uint iField); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiRecordReadStream(int hRecord, uint iField, byte[] szDataBuf, ref uint cbDataBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiRecordSetStream(int hRecord, uint iField, string szFilePath); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetSummaryInformation(int hDatabase, string szDatabasePath, uint uiUpdateCount, out int hSummaryInfo); +//[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSummaryInfoGetPropertyCount(int hSummaryInfo, out uint uiPropertyCount); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSummaryInfoGetProperty(int hSummaryInfo, uint uiProperty, out uint uiDataType, out int iValue, ref long ftValue, StringBuilder szValueBuf, ref uint cchValueBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSummaryInfoSetProperty(int hSummaryInfo, uint uiProperty, uint uiDataType, int iValue, ref long ftValue, string szValue); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSummaryInfoPersist(int hSummaryInfo); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiCloseHandle(int hAny); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetFileVersion(string szFilePath, StringBuilder szVersionBuf, ref uint cchVersionBuf, StringBuilder szLangBuf, ref uint cchLangBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetFileHash(string szFilePath, uint dwOptions, uint[] hash); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern int MsiGetActiveDatabase(int hInstall); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetProperty(int hInstall, string szName, StringBuilder szValueBuf, ref uint cchValueBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSetProperty(int hInstall, string szName, string szValue); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern int MsiProcessMessage(int hInstall, uint eMessageType, int hRecord); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiEvaluateCondition(int hInstall, string szCondition); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool MsiGetMode(int hInstall, uint iRunMode); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSetMode(int hInstall, uint iRunMode, [MarshalAs(UnmanagedType.Bool)] bool fState); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiDoAction(int hInstall, string szAction); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSequence(int hInstall, string szTable, int iSequenceMode); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetSourcePath(int hInstall, string szFolder, StringBuilder szPathBuf, ref uint cchPathBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetTargetPath(int hInstall, string szFolder, StringBuilder szPathBuf, ref uint cchPathBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSetTargetPath(int hInstall, string szFolder, string szFolderPath); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetComponentState(int hInstall, string szComponent, out int iInstalled, out int iAction); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSetComponentState(int hInstall, string szComponent, int iState); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetFeatureState(int hInstall, string szFeature, out int iInstalled, out int iAction); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSetFeatureState(int hInstall, string szFeature, int iState); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetFeatureValidStates(int hInstall, string szFeature, out uint dwInstallState); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSetInstallLevel(int hInstall, int iInstallLevel); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern ushort MsiGetLanguage(int hInstall); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiEnumComponents(uint iComponentIndex, StringBuilder lpComponentBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiEnumComponentsEx(string szUserSid, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, uint dwIndex, StringBuilder szInstalledProductCode, [MarshalAs(UnmanagedType.I4)] out UserContexts pdwInstalledContext, StringBuilder szSid, ref uint pcchSid); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiEnumClients(string szComponent, uint iProductIndex, StringBuilder lpProductBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiEnumClientsEx(string szComponent, string szUserSid, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, uint iProductIndex, StringBuilder lpProductBuf, [MarshalAs(UnmanagedType.I4)] out UserContexts pdwInstalledContext, StringBuilder szSid, ref uint pcchSid); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern int MsiGetComponentPath(string szProduct, string szComponent, StringBuilder lpPathBuf, ref uint pcchBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern int MsiGetComponentPathEx(string szProduct, string szComponent, string szUserSid, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, StringBuilder lpPathBuf, ref uint pcchBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiEnumComponentQualifiers(string szComponent, uint iIndex, StringBuilder lpQualifierBuf, ref uint pcchQualifierBuf, StringBuilder lpApplicationDataBuf, ref uint pcchApplicationDataBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern int MsiGetLastErrorRecord(); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiEnumRelatedProducts(string upgradeCode, uint dwReserved, uint iProductIndex, StringBuilder lpProductBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetProductCode(string szComponent, StringBuilder lpProductBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetFeatureUsage(string szProduct, string szFeature, out uint dwUseCount, out ushort dwDateUsed); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetFeatureCost(int hInstall, string szFeature, int iCostTree, int iState, out int iCost); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiVerifyPackage(string szPackagePath); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiIsProductElevated(string szProductCode, [MarshalAs(UnmanagedType.Bool)] out bool fElevated); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiAdvertiseProduct(string szPackagePath, IntPtr szScriptFilePath, string szTransforms, ushort lgidLanguage); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiAdvertiseProduct(string szPackagePath, string szScriptFilePath, string szTransforms, ushort lgidLanguage); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiAdvertiseProductEx(string szPackagePath, string szScriptFilePath, string szTransforms, ushort lgidLanguage, uint dwPlatform, uint dwReserved); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiAdvertiseScript(string szScriptFile, uint dwFlags, IntPtr phRegData, [MarshalAs(UnmanagedType.Bool)] bool fRemoveItems); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiProcessAdvertiseScript(string szScriptFile, string szIconFolder, IntPtr hRegData, [MarshalAs(UnmanagedType.Bool)] bool fShortcuts, [MarshalAs(UnmanagedType.Bool)] bool fRemoveItems); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetProductInfoFromScript(string szScriptFile, StringBuilder lpProductBuf39, out ushort plgidLanguage, out uint pdwVersion, StringBuilder lpNameBuf, ref uint cchNameBuf, StringBuilder lpPackageBuf, ref uint cchPackageBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiProvideAssembly(string szAssemblyName, string szAppContext, uint dwInstallMode, uint dwAssemblyInfo, StringBuilder lpPathBuf, ref uint cchPathBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiInstallMissingComponent(string szProduct, string szComponent, int eInstallState); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiInstallMissingFile(string szProduct, string szFile); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern int MsiLocateComponent(string szComponent, StringBuilder lpPathBuf, ref uint cchBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetProductProperty(int hProduct, string szProperty, StringBuilder lpValueBuf, ref uint cchValueBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetFeatureInfo(int hProduct, string szFeature, out uint lpAttributes, StringBuilder lpTitleBuf, ref uint cchTitleBuf, StringBuilder lpHelpBuf, ref uint cchHelpBuf); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiVerifyDiskSpace(int hInstall); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiEnumComponentCosts(int hInstall, string szComponent, uint dwIndex, int iState, StringBuilder lpDriveBuf, ref uint cchDriveBuf, out int iCost, out int iTempCost); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSetFeatureAttributes(int hInstall, string szFeature, uint dwAttributes); + +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiRemovePatches(string szPatchList, string szProductCode, int eUninstallType, string szPropertyList); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiDetermineApplicablePatches(string szProductPackagePath, uint cPatchInfo, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1), In, Out] MsiPatchSequenceData[] pPatchInfo); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiDeterminePatchSequence(string szProductCode, string szUserSid, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, uint cPatchInfo, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=3), In, Out] MsiPatchSequenceData[] pPatchInfo); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiApplyMultiplePatches(string szPatchPackages, string szProductCode, string szPropertiesList); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiEnumPatchesEx(string szProductCode, string szUserSid, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, uint dwFilter, uint dwIndex, StringBuilder szPatchCode, StringBuilder szTargetProductCode, [MarshalAs(UnmanagedType.I4)] out UserContexts pdwTargetProductContext, StringBuilder szTargetUserSid, ref uint pcchTargetUserSid); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetPatchInfoEx(string szPatchCode, string szProductCode, string szUserSid, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, string szProperty, StringBuilder lpValue, ref uint pcchValue); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiEnumProductsEx(string szProductCode, string szUserSid, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, uint dwIndex, StringBuilder szInstalledProductCode, [MarshalAs(UnmanagedType.I4)] out UserContexts pdwInstalledContext, StringBuilder szSid, ref uint pcchSid); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetProductInfoEx(string szProductCode, string szUserSid, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, string szProperty, StringBuilder lpValue, ref uint pcchValue); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiQueryFeatureStateEx(string szProductCode, string szUserSid, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, string szFeature, out int pdwState); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiQueryComponentState(string szProductCode, string szUserSid, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, string szComponent, out int pdwState); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiExtractPatchXMLData(string szPatchPath, uint dwReserved, StringBuilder szXMLData, ref uint pcchXMLData); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSourceListEnumSources(string szProductCodeOrPatchCode, string szUserSid, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, uint dwOptions, uint dwIndex, StringBuilder szSource, ref uint pcchSource); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSourceListAddSourceEx(string szProductCodeOrPatchCode, string szUserSid, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, uint dwOptions, string szSource, uint dwIndex); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSourceListClearSource(string szProductCodeOrPatchCode, string szUserSid, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, uint dwOptions, string szSource); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSourceListClearAllEx(string szProductCodeOrPatchCode, string szUserSid, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, uint dwOptions); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSourceListForceResolutionEx(string szProductCodeOrPatchCode, string szUserSid, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, uint dwOptions); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSourceListGetInfo(string szProductCodeOrPatchCode, string szUserSid, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, uint dwOptions, string szProperty, StringBuilder szValue, ref uint pcchValue); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSourceListSetInfo(string szProductCodeOrPatchCode, string szUserSid, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, uint dwOptions, string szProperty, string szValue); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSourceListEnumMediaDisks(string szProductCodeOrPatchCode, string szUserSID, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, uint dwOptions, uint dwIndex, out uint pdwDiskId, StringBuilder szVolumeLabel, ref uint pcchVolumeLabel, StringBuilder szDiskPrompt, ref uint pcchDiskPrompt); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSourceListAddMediaDisk(string szProductCodeOrPatchCode, string szUserSid, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, uint dwOptions, uint dwDiskId, string szVolumeLabel, string szDiskPrompt); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSourceListClearMediaDisk(string szProductCodeOrPatchCode, string szUserSid, [MarshalAs(UnmanagedType.I4)] UserContexts dwContext, uint dwOptions, uint dwDiskID); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiNotifySidChange(string szOldSid, string szNewSid); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiSetExternalUIRecord([MarshalAs(UnmanagedType.FunctionPtr)] NativeExternalUIRecordHandler puiHandler, uint dwMessageFilter, IntPtr pvContext, out NativeExternalUIRecordHandler ppuiPrevHandler); + +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiGetPatchFileList(string szProductCode, string szPatchList, out uint cFiles, out IntPtr phFileRecords); + +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiBeginTransaction(string szTransactionName, int dwTransactionAttributes, out int hTransaction, out IntPtr phChangeOfOwnerEvent); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiEndTransaction(int dwTransactionState); +[DllImport("msi.dll", CharSet=CharSet.Unicode)] internal static extern uint MsiJoinTransaction(int hTransaction, int dwTransactionAttributes, out IntPtr phChangeOfOwnerEvent); + +[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode, EntryPoint="LoadLibraryExW")] internal static extern IntPtr LoadLibraryEx(string fileName, IntPtr hFile, uint flags); +[DllImport("kernel32.dll", SetLastError=true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool FreeLibrary(IntPtr hModule); +[DllImport("kernel32.dll", SetLastError=true)] internal static extern IntPtr FindResourceEx(IntPtr hModule, IntPtr type, IntPtr name, ushort langId); +[DllImport("kernel32.dll", SetLastError=true)] internal static extern IntPtr LoadResource(IntPtr hModule, IntPtr lpResourceInfo); +[DllImport("kernel32.dll", SetLastError=true)] internal static extern IntPtr LockResource(IntPtr resourceData); +[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode, EntryPoint="FormatMessageW")] internal static extern uint FormatMessage(uint dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, StringBuilder lpBuffer, uint nSize, IntPtr Arguments); +[DllImport("kernel32.dll", SetLastError=true)] internal static extern int WaitForSingleObject(IntPtr handle, int milliseconds); + +[DllImport("ole32.dll")] internal static extern int StgOpenStorage([MarshalAs(UnmanagedType.LPWStr)] string wcsName, IntPtr stgPriority, uint grfMode, IntPtr snbExclude, uint reserved, [MarshalAs(UnmanagedType.Interface)] out IStorage stgOpen); +[DllImport("ole32.dll")] internal static extern int StgCreateDocfile([MarshalAs(UnmanagedType.LPWStr)] string wcsName, uint grfMode, uint reserved, [MarshalAs(UnmanagedType.Interface)] out IStorage stgOpen); + +[DllImport("user32.dll", CharSet=CharSet.Unicode, EntryPoint="MessageBoxW")] internal static extern MessageResult MessageBox(IntPtr hWnd, string lpText, string lpCaption, [MarshalAs(UnmanagedType.U4)] int uType); + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + internal struct MsiPatchSequenceData + { + public string szPatchData; + public int ePatchDataType; + public int dwOrder; + public uint dwStatus; + } + + internal class MsiHandle : SafeHandle + { + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public MsiHandle(IntPtr handle, bool ownsHandle) + : base(handle, ownsHandle) + { + } + + public override bool IsInvalid + { + get + { + return this.handle == IntPtr.Zero; + } + } + + public static implicit operator IntPtr(MsiHandle msiHandle) + { + return msiHandle.handle; + } + + [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)] + protected override bool ReleaseHandle() + { + return RemotableNativeMethods.MsiCloseHandle((int) this.handle) == 0; + } + } +} +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/PatchInstallation.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/PatchInstallation.cs new file mode 100644 index 00000000..defbf64a --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/PatchInstallation.cs @@ -0,0 +1,413 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.Text; + using System.Collections.Generic; + using System.Globalization; + using System.Diagnostics.CodeAnalysis; + + ///+ /// The Patch object represents a unique instance of a patch that has been + /// registered or applied. + /// + public class PatchInstallation : Installation + { + ///+ /// Enumerates all patch installations on the system. + /// + ///Enumeration of patch objects. + ///+ public static IEnumerable + /// Win32 MSI API: + /// MsiEnumPatches + ///
AllPatches + { + get + { + return PatchInstallation.GetPatches(null, null, null, UserContexts.All, PatchStates.All); + } + } + + /// + /// Enumerates patch installations based on certain criteria. + /// + /// PatchCode (GUID) of the patch to be enumerated. Only + /// instances of patches within the scope of the context specified by the + ///and parameters will be + /// enumerated. This parameter may be set to null to enumerate all patches in the specified + /// context. + /// ProductCode (GUID) product whose patches are to be + /// enumerated. If non-null, patch enumeration is restricted to instances of this product + /// within the specified context. If null, the patches for all products under the specified + /// context are enumerated. + /// Specifies a security identifier (SID) that restricts the context + /// of enumeration. A SID value other than s-1-1-0 is considered a user SID and restricts + /// enumeration to the current user or any user in the system. The special SID string + /// s-1-1-0 (Everyone) specifies enumeration across all users in the system. This parameter + /// can be set to null to restrict the enumeration scope to the current user. When + /// must be null. + /// Specifies the user context. + /// The of patches to return. + /// + public static IEnumerable + /// Win32 MSI APIs: + /// MsiEnumPatchesEx + ///
GetPatches( + string patchCode, + string targetProductCode, + string userSid, + UserContexts context, + PatchStates states) + { + StringBuilder buf = new StringBuilder(40); + StringBuilder targetProductBuf = new StringBuilder(40); + UserContexts targetContext; + StringBuilder targetSidBuf = new StringBuilder(40); + for (uint i = 0; ; i++) + { + uint targetSidBufSize = (uint) targetSidBuf.Capacity; + uint ret = NativeMethods.MsiEnumPatchesEx( + targetProductCode, + userSid, + context, + (uint) states, + i, + buf, + targetProductBuf, + out targetContext, + targetSidBuf, + ref targetSidBufSize); + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + targetSidBuf.Capacity = (int) ++targetSidBufSize; + ret = NativeMethods.MsiEnumPatchesEx( + targetProductCode, + userSid, + context, + (uint) states, + i, + buf, + targetProductBuf, + out targetContext, + targetSidBuf, + ref targetSidBufSize); + } + + if (ret == (uint) NativeMethods.Error.NO_MORE_ITEMS) + { + break; + } + + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + + string thisPatchCode = buf.ToString(); + if (patchCode == null || patchCode == thisPatchCode) + { + yield return new PatchInstallation( + buf.ToString(), + targetProductBuf.ToString(), + targetSidBuf.ToString(), + targetContext); + } + } + } + + private string productCode; + + /// + /// Creates a new object for accessing information about a patch installation on the current system. + /// + /// Patch code (GUID) of the patch. + /// ProductCode (GUID) the patch has been applied to. + /// This parameter may be null for patches that are registered only and not yet + /// applied to any product. + ///+ public PatchInstallation(string patchCode, string productCode) + : this(patchCode, productCode, null, UserContexts.All) + { + } + + /// + /// All available user contexts will be queried. + ///
+ /// Creates a new object for accessing information about a patch installation on the current system. + /// + /// Registered patch code (GUID) of the patch. + /// ProductCode (GUID) the patch has been applied to. + /// This parameter may be null for patches that are registered only and not yet + /// applied to any product. + /// The specific user, when working in a user context. This + /// parameter may be null to indicate the current user. The parameter must be null + /// when working in a machine context. + /// The user context. The calling process must have administrative + /// privileges to get information for a product installed for a user other than the + /// current user. + ///+ public PatchInstallation(string patchCode, string productCode, string userSid, UserContexts context) + : base(patchCode, userSid, context) + { + if (String.IsNullOrEmpty(patchCode)) + { + throw new ArgumentNullException("patchCode"); + } + + this.productCode = productCode; + } + + /// + /// If the
is null, the Patch object may + /// only be used to read and update the patch's SourceList information. + /// + /// Gets the patch code (GUID) of the patch. + /// + public string PatchCode + { + get + { + return this.InstallationCode; + } + } + + ///+ /// Gets the ProductCode (GUID) of the product. + /// + public string ProductCode + { + get + { + return this.productCode; + } + } + + ///+ /// Gets a value indicating whether this patch is currently installed. + /// + public override bool IsInstalled + { + get + { + return (this.State & PatchStates.Applied) != 0; + } + } + + ///+ /// Gets a value indicating whether this patch is marked as obsolte. + /// + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Obsoleted")] + public bool IsObsoleted + { + get + { + return (this.State & PatchStates.Obsoleted) != 0; + } + } + + ///+ /// Gets a value indicating whether this patch is present but has been + /// superseded by a more recent installed patch. + /// + public bool IsSuperseded + { + get + { + return (this.State & PatchStates.Superseded) != 0; + } + } + + internal override int InstallationType + { + get + { + const int MSICODE_PATCH = 0x40000000; + return MSICODE_PATCH; + } + } + + ///+ /// Gets the installation state of this instance of the patch. + /// + ///An unknown patch was requested + ///The installer configuration data is corrupt + public PatchStates State + { + get + { + string stateString = this["State"]; + return (PatchStates) Int32.Parse(stateString, CultureInfo.InvariantCulture.NumberFormat); + } + } + + ///+ /// Gets the cached patch file that the product uses. + /// + public string LocalPackage + { + get + { + return this["LocalPackage"]; + } + } + + ///+ /// Gets the set of patch transforms that the last patch + /// installation applied to the product. + /// + ///+ public string Transforms + { + get + { + // TODO: convert to IList + /// This value may not be available for per-user, non-managed applications + /// if the user is not logged on. + ///
? + return this["Transforms"]; + } + } + + /// + /// Gets the date and time when the patch is applied to the product. + /// + public DateTime InstallDate + { + get + { + try + { + return DateTime.ParseExact( + this["InstallDate"], "yyyyMMdd", CultureInfo.InvariantCulture); + } + catch (FormatException) + { + return DateTime.MinValue; + } + } + } + + ///+ /// True patch is marked as possible to uninstall from the product. + /// + ///+ [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Uninstallable")] + public bool Uninstallable + { + get + { + return this["Uninstallable"] == "1"; + } + } + + /// + /// Even if this property is true, the installer can still block the + /// uninstallation if this patch is required by another patch that + /// cannot be uninstalled. + ///
+ /// Get the registered display name for the patch. + /// + public string DisplayName + { + get + { + return this["DisplayName"]; + } + } + + ///+ /// Gets the registered support information URL for the patch. + /// + public Uri MoreInfoUrl + { + get + { + string value = this["MoreInfoURL"]; + if (!String.IsNullOrEmpty(value)) + { + try + { + return new Uri(value); + } + catch (UriFormatException) { } + } + + return null; + } + } + + ///+ /// Gets information about a specific patch installation. + /// + /// The property being retrieved; see remarks for valid properties. + ///The property value, or an empty string if the property is not set for the patch. + ///An unknown patch or property was requested + ///The installer configuration data is corrupt + ///+ public override string this[string propertyName] + { + get + { + StringBuilder buf = new StringBuilder(""); + uint bufSize = 0; + uint ret; + + if (this.Context == UserContexts.UserManaged || + this.Context == UserContexts.UserUnmanaged || + this.Context == UserContexts.Machine) + { + ret = NativeMethods.MsiGetPatchInfoEx( + this.PatchCode, + this.ProductCode, + this.UserSid, + this.Context, + propertyName, + buf, + ref bufSize); + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + buf.Capacity = (int) ++bufSize; + ret = NativeMethods.MsiGetPatchInfoEx( + this.PatchCode, + this.ProductCode, + this.UserSid, + this.Context, + propertyName, + buf, + ref bufSize); + } + } + else + { + ret = NativeMethods.MsiGetPatchInfo( + this.PatchCode, + propertyName, + buf, + ref bufSize); + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + buf.Capacity = (int) ++bufSize; + ret = NativeMethods.MsiGetPatchInfo( + this.PatchCode, + propertyName, + buf, + ref bufSize); + } + } + + if (ret != 0) + { + return null; + } + + return buf.ToString(); + } + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/ProductInstallation.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/ProductInstallation.cs new file mode 100644 index 00000000..27739e17 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/ProductInstallation.cs @@ -0,0 +1,801 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.Text; + using System.Collections.Generic; + using System.Globalization; + using System.Diagnostics.CodeAnalysis; + + /// + /// Win32 MSI APIs: + /// MsiGetPatchInfo, + /// MsiGetPatchInfoEx + ///
+ /// Represents a unique instance of a product that + /// is either advertised, installed or unknown. + /// + public class ProductInstallation : Installation + { + ///+ /// Gets the set of all products with a specified upgrade code. This method lists the + /// currently installed and advertised products that have the specified UpgradeCode + /// property in their Property table. + /// + /// Upgrade code of related products + ///Enumeration of product codes + ///+ public static IEnumerable + /// Win32 MSI API: + /// MsiEnumRelatedProducts + ///
GetRelatedProducts(string upgradeCode) + { + StringBuilder buf = new StringBuilder(40); + for (uint i = 0; true; i++) + { + uint ret = NativeMethods.MsiEnumRelatedProducts(upgradeCode, 0, i, buf); + if (ret == (uint) NativeMethods.Error.NO_MORE_ITEMS) break; + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + yield return new ProductInstallation(buf.ToString()); + } + } + + /// + /// Enumerates all product installations on the system. + /// + ///An enumeration of product objects. + ///+ public static IEnumerable + /// Win32 MSI API: + /// MsiEnumProducts, + ///
AllProducts + { + get + { + return GetProducts(null, null, UserContexts.All); + } + } + + /// + /// Enumerates product installations based on certain criteria. + /// + /// ProductCode (GUID) of the product instances to be enumerated. Only + /// instances of products within the scope of the context specified by the + ///and parameters will be + /// enumerated. This parameter may be set to null to enumerate all products in the specified + /// context. + /// Specifies a security identifier (SID) that restricts the context + /// of enumeration. A SID value other than s-1-1-0 is considered a user SID and restricts + /// enumeration to the current user or any user in the system. The special SID string + /// s-1-1-0 (Everyone) specifies enumeration across all users in the system. This parameter + /// can be set to null to restrict the enumeration scope to the current user. When + /// is set to the machine context only, + /// must be null. + /// Specifies the user context. + /// An enumeration of product objects for enumerated product instances. + ///+ public static IEnumerable + /// Win32 MSI API: + /// MsiEnumProductsEx + ///
GetProducts( + string productCode, string userSid, UserContexts context) + { + StringBuilder buf = new StringBuilder(40); + UserContexts targetContext; + StringBuilder targetSidBuf = new StringBuilder(40); + for (uint i = 0; ; i++) + { + uint targetSidBufSize = (uint) targetSidBuf.Capacity; + uint ret = NativeMethods.MsiEnumProductsEx( + productCode, + userSid, + context, + i, + buf, + out targetContext, + targetSidBuf, + ref targetSidBufSize); + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + targetSidBuf.Capacity = (int) ++targetSidBufSize; + ret = NativeMethods.MsiEnumProductsEx( + productCode, + userSid, + context, + i, + buf, + out targetContext, + targetSidBuf, + ref targetSidBufSize); + } + + if (ret == (uint) NativeMethods.Error.NO_MORE_ITEMS) + { + break; + } + + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + + yield return new ProductInstallation( + buf.ToString(), + targetSidBuf.ToString(), + targetContext); + } + } + + private IDictionary properties; + + /// + /// Creates a new object for accessing information about a product installation on the current system. + /// + /// ProductCode (GUID) of the product. + ///+ public ProductInstallation(string productCode) + : this(productCode, null, UserContexts.All) + { + } + + /// + /// All available user contexts will be queried. + ///
+ /// Creates a new object for accessing information about a product installation on the current system. + /// + /// ProductCode (GUID) of the product. + /// The specific user, when working in a user context. This + /// parameter may be null to indicate the current user. The parameter must be null + /// when working in a machine context. + /// The user context. The calling process must have administrative + /// privileges to get information for a product installed for a user other than the + /// current user. + public ProductInstallation(string productCode, string userSid, UserContexts context) + : base(productCode, userSid, context) + { + if (String.IsNullOrEmpty(productCode)) + { + throw new ArgumentNullException("productCode"); + } + } + + internal ProductInstallation(IDictionaryproperties) + : base(properties["ProductCode"], null, UserContexts.None) + { + this.properties = properties; + } + + /// + /// Gets the set of published features for the product. + /// + ///Enumeration of published features for the product. + ///The installer configuration data is corrupt + ///+ public IEnumerable + /// Because features are not ordered, any new feature has an arbitrary index, meaning + /// this property can return features in any order. + ///
+ /// Win32 MSI API: + /// MsiEnumFeatures + ///
Features + { + get + { + StringBuilder buf = new StringBuilder(256); + for (uint i = 0; ; i++) + { + uint ret = NativeMethods.MsiEnumFeatures(this.ProductCode, i, buf, null); + + if (ret != 0) + { + break; + } + + yield return new FeatureInstallation(buf.ToString(), this.ProductCode); + } + } + } + + /// + /// Gets the ProductCode (GUID) of the product. + /// + public string ProductCode + { + get { return this.InstallationCode; } + } + + ///+ /// Gets a value indicating whether this product is installed on the current system. + /// + public override bool IsInstalled + { + get + { + return (this.State == InstallState.Default); + } + } + + ///+ /// Gets a value indicating whether this product is advertised on the current system. + /// + public bool IsAdvertised + { + get + { + return (this.State == InstallState.Advertised); + } + } + + ///+ /// Checks whether the product is installed with elevated privileges. An application is called + /// a "managed application" if elevated (system) privileges are used to install the application. + /// + ///True if the product is elevated; false otherwise + ///+ public bool IsElevated + { + get + { + bool isElevated; + uint ret = NativeMethods.MsiIsProductElevated(this.ProductCode, out isElevated); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + return isElevated; + } + } + + /// + /// Note that this property does not take into account policies such as AlwaysInstallElevated, + /// but verifies that the local system owns the product's registry data. + ///
+ /// Gets the source list of this product installation. + /// + public override SourceList SourceList + { + get + { + return this.properties == null ? base.SourceList : null; + } + } + + internal InstallState State + { + get + { + if (this.properties != null) + { + return InstallState.Unknown; + } + else + { + int installState = NativeMethods.MsiQueryProductState(this.ProductCode); + return (InstallState) installState; + } + } + } + + internal override int InstallationType + { + get + { + const int MSICODE_PRODUCT = 0x00000000; + return MSICODE_PRODUCT; + } + } + + ///+ /// The support link. + /// + public string HelpLink + { + get + { + return this["HelpLink"]; + } + } + + ///+ /// The support telephone. + /// + public string HelpTelephone + { + get + { + return this["HelpTelephone"]; + } + } + + ///+ /// Date and time the product was installed. + /// + public DateTime InstallDate + { + get + { + try + { + return DateTime.ParseExact( + this["InstallDate"], "yyyyMMdd", CultureInfo.InvariantCulture); + } + catch (FormatException) + { + return DateTime.MinValue; + } + } + } + + ///+ /// The installed product name. + /// + public string ProductName + { + get + { + return this["InstalledProductName"]; + } + } + + ///+ /// The installation location. + /// + public string InstallLocation + { + get + { + return this["InstallLocation"]; + } + } + + ///+ /// The installation source. + /// + public string InstallSource + { + get + { + return this["InstallSource"]; + } + } + + ///+ /// The local cached package. + /// + public string LocalPackage + { + get + { + return this["LocalPackage"]; + } + } + + ///+ /// The publisher. + /// + public string Publisher + { + get + { + return this["Publisher"]; + } + } + + ///+ /// URL about information. + /// + public Uri UrlInfoAbout + { + get + { + string value = this["URLInfoAbout"]; + if (!String.IsNullOrEmpty(value)) + { + try + { + return new Uri(value); + } + catch (UriFormatException) { } + } + + return null; + } + } + + ///+ /// The URL update information. + /// + public Uri UrlUpdateInfo + { + get + { + string value = this["URLUpdateInfo"]; + if (!String.IsNullOrEmpty(value)) + { + try + { + return new Uri(value); + } + catch (UriFormatException) { } + } + + return null; + } + } + + ///+ /// The product version. + /// + public Version ProductVersion + { + get + { + string ver = this["VersionString"]; + return ProductInstallation.ParseVersion(ver); + } + } + + ///+ /// The product identifier. + /// + ///+ public string ProductId + { + get + { + return this["ProductID"]; + } + } + + /// + /// For more information, see + /// ProductID + ///
+ /// The company that is registered to use the product. + /// + public string RegCompany + { + get + { + return this["RegCompany"]; + } + } + + ///+ /// The owner who is registered to use the product. + /// + public string RegOwner + { + get + { + return this["RegOwner"]; + } + } + + ///+ /// Transforms. + /// + public string AdvertisedTransforms + { + get + { + return this["Transforms"]; + } + } + + ///+ /// Product language. + /// + public string AdvertisedLanguage + { + get + { + return this["Language"]; + } + } + + ///+ /// Human readable product name. + /// + public string AdvertisedProductName + { + get + { + return this["ProductName"]; + } + } + + ///+ /// True if the product is advertised per-machine; + /// false if it is per-user or not advertised. + /// + public bool AdvertisedPerMachine + { + get + { + return this["AssignmentType"] == "1"; + } + } + + ///+ /// Identifier of the package that a product is installed from. + /// + public string AdvertisedPackageCode + { + get + { + return this["PackageCode"]; + } + } + + ///+ /// Version of the advertised product. + /// + public Version AdvertisedVersion + { + get + { + string ver = this["Version"]; + return ProductInstallation.ParseVersion(ver); + } + } + + ///+ /// Primary icon for the package. + /// + public string AdvertisedProductIcon + { + get + { + return this["ProductIcon"]; + } + } + + ///+ /// Name of the installation package for the advertised product. + /// + public string AdvertisedPackageName + { + get + { + return this["PackageName"]; + } + } + + ///+ /// True if the advertised product can be serviced by + /// non-administrators without elevation. + /// + public bool PrivilegedPatchingAuthorized + { + get + { + return this["AuthorizedLUAApp"] == "1"; + } + } + + ///+ /// Gets information about an installation of a product. + /// + /// Name of the property being retrieved. + ///An unknown product or property was requested + ///The installer configuration data is corrupt + ///+ public override string this[string propertyName] + { + get + { + if (this.properties != null) + { + string value = null; + this.properties.TryGetValue(propertyName, out value); + return value; + } + else + { + StringBuilder buf = new StringBuilder(40); + uint bufSize = (uint) buf.Capacity; + uint ret; + + if (this.Context == UserContexts.UserManaged || + this.Context == UserContexts.UserUnmanaged || + this.Context == UserContexts.Machine) + { + ret = NativeMethods.MsiGetProductInfoEx( + this.ProductCode, + this.UserSid, + this.Context, + propertyName, + buf, + ref bufSize); + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + buf.Capacity = (int) ++bufSize; + ret = NativeMethods.MsiGetProductInfoEx( + this.ProductCode, + this.UserSid, + this.Context, + propertyName, + buf, + ref bufSize); + } + } + else + { + ret = NativeMethods.MsiGetProductInfo( + this.ProductCode, + propertyName, + buf, + ref bufSize); + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + buf.Capacity = (int) ++bufSize; + ret = NativeMethods.MsiGetProductInfo( + this.ProductCode, + propertyName, + buf, + ref bufSize); + } + } + + if (ret != 0) + { + return null; + } + + return buf.ToString(); + } + } + } + + /// + /// Win32 MSI APIs: + /// MsiGetProductInfo, + /// MsiGetProductInfoEx + ///
+ /// Gets the installed state for a product feature. + /// + /// The feature being queried; identifier from the + /// Feature table + ///Installation state of the feature for the product instance: either + /// + ///, , + /// or . + public InstallState GetFeatureState(string feature) + { + if (this.properties != null) + { + return InstallState.Unknown; + } + else + { + int installState; + uint ret = NativeMethods.MsiQueryFeatureStateEx( + this.ProductCode, + this.UserSid, + this.Context, + feature, + out installState); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + return (InstallState) installState; + } + } + + /// + /// Win32 MSI APIs: + /// MsiQueryFeatureState, + /// MsiQueryFeatureStateEx + ///
+ /// Gets the installed state for a product component. + /// + /// The component being queried; GUID of the component + /// as found in the ComponentId column of the Component table. + ///Installation state of the component for the product instance: either + /// + ///or . + public InstallState GetComponentState(string component) + { + if (this.properties != null) + { + return InstallState.Unknown; + } + else + { + int installState; + uint ret = NativeMethods.MsiQueryComponentState( + this.ProductCode, + this.UserSid, + this.Context, + component, + out installState); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + return (InstallState) installState; + } + } + + /// + /// Win32 MSI API: + /// MsiQueryComponentState + ///
+ /// Obtains and stores the user information and product ID from an installation wizard. + /// + ///+ public void CollectUserInfo() + { + if (this.properties == null) + { + uint ret = NativeMethods.MsiCollectUserInfo(this.InstallationCode); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + } + + /// + /// This method is typically called by an application during the first run of the application. The application + /// first gets the
or . + /// If those properties are missing, the application calls CollectUserInfo. + /// CollectUserInfo opens the product's installation package and invokes a wizard sequence that collects + /// user information. Upon completion of the sequence, user information is registered. Since this API requires + /// an authored user interface, the user interface level should be set to full by calling + /// as . + /// + /// The CollectUserInfo method invokes a FirstRun dialog from the product installation database. + ///
+ /// Win32 MSI API: + /// MsiCollectUserInfo + ///
+ /// Some products might write some invalid/nonstandard version strings to the registry. + /// This method tries to get the best data it can. + /// + /// Version string retrieved from the registry. + ///Version object, or null if the version string is completely invalid. + private static Version ParseVersion(string ver) + { + if (ver != null) + { + int dotCount = 0; + for (int i = 0; i < ver.Length; i++) + { + char c = ver[i]; + if (c == '.') dotCount++; + else if (!Char.IsDigit(c)) + { + ver = ver.Substring(0, i); + break; + } + } + + if (ver.Length > 0) + { + if (dotCount == 0) + { + ver = ver + ".0"; + } + else if (dotCount > 3) + { + string[] verSplit = ver.Split('.'); + ver = String.Join(".", verSplit, 0, 4); + } + + try + { + return new Version(ver); + } + catch (ArgumentException) + { + } + } + } + + return null; + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Record.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Record.cs new file mode 100644 index 00000000..2d31fa75 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Record.cs @@ -0,0 +1,1048 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.IO; + using System.Text; + using System.Collections.Generic; + using System.Runtime.InteropServices; + using System.Diagnostics.CodeAnalysis; + + ///+ /// The Record object is a container for holding and transferring a variable number of values. + /// Fields within the record are numerically indexed and can contain strings, integers, streams, + /// and null values. Record fields are indexed starting with 1. Field 0 is a special format field. + /// + ///+ public class Record : InstallerHandle + { + private View view; + private bool isFormatStringInvalid; + + /// + /// Most methods on the Record class have overloads that allow using either a number + /// or a name to designate a field. However note that field names only exist when the + /// Record is directly returned from a query on a database. For other records, attempting + /// to access a field by name will result in an InvalidOperationException. + ///
+ /// IsFormatStringInvalid is set from several View methods that invalidate the FormatString + /// and used to determine behavior during Record.ToString(). + /// + internal protected bool IsFormatStringInvalid + { + set { this.isFormatStringInvalid = value; } + + get { return this.isFormatStringInvalid; } + } + + ///+ /// Creates a new record object with the requested number of fields. + /// + /// Required number of fields, which may be 0. + /// The maximum number of fields in a record is limited to 65535. + ///+ public Record(int fieldCount) + : this((IntPtr) RemotableNativeMethods.MsiCreateRecord((uint) fieldCount, 0), true, (View) null) + { + } + + /// + /// The Record object should be
d after use. + /// It is best that the handle be closed manually as soon as it is no longer + /// needed, as leaving lots of unused handles open can degrade performance. + /// + /// Win32 MSI API: + /// MsiCreateRecord + ///
+ /// Creates a new record object, providing values for an arbitrary number of fields. + /// + /// The values of the record fields. The parameters should be of type Int16, Int32 or String + ///+ public Record(params object[] fields) + : this(fields.Length) + { + for (int i = 0; i < fields.Length; i++) + { + this[i + 1] = fields[i]; + } + } + + internal Record(IntPtr handle, bool ownsHandle, View view) + : base(handle, ownsHandle) + { + this.view = view; + } + + /// + /// The Record object should be
d after use. + /// It is best that the handle be closed manually as soon as it is no longer + /// needed, as leaving lots of unused handles open can degrade performance. + /// + /// Win32 MSI API: + /// MsiCreateRecord + ///
+ /// Gets the number of fields in a record. + /// + ///+ public int FieldCount + { + get + { + return (int) RemotableNativeMethods.MsiRecordGetFieldCount((int) this.Handle); + } + } + + /// + /// Win32 MSI API: + /// MsiRecordGetFieldCount + ///
+ /// Gets or sets field 0 of the Record, which is the format string. + /// + public string FormatString + { + get { return this.GetString(0); } + set { this.SetString(0, value); } + } + + ///+ /// Gets or sets a record field value. + /// + /// Specifies the name of the field of the Record to get or set. + ///The name does not match any known field of the Record. + ///+ public object this[string fieldName] + { + get + { + int field = this.FindColumn(fieldName); + return this[field]; + } + + set + { + int field = this.FindColumn(fieldName); + this[field] = value; + } + } + + /// + /// When getting a field, the type of the object returned depends on the type of the Record field. + /// The object will be one of: Int16, Int32, String, Stream, or null. + ///
+ /// When setting a field, the type of the object provided will be converted to match the View + /// query that returned the record, or if Record was not returned from a view then the type of + /// the object provided will determine the type of the Record field. The object should be one of: + /// Int16, Int32, String, Stream, or null. + ///
+ /// Gets or sets a record field value. + /// + /// Specifies the field of the Record to get or set. + ///The field is less than 0 or greater than the + /// number of fields in the Record. + ///+ public object this[int field] + { + get + { + if (field == 0) + { + return this.GetString(0); + } + else + { + Type valueType = null; + if (this.view != null) + { + this.CheckRange(field); + + valueType = this.view.Columns[field - 1].Type; + } + + if (valueType == null || valueType == typeof(String)) + { + return this.GetString(field); + } + else if (valueType == typeof(Stream)) + { + return this.IsNull(field) ? null : new RecordStream(this, field); + } + else + { + int? value = this.GetNullableInteger(field); + return value.HasValue ? (object) value.Value : null; + } + } + } + + set + { + if (field == 0) + { + if (value == null) + { + value = String.Empty; + } + + this.SetString(0, value.ToString()); + } + else if (value == null) + { + this.SetNullableInteger(field, null); + } + else + { + Type valueType = value.GetType(); + if (valueType == typeof(Int32) || valueType == typeof(Int16)) + { + this.SetInteger(field, (int) value); + } + else if (valueType.IsSubclassOf(typeof(Stream))) + { + this.SetStream(field, (Stream) value); + } + else + { + this.SetString(field, value.ToString()); + } + } + } + } + + /// + /// Record fields are indexed starting with 1. Field 0 is a special format field. + ///
+ /// When getting a field, the type of the object returned depends on the type of the Record field. + /// The object will be one of: Int16, Int32, String, Stream, or null. If the Record was returned + /// from a View, the type will match that of the field from the View query. Otherwise, the type + /// will match the type of the last value set for the field. + ///
+ /// When setting a field, the type of the object provided will be converted to match the View + /// query that returned the Record, or if Record was not returned from a View then the type of + /// the object provided will determine the type of the Record field. The object should be one of: + /// Int16, Int32, String, Stream, or null. + ///
+ /// The type-specific getters and setters are slightly more efficient than this property, since + /// they don't have to do the extra work to infer the value's type every time. + ///
+ /// Win32 MSI APIs: + /// MsiRecordGetInteger, + /// MsiRecordGetString, + /// MsiRecordSetInteger, + /// MsiRecordSetString + ///
+ /// Creates a new Record object from an integer record handle. + /// + ///+ /// Integer record handle + /// true to close the handle when this object is disposed or finalized + public static Record FromHandle(IntPtr handle, bool ownsHandle) + { + return new Record(handle, ownsHandle, (View) null); + } + + /// + /// This method is only provided for interop purposes. A Record object + /// should normally be obtained by calling
+ /// other methods. + /// The handle will be closed when this object is disposed or finalized.
+ ///+ /// Sets all fields in a record to null. + /// + ///+ public void Clear() + { + uint ret = RemotableNativeMethods.MsiRecordClearData((int) this.Handle); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// Win32 MSI API: + /// MsiRecordClearData + ///
+ /// Reports whether a record field is null. + /// + /// Specifies the field to check. + ///True if the field is null, false otherwise. + ///The field is less than 0 or greater than the + /// number of fields in the Record. + ///+ public bool IsNull(int field) + { + this.CheckRange(field); + return RemotableNativeMethods.MsiRecordIsNull((int) this.Handle, (uint) field); + } + + /// + /// Win32 MSI API: + /// MsiRecordIsNull + ///
+ /// Reports whether a record field is null. + /// + /// Specifies the field to check. + ///True if the field is null, false otherwise. + ///The field name does not match any + /// of the named fields in the Record. + public bool IsNull(string fieldName) + { + int field = this.FindColumn(fieldName); + return this.IsNull(field); + } + + ///+ /// Gets the length of a record field. The count does not include the terminating null. + /// + ///The field is less than 0 or greater than the + /// number of fields in the Record. + ///+ public int GetDataSize(int field) + { + this.CheckRange(field); + return (int) RemotableNativeMethods.MsiRecordDataSize((int) this.Handle, (uint) field); + } + + /// + /// The returned data size is 0 if the field is null, non-existent, + /// or an internal object pointer. The method also returns 0 if the handle is not a valid + /// Record handle. + ///
+ /// If the data is in integer format, the property returns 2 or 4. + ///
+ /// If the data is in string format, the property returns the character count + /// (not including the NULL terminator). + ///
+ /// If the data is in stream format, the property returns the byte count. + ///
+ /// Win32 MSI API: + /// MsiRecordDataSize + ///
+ /// Gets the length of a record field. The count does not include the terminating null. + /// + /// Specifies the field to check. + ///The field name does not match any + /// of the named fields in the Record. + ///+ public int GetDataSize(string fieldName) + { + int field = this.FindColumn(fieldName); + return this.GetDataSize(field); + } + + /// The returned data size is 0 if the field is null, non-existent, + /// or an internal object pointer. The method also returns 0 if the handle is not a valid + /// Record handle. + ///
+ /// If the data is in integer format, the property returns 2 or 4. + ///
+ /// If the data is in string format, the property returns the character count + /// (not including the NULL terminator). + ///
+ /// If the data is in stream format, the property returns the byte count. + ///
+ /// Gets a field value as an integer. + /// + /// Specifies the field to retrieve. + ///Integer value of the field, or 0 if the field is null. + ///The field is less than 0 or greater than the + /// number of fields in the Record. + ///+ /// + /// Win32 MSI API: + /// MsiRecordGetInteger + ///
+ [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "integer")] + public int GetInteger(int field) + { + this.CheckRange(field); + + int value = RemotableNativeMethods.MsiRecordGetInteger((int) this.Handle, (uint) field); + if (value == Int32.MinValue) // MSI_NULL_INTEGER + { + return 0; + } + return value; + } + + /// + /// Gets a field value as an integer. + /// + /// Specifies the field to retrieve. + ///Integer value of the field, or 0 if the field is null. + ///The field name does not match any + /// of the named fields in the Record. + ///+ [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "integer")] + public int GetInteger(string fieldName) + { + int field = this.FindColumn(fieldName); + return this.GetInteger(field); + } + + /// + /// Gets a field value as an integer. + /// + /// Specifies the field to retrieve. + ///Integer value of the field, or null if the field is null. + ///The field is less than 0 or greater than the + /// number of fields in the Record. + ///+ /// + /// Win32 MSI API: + /// MsiRecordGetInteger + ///
+ public int? GetNullableInteger(int field) + { + this.CheckRange(field); + + int value = RemotableNativeMethods.MsiRecordGetInteger((int) this.Handle, (uint) field); + if (value == Int32.MinValue) // MSI_NULL_INTEGER + { + return null; + } + return value; + } + + /// + /// Gets a field value as an integer. + /// + /// Specifies the field to retrieve. + ///Integer value of the field, or null if the field is null. + ///The field name does not match any + /// of the named fields in the Record. + ///+ public int? GetNullableInteger(string fieldName) + { + int field = this.FindColumn(fieldName); + return this.GetInteger(field); + } + + /// + /// Sets the value of a field to an integer. + /// + /// Specifies the field to set. + /// new value of the field + ///The field is less than 0 or greater than the + /// number of fields in the Record. + ///+ /// + /// Win32 MSI API: + /// MsiRecordSetInteger + ///
+ public void SetInteger(int field, int value) + { + this.CheckRange(field); + + uint ret = RemotableNativeMethods.MsiRecordSetInteger((int) this.Handle, (uint) field, value); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// Sets the value of a field to an integer. + /// + /// Specifies the field to set. + /// new value of the field + ///The field name does not match any + /// of the named fields in the Record. + ///+ public void SetInteger(string fieldName, int value) + { + int field = this.FindColumn(fieldName); + this.SetInteger(field, value); + } + + /// + /// Sets the value of a field to a nullable integer. + /// + /// Specifies the field to set. + /// new value of the field + ///The field is less than 0 or greater than the + /// number of fields in the Record. + ///+ /// + /// Win32 MSI API: + /// MsiRecordSetInteger + ///
+ public void SetNullableInteger(int field, int? value) + { + this.CheckRange(field); + + uint ret = RemotableNativeMethods.MsiRecordSetInteger( + (int) this.Handle, + (uint) field, + value.HasValue ? (int) value : Int32.MinValue); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// Sets the value of a field to a nullable integer. + /// + /// Specifies the field to set. + /// new value of the field + ///The field name does not match any + /// of the named fields in the Record. + ///+ public void SetNullableInteger(string fieldName, int? value) + { + int field = this.FindColumn(fieldName); + this.SetNullableInteger(field, value); + } + + /// + /// Gets a field value as a string. + /// + /// Specifies the field to retrieve. + ///String value of the field, or an empty string if the field is null. + ///The field is less than 0 or greater than the + /// number of fields in the Record. + ///+ public string GetString(int field) + { + this.CheckRange(field); + + StringBuilder buf = new StringBuilder(String.Empty); + uint bufSize = 0; + uint ret = RemotableNativeMethods.MsiRecordGetString((int) this.Handle, (uint) field, buf, ref bufSize); + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + buf.Capacity = (int) ++bufSize; + ret = RemotableNativeMethods.MsiRecordGetString((int) this.Handle, (uint) field, buf, ref bufSize); + } + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + return buf.ToString(); + } + + /// + /// Win32 MSI API: + /// MsiRecordGetString + ///
+ /// Gets a field value as a string. + /// + /// Specifies the field to retrieve. + ///String value of the field, or an empty string if the field is null. + ///The field name does not match any + /// of the named fields in the Record. + public string GetString(string fieldName) + { + int field = this.FindColumn(fieldName); + return this.GetString(field); + } + + ///+ /// Sets the value of a field to a string. + /// + /// Specifies the field to set. + /// new value of the field + ///The field is less than 0 or greater than the + /// number of fields in the Record. + ///+ public void SetString(int field, string value) + { + this.CheckRange(field); + + if (value == null) + { + value = String.Empty; + } + + uint ret = RemotableNativeMethods.MsiRecordSetString((int) this.Handle, (uint) field, value); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + + // If we set the FormatString manually, then it should be valid again + if (field == 0) + { + this.IsFormatStringInvalid = false; + } + } + + /// + /// Win32 MSI API: + /// MsiRecordSetString + ///
+ /// Sets the value of a field to a string. + /// + /// Specifies the field to set. + /// new value of the field + ///The field name does not match any + /// of the named fields in the Record. + public void SetString(string fieldName, string value) + { + int field = this.FindColumn(fieldName); + this.SetString(field, value); + } + + ///+ /// Reads a record stream field into a file. + /// + /// Specifies the field of the Record to get. + /// Specifies the path to the file to contain the stream. + ///The field is less than 0 or greater than the + /// number of fields in the Record. + ///Attempt to extract a storage from a database open + /// in read-write mode, or from a database without an associated file path + ///+ public void GetStream(int field, string filePath) + { + if (String.IsNullOrEmpty(filePath)) + { + throw new ArgumentNullException("filePath"); + } + + IList + /// This method is capable of directly extracting substorages. To do so, first select both the + /// `Name` and `Data` column of the `_Storages` table, then get the stream of the `Data` field. + /// However, substorages may only be extracted from a database that is open in read-only mode. + ///
+ /// Win32 MSI API: + /// MsiRecordReadStream + ///
tables = (this.view != null ? this.view.Tables : null); + if (tables != null && tables.Count == 1 && tables[0].Name == "_Storages" && field == this.FindColumn("Data")) + { + if (!this.view.Database.IsReadOnly) + { + throw new NotSupportedException("Database must be opened read-only to support substorage extraction."); + } + else if (this.view.Database.FilePath == null) + { + throw new NotSupportedException("Database must have an associated file path to support substorage extraction."); + } + else if (this.FindColumn("Name") <= 0) + { + throw new NotSupportedException("Name column must be part of the Record in order to extract substorage."); + } + else + { + Record.ExtractSubStorage(this.view.Database.FilePath, this.GetString("Name"), filePath); + } + } + else + { + if (!this.IsNull(field)) + { + Stream readStream = null, writeStream = null; + try + { + readStream = new RecordStream(this, field); + writeStream = new FileStream(filePath, FileMode.Create, FileAccess.Write); + int count = 512; + byte[] buf = new byte[count]; + while (count == buf.Length) + { + if ((count = readStream.Read(buf, 0, buf.Length)) > 0) + { + writeStream.Write(buf, 0, count); + } + } + } + finally + { + if (readStream != null) readStream.Close(); + if (writeStream != null) writeStream.Close(); + } + } + } + } + + /// + /// Reads a record stream field into a file. + /// + /// Specifies the field of the Record to get. + /// Specifies the path to the file to contain the stream. + ///The field name does not match any + /// of the named fields in the Record. + ///Attempt to extract a storage from a database open + /// in read-write mode, or from a database without an associated file path + ///+ public void GetStream(string fieldName, string filePath) + { + int field = this.FindColumn(fieldName); + this.GetStream(field, filePath); + } + + /// + /// This method is capable of directly extracting substorages. To do so, first select both the + /// `Name` and `Data` column of the `_Storages` table, then get the stream of the `Data` field. + /// However, substorages may only be extracted from a database that is open in read-only mode. + ///
+ /// Gets a record stream field. + /// + /// Specifies the field of the Record to get. + ///A Stream that reads the field data. + ///The field is less than 0 or greater than the + /// number of fields in the Record. + ///+ public Stream GetStream(int field) + { + this.CheckRange(field); + + return this.IsNull(field) ? null : new RecordStream(this, field); + } + + /// + /// This method is not capable of reading substorages. To extract a substorage, + /// use
. + /// + /// Win32 MSI API: + /// MsiRecordReadStream + ///
+ /// Gets a record stream field. + /// + /// Specifies the field of the Record to get. + ///A Stream that reads the field data. + ///The field name does not match any + /// of the named fields in the Record. + ///+ public Stream GetStream(string fieldName) + { + int field = this.FindColumn(fieldName); + return this.GetStream(field); + } + + /// + /// This method is not capable of reading substorages. To extract a substorage, + /// use
. + /// + /// Sets a record stream field from a file. Stream data cannot be inserted into temporary fields. + /// + /// Specifies the field of the Record to set. + /// Specifies the path to the file containing the stream. + ///The field is less than 0 or greater than the + /// number of fields in the Record. + ///+ public void SetStream(int field, string filePath) + { + this.CheckRange(field); + + if (String.IsNullOrEmpty(filePath)) + { + throw new ArgumentNullException("filePath"); + } + + uint ret = RemotableNativeMethods.MsiRecordSetStream((int) this.Handle, (uint) field, filePath); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// The contents of the specified file are read into a stream object. The stream persists if + /// the Record is inserted into the Database and the Database is committed. + ///
+ /// To reset the stream to its beginning you must pass in null for filePath. + /// Do not pass an empty string, "", to reset the stream. + ///
+ /// Setting a stream with this method is more efficient than setting a field to a + /// FileStream object. + ///
+ /// Win32 MSI API: + /// MsiRecordsetStream + ///
+ /// Sets a record stream field from a file. Stream data cannot be inserted into temporary fields. + /// + /// Specifies the field name of the Record to set. + /// Specifies the path to the file containing the stream. + ///The field name does not match any + /// of the named fields in the Record. + ///+ public void SetStream(string fieldName, string filePath) + { + int field = this.FindColumn(fieldName); + this.SetStream(field, filePath); + } + + /// + /// The contents of the specified file are read into a stream object. The stream persists if + /// the Record is inserted into the Database and the Database is committed. + /// To reset the stream to its beginning you must pass in null for filePath. + /// Do not pass an empty string, "", to reset the stream. + ///
+ /// Setting a stream with this method is more efficient than setting a field to a + /// FileStream object. + ///
+ /// Sets a record stream field from a Stream object. Stream data cannot be inserted into temporary fields. + /// + /// Specifies the field of the Record to set. + /// Specifies the stream data. + ///The field is less than 0 or greater than the + /// number of fields in the Record. + ///+ public void SetStream(int field, Stream stream) + { + this.CheckRange(field); + + if (stream == null) + { + uint ret = RemotableNativeMethods.MsiRecordSetStream((int) this.Handle, (uint) field, null); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + else + { + Stream writeStream = null; + string tempPath = Path.GetTempFileName(); + try + { + writeStream = new FileStream(tempPath, FileMode.Truncate, FileAccess.Write); + byte[] buf = new byte[512]; + int count; + while ((count = stream.Read(buf, 0, buf.Length)) > 0) + { + writeStream.Write(buf, 0, count); + } + writeStream.Close(); + writeStream = null; + + uint ret = RemotableNativeMethods.MsiRecordSetStream((int) this.Handle, (uint) field, tempPath); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + finally + { + if (writeStream != null) writeStream.Close(); + if (File.Exists(tempPath)) + { + try + { + File.Delete(tempPath); + } + catch (IOException) + { + if (this.view != null) + { + this.view.Database.DeleteOnClose(tempPath); + } + } + } + } + } + } + + /// + /// The stream persists if the Record is inserted into the Database and the Database is committed. + ///
+ /// Win32 MSI API: + /// MsiRecordsetStream + ///
+ /// Sets a record stream field from a Stream object. Stream data cannot be inserted into temporary fields. + /// + /// Specifies the field name of the Record to set. + /// Specifies the stream data. + ///The field name does not match any + /// of the named fields in the Record. + ///+ public void SetStream(string fieldName, Stream stream) + { + int field = this.FindColumn(fieldName); + this.SetStream(field, stream); + } + + /// + /// The stream persists if the Record is inserted into the Database and the Database is committed. + ///
+ /// Gets a formatted string representation of the Record. + /// + ///A formatted string representation of the Record. + ///+ /// + /// If field 0 of the Record is set to a nonempty string, it is used to format the data in the Record. + ///
+ /// Win32 MSI API: + /// MsiFormatRecord + ///
+ /// + public override string ToString() + { + return this.ToString((IFormatProvider) null); + } + + /// + /// Gets a formatted string representation of the Record, optionally using a Session to format properties. + /// + /// an optional Session instance that will be used to lookup any + /// properties in the Record's format string + ///A formatted string representation of the Record. + ///+ /// + /// If field 0 of the Record is set to a nonempty string, it is used to format the data in the Record. + ///
+ /// Win32 MSI API: + /// MsiFormatRecord + ///
+ /// + public string ToString(IFormatProvider provider) + { + if (this.IsFormatStringInvalid) // Format string is invalid + { + // TODO: return all values by default? + return String.Empty; + } + + InstallerHandle session = provider as InstallerHandle; + int sessionHandle = session != null ? (int) session.Handle : 0; + StringBuilder buf = new StringBuilder(String.Empty); + uint bufSize = 1; + uint ret = RemotableNativeMethods.MsiFormatRecord(sessionHandle, (int) this.Handle, buf, ref bufSize); + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + bufSize++; + buf = new StringBuilder((int) bufSize); + ret = RemotableNativeMethods.MsiFormatRecord(sessionHandle, (int) this.Handle, buf, ref bufSize); + } + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + return buf.ToString(); + } + + /// + /// Gets a formatted string representation of the Record. + /// + /// String to be used to format the data in the Record, + /// instead of the Record's format string. + ///A formatted string representation of the Record. + ///+ [Obsolete("This method is obsolete because it has undesirable side-effects. As an alternative, set the FormatString " + + "property separately before calling the ToString() override that takes no parameters.")] + public string ToString(string format) + { + return this.ToString(format, null); + } + + /// + /// Win32 MSI API: + /// MsiFormatRecord + ///
+ /// Gets a formatted string representation of the Record, optionally using a Session to format properties. + /// + /// String to be used to format the data in the Record, + /// instead of the Record's format string. + /// an optional Session instance that will be used to lookup any + /// properties in the Record's format string + ///A formatted string representation of the Record. + ///+ /// + /// Win32 MSI API: + /// MsiFormatRecord + ///
+ /// + [Obsolete("This method is obsolete because it has undesirable side-effects. As an alternative, set the FormatString " + + "property separately before calling the ToString() override that takes just a format provider.")] + public string ToString(string format, IFormatProvider provider) + { + if (format == null) + { + return this.ToString(provider); + } + else if (format.Length == 0) + { + return String.Empty; + } + else + { + string savedFormatString = (string) this[0]; + try + { + this.FormatString = format; + return this.ToString(provider); + } + finally + { + this.FormatString = savedFormatString; + } + } + } + + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + private static void ExtractSubStorage(string databaseFile, string storageName, string extractFile) + { + IStorage storage; + NativeMethods.STGM openMode = NativeMethods.STGM.READ | NativeMethods.STGM.SHARE_DENY_WRITE; + int hr = NativeMethods.StgOpenStorage(databaseFile, IntPtr.Zero, (uint) openMode, IntPtr.Zero, 0, out storage); + if (hr != 0) + { + Marshal.ThrowExceptionForHR(hr); + } + + try + { + openMode = NativeMethods.STGM.READ | NativeMethods.STGM.SHARE_EXCLUSIVE; + IStorage subStorage = storage.OpenStorage(storageName, IntPtr.Zero, (uint) openMode, IntPtr.Zero, 0); + + try + { + IStorage newStorage; + openMode = NativeMethods.STGM.CREATE | NativeMethods.STGM.READWRITE | NativeMethods.STGM.SHARE_EXCLUSIVE; + hr = NativeMethods.StgCreateDocfile(extractFile, (uint) openMode, 0, out newStorage); + if (hr != 0) + { + Marshal.ThrowExceptionForHR(hr); + } + + try + { + subStorage.CopyTo(0, IntPtr.Zero, IntPtr.Zero, newStorage); + + newStorage.Commit(0); + } + finally + { + Marshal.ReleaseComObject(newStorage); + } + } + finally + { + Marshal.ReleaseComObject(subStorage); + } + } + finally + { + Marshal.ReleaseComObject(storage); + } + } + + private int FindColumn(string fieldName) + { + if (this.view == null) + { + throw new InvalidOperationException(); + } + ColumnCollection columns = this.view.Columns; + for (int i = 0; i < columns.Count; i++) + { + if (columns[i].Name == fieldName) + { + return i + 1; + } + } + throw new ArgumentOutOfRangeException("fieldName"); + } + + private void CheckRange(int field) + { + if (field < 0 || field > this.FieldCount) + { + throw new ArgumentOutOfRangeException("field"); + } + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/RecordStream.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/RecordStream.cs new file mode 100644 index 00000000..82e8fb46 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/RecordStream.cs @@ -0,0 +1,92 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.IO; + + internal class RecordStream : Stream + { + private Record record; + private int field; + private long position; + + internal RecordStream(Record record, int field) + : base() + { + this.record = record; + this.field = field; + } + + public override bool CanRead { get { return true; } } + public override bool CanWrite { get { return false; } } + public override bool CanSeek { get { return false; } } + + public override long Length + { + get + { + return this.record.GetDataSize(this.field); + } + } + + public override long Position + { + get + { + return this.position; + } + + set + { + throw new NotSupportedException(); + } + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (count > 0) + { + byte[] readBuffer = (offset == 0 ? buffer : new byte[count]); + uint ucount = (uint) count; + uint ret = RemotableNativeMethods.MsiRecordReadStream((int) this.record.Handle, (uint) this.field, buffer, ref ucount); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + count = (int) ucount; + if (offset > 0) + { + Array.Copy(readBuffer, 0, buffer, offset, count); + } + this.position += count; + } + return count; + } + + public override void Write(byte[] array, int offset, int count) + { + throw new NotSupportedException(); + } + + public override string ToString() + { + return "[Binary data]"; + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/RemotableNativeMethods.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/RemotableNativeMethods.cs new file mode 100644 index 00000000..960fd15f --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/RemotableNativeMethods.cs @@ -0,0 +1,1171 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.Text; + using System.Runtime.InteropServices; + using System.Diagnostics.CodeAnalysis; + + /// + /// Assigns ID numbers to the MSI APIs that are remotable. + /// + ///+ internal enum RemoteMsiFunctionId + { + EndSession = 0, + MsiCloseHandle, + MsiCreateRecord, + MsiDatabaseGetPrimaryKeys, + MsiDatabaseIsTablePersistent, + MsiDatabaseOpenView, + MsiDoAction, + MsiEnumComponentCosts, + MsiEvaluateCondition, + MsiFormatRecord, + MsiGetActiveDatabase, + MsiGetComponentState, + MsiGetFeatureCost, + MsiGetFeatureState, + MsiGetFeatureValidStates, + MsiGetLanguage, + MsiGetLastErrorRecord, + MsiGetMode, + MsiGetProperty, + MsiGetSourcePath, + MsiGetSummaryInformation, + MsiGetTargetPath, + MsiProcessMessage, + MsiRecordClearData, + MsiRecordDataSize, + MsiRecordGetFieldCount, + MsiRecordGetInteger, + MsiRecordGetString, + MsiRecordIsNull, + MsiRecordReadStream, + MsiRecordSetInteger, + MsiRecordSetStream, + MsiRecordSetString, + MsiSequence, + MsiSetComponentState, + MsiSetFeatureAttributes, + MsiSetFeatureState, + MsiSetInstallLevel, + MsiSetMode, + MsiSetProperty, + MsiSetTargetPath, + MsiSummaryInfoGetProperty, + MsiVerifyDiskSpace, + MsiViewExecute, + MsiViewFetch, + MsiViewGetError, + MsiViewGetColumnInfo, + MsiViewModify, + } + + /// + /// This enumeration MUST stay in sync with the + /// unmanaged equivalent in RemoteMsiSession.h! + ///
+ /// Defines the signature of the native function + /// in SfxCA.dll that implements the remoting call. + /// + internal delegate void MsiRemoteInvoke( + RemoteMsiFunctionId id, + [MarshalAs(UnmanagedType.SysInt)] + IntPtr request, + [MarshalAs(UnmanagedType.SysInt)] + out IntPtr response); + + ///+ /// Redirects native API calls to either the normal NativeMethods class + /// or to out-of-proc calls via the remoting channel. + /// + internal static class RemotableNativeMethods + { + private const int MAX_REQUEST_FIELDS = 4; + private static int requestFieldDataOffset; + private static int requestFieldSize; + + [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] + private static IntPtr requestBuf; + + private static MsiRemoteInvoke remotingDelegate; + + ///+ /// Checks if the current process is using remoting to access the + /// MSI session and database APIs. + /// + internal static bool RemotingEnabled + { + get + { + return RemotableNativeMethods.remotingDelegate != null; + } + } + + ///+ /// Sets a delegate that is used to make remote API calls. + /// + ///+ [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal static MsiRemoteInvoke RemotingDelegate + { + set + { + RemotableNativeMethods.remotingDelegate = value; + + if (value != null && requestBuf == IntPtr.Zero) + { + requestFieldDataOffset = Marshal.SizeOf(typeof(IntPtr)); + requestFieldSize = 2 * Marshal.SizeOf(typeof(IntPtr)); + RemotableNativeMethods.requestBuf = Marshal.AllocHGlobal( + requestFieldSize * MAX_REQUEST_FIELDS); + } + } + } + + internal static bool IsRemoteHandle(int handle) + { + return (handle & Int32.MinValue) != 0; + } + + internal static int MakeRemoteHandle(int handle) + { + if (handle == 0) + { + return handle; + } + + if (RemotableNativeMethods.IsRemoteHandle(handle)) + { + throw new InvalidOperationException("Handle already has the remote bit set."); + } + + return handle ^ Int32.MinValue; + } + + internal static int GetRemoteHandle(int handle) + { + if (handle == 0) + { + return handle; + } + + if (!RemotableNativeMethods.IsRemoteHandle(handle)) + { + throw new InvalidOperationException("Handle does not have the remote bit set."); + } + + return handle ^ Int32.MinValue; + } + + private static void ClearData(IntPtr buf) + { + for (int i = 0; i < MAX_REQUEST_FIELDS; i++) + { + Marshal.WriteInt32(buf, (i * requestFieldSize), (int) VarEnum.VT_NULL); + Marshal.WriteIntPtr(buf, (i * requestFieldSize) + requestFieldDataOffset, IntPtr.Zero); + } + } + + private static void WriteInt(IntPtr buf, int field, int value) + { + Marshal.WriteInt32(buf, (field * requestFieldSize), (int) VarEnum.VT_I4); + Marshal.WriteInt32(buf, (field * requestFieldSize) + requestFieldDataOffset, value); + } + + private static void WriteString(IntPtr buf, int field, string value) + { + if (value == null) + { + Marshal.WriteInt32(buf, (field * requestFieldSize), (int) VarEnum.VT_NULL); + Marshal.WriteIntPtr(buf, (field * requestFieldSize) + requestFieldDataOffset, IntPtr.Zero); + } + else + { + IntPtr stringPtr = Marshal.StringToHGlobalUni(value); + Marshal.WriteInt32(buf, (field * requestFieldSize), (int) VarEnum.VT_LPWSTR); + Marshal.WriteIntPtr(buf, (field * requestFieldSize) + requestFieldDataOffset, stringPtr); + } + } + + private static int ReadInt(IntPtr buf, int field) + { + VarEnum vt = (VarEnum) Marshal.ReadInt32(buf, (field * requestFieldSize)); + if (vt == VarEnum.VT_EMPTY) + { + return 0; + } + else if (vt != VarEnum.VT_I4 && vt != VarEnum.VT_UI4) + { + throw new InstallerException("Invalid data received from remote MSI function invocation."); + } + return Marshal.ReadInt32(buf, (field * requestFieldSize) + requestFieldDataOffset); + } + + private static void ReadString(IntPtr buf, int field, StringBuilder szBuf, ref uint cchBuf) + { + VarEnum vt = (VarEnum) Marshal.ReadInt32(buf, (field * requestFieldSize)); + if (vt == VarEnum.VT_NULL) + { + szBuf.Remove(0, szBuf.Length); + return; + } + else if (vt != VarEnum.VT_LPWSTR) + { + throw new InstallerException("Invalid data received from remote MSI function invocation."); + } + + szBuf.Remove(0, szBuf.Length); + IntPtr strPtr = Marshal.ReadIntPtr(buf, (field * requestFieldSize) + requestFieldDataOffset); + string str = Marshal.PtrToStringUni(strPtr); + if (str != null) + { + szBuf.Append(str); + } + cchBuf = (uint) szBuf.Length; + } + + private static void FreeString(IntPtr buf, int field) + { + IntPtr stringPtr = Marshal.ReadIntPtr(buf, (field * requestFieldSize) + requestFieldDataOffset); + if (stringPtr != IntPtr.Zero) + { + Marshal.FreeHGlobal(stringPtr); + } + } + + private static void ReadStream(IntPtr buf, int field, byte[] sBuf, int count) + { + VarEnum vt = (VarEnum) Marshal.ReadInt32(buf, (field * requestFieldSize)); + if (vt != VarEnum.VT_STREAM) + { + throw new InstallerException("Invalid data received from remote MSI function invocation."); + } + + IntPtr sPtr = Marshal.ReadIntPtr(buf, (field * requestFieldSize) + requestFieldDataOffset); + Marshal.Copy(sPtr, sBuf, 0, count); + } + + private static uint MsiFunc_III(RemoteMsiFunctionId id, int in1, int in2, int in3) + { + lock (RemotableNativeMethods.remotingDelegate) + { + ClearData(requestBuf); + WriteInt(requestBuf, 0, in1); + WriteInt(requestBuf, 1, in2); + WriteInt(requestBuf, 2, in3); + IntPtr resp; + remotingDelegate(id, requestBuf, out resp); + return unchecked ((uint) ReadInt(resp, 0)); + } + } + + private static uint MsiFunc_IIS(RemoteMsiFunctionId id, int in1, int in2, string in3) + { + lock (RemotableNativeMethods.remotingDelegate) + { + ClearData(requestBuf); + WriteInt(requestBuf, 0, in1); + WriteInt(requestBuf, 1, in2); + WriteString(requestBuf, 2, in3); + IntPtr resp; + remotingDelegate(id, requestBuf, out resp); + FreeString(requestBuf, 2); + return unchecked ((uint) ReadInt(resp, 0)); + } + } + + private static uint MsiFunc_ISI(RemoteMsiFunctionId id, int in1, string in2, int in3) + { + lock (RemotableNativeMethods.remotingDelegate) + { + ClearData(requestBuf); + WriteInt(requestBuf, 0, in1); + WriteString(requestBuf, 1, in2); + WriteInt(requestBuf, 2, in3); + IntPtr resp; + remotingDelegate(id, requestBuf, out resp); + FreeString(requestBuf, 2); + return unchecked ((uint) ReadInt(resp, 0)); + } + } + + private static uint MsiFunc_ISS(RemoteMsiFunctionId id, int in1, string in2, string in3) + { + lock (RemotableNativeMethods.remotingDelegate) + { + ClearData(requestBuf); + WriteInt(requestBuf, 0, in1); + WriteString(requestBuf, 1, in2); + WriteString(requestBuf, 2, in3); + IntPtr resp; + remotingDelegate(id, requestBuf, out resp); + FreeString(requestBuf, 1); + FreeString(requestBuf, 2); + return unchecked ((uint) ReadInt(resp, 0)); + } + } + + private static uint MsiFunc_II_I(RemoteMsiFunctionId id, int in1, int in2, out int out1) + { + lock (RemotableNativeMethods.remotingDelegate) + { + ClearData(requestBuf); + WriteInt(requestBuf, 0, in1); + WriteInt(requestBuf, 1, in2); + IntPtr resp; + remotingDelegate(id, requestBuf, out resp); + uint ret = unchecked ((uint) ReadInt(resp, 0)); + out1 = ReadInt(resp, 1); + return ret; + } + } + + private static uint MsiFunc_ISII_I(RemoteMsiFunctionId id, int in1, string in2, int in3, int in4, out int out1) + { + lock (RemotableNativeMethods.remotingDelegate) + { + ClearData(requestBuf); + WriteInt(requestBuf, 0, in1); + WriteString(requestBuf, 1, in2); + WriteInt(requestBuf, 2, in3); + WriteInt(requestBuf, 3, in4); + IntPtr resp; + remotingDelegate(id, requestBuf, out resp); + FreeString(requestBuf, 1); + uint ret = unchecked ((uint) ReadInt(resp, 0)); + out1 = ReadInt(resp, 1); + return ret; + } + } + + private static uint MsiFunc_IS_II(RemoteMsiFunctionId id, int in1, string in2, out int out1, out int out2) + { + lock (RemotableNativeMethods.remotingDelegate) + { + ClearData(requestBuf); + WriteInt(requestBuf, 0, in1); + WriteString(requestBuf, 1, in2); + IntPtr resp; + remotingDelegate(id, requestBuf, out resp); + FreeString(requestBuf, 1); + uint ret = unchecked ((uint) ReadInt(resp, 0)); + out1 = ReadInt(resp, 1); + out2 = ReadInt(resp, 2); + return ret; + } + } + + private static uint MsiFunc_II_S(RemoteMsiFunctionId id, int in1, int in2, StringBuilder out1, ref uint cchOut1) + { + lock (RemotableNativeMethods.remotingDelegate) + { + ClearData(requestBuf); + WriteInt(requestBuf, 0, in1); + WriteInt(requestBuf, 1, in2); + IntPtr resp; + remotingDelegate(id, requestBuf, out resp); + uint ret = unchecked ((uint) ReadInt(resp, 0)); + if (ret == 0) ReadString(resp, 1, out1, ref cchOut1); + return ret; + } + } + + private static uint MsiFunc_IS_S(RemoteMsiFunctionId id, int in1, string in2, StringBuilder out1, ref uint cchOut1) + { + lock (RemotableNativeMethods.remotingDelegate) + { + ClearData(requestBuf); + WriteInt(requestBuf, 0, in1); + WriteString(requestBuf, 1, in2); + IntPtr resp; + remotingDelegate(id, requestBuf, out resp); + FreeString(requestBuf, 1); + uint ret = unchecked ((uint) ReadInt(resp, 0)); + if (ret == 0) ReadString(resp, 1, out1, ref cchOut1); + return ret; + } + } + + private static uint MsiFunc_ISII_SII(RemoteMsiFunctionId id, int in1, string in2, int in3, int in4, StringBuilder out1, ref uint cchOut1, out int out2, out int out3) + { + lock (RemotableNativeMethods.remotingDelegate) + { + ClearData(requestBuf); + WriteInt(requestBuf, 0, in1); + WriteString(requestBuf, 1, in2); + WriteInt(requestBuf, 2, in3); + WriteInt(requestBuf, 3, in4); + IntPtr resp; + remotingDelegate(id, requestBuf, out resp); + FreeString(requestBuf, 1); + uint ret = unchecked ((uint) ReadInt(resp, 0)); + if (ret == 0) ReadString(resp, 1, out1, ref cchOut1); + out2 = ReadInt(resp, 2); + out3 = ReadInt(resp, 3); + return ret; + } + } + + internal static int MsiProcessMessage(int hInstall, uint eMessageType, int hRecord) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + { + return NativeMethods.MsiProcessMessage(hInstall, eMessageType, hRecord); + } + else lock (remotingDelegate) + { + // I don't understand why, but this particular function doesn't work + // when using the static requestBuf -- some data doesn't make it through. + // But it works when a fresh buffer is allocated here every call. + IntPtr buf = Marshal.AllocHGlobal( + requestFieldSize * MAX_REQUEST_FIELDS); + ClearData(buf); + WriteInt(buf, 0, RemotableNativeMethods.GetRemoteHandle(hInstall)); + WriteInt(buf, 1, unchecked ((int) eMessageType)); + WriteInt(buf, 2, RemotableNativeMethods.GetRemoteHandle(hRecord)); + IntPtr resp; + remotingDelegate(RemoteMsiFunctionId.MsiProcessMessage, buf, out resp); + Marshal.FreeHGlobal(buf); + return ReadInt(resp, 0); + } + } + + internal static uint MsiCloseHandle(int hAny) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hAny)) + return NativeMethods.MsiCloseHandle(hAny); + else + return RemotableNativeMethods.MsiFunc_III( + RemoteMsiFunctionId.MsiCloseHandle, RemotableNativeMethods.GetRemoteHandle(hAny), 0, 0); + } + + internal static uint MsiGetProperty(int hInstall, string szName, StringBuilder szValueBuf, ref uint cchValueBuf) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiGetProperty(hInstall, szName, szValueBuf, ref cchValueBuf); + else + { + return RemotableNativeMethods.MsiFunc_IS_S( + RemoteMsiFunctionId.MsiGetProperty, + RemotableNativeMethods.GetRemoteHandle(hInstall), + szName, + szValueBuf, + ref cchValueBuf); + } + } + + internal static uint MsiSetProperty(int hInstall, string szName, string szValue) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiSetProperty(hInstall, szName, szValue); + else + { + return RemotableNativeMethods.MsiFunc_ISS( + RemoteMsiFunctionId.MsiSetProperty, + RemotableNativeMethods.GetRemoteHandle(hInstall), + szName, + szValue); + } + } + + internal static int MsiCreateRecord(uint cParams, int hAny) + { + // When remoting is enabled, we might need to create either a local or + // remote record, depending on the handle it is to have an affinity with. + // If no affinity handle is specified, create a remote record (the 99% case). + if (!RemotingEnabled || + (hAny != 0 && !RemotableNativeMethods.IsRemoteHandle(hAny))) + { + return NativeMethods.MsiCreateRecord(cParams); + } + else + { + int hRecord = unchecked((int)RemotableNativeMethods.MsiFunc_III( + RemoteMsiFunctionId.MsiCreateRecord, (int) cParams, 0, 0)); + return RemotableNativeMethods.MakeRemoteHandle(hRecord); + } + } + + internal static uint MsiRecordGetFieldCount(int hRecord) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hRecord)) + return NativeMethods.MsiRecordGetFieldCount(hRecord); + else + { + return RemotableNativeMethods.MsiFunc_III( + RemoteMsiFunctionId.MsiRecordGetFieldCount, + RemotableNativeMethods.GetRemoteHandle(hRecord), + 0, + 0); + } + } + + internal static int MsiRecordGetInteger(int hRecord, uint iField) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hRecord)) + return NativeMethods.MsiRecordGetInteger(hRecord, iField); + else + { + return unchecked ((int) RemotableNativeMethods.MsiFunc_III( + RemoteMsiFunctionId.MsiRecordGetInteger, + RemotableNativeMethods.GetRemoteHandle(hRecord), + (int) iField, + 0)); + } + } + + internal static uint MsiRecordGetString(int hRecord, uint iField, StringBuilder szValueBuf, ref uint cchValueBuf) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hRecord)) + { + return NativeMethods.MsiRecordGetString(hRecord, iField, szValueBuf, ref cchValueBuf); + } + else + { + return RemotableNativeMethods.MsiFunc_II_S( + RemoteMsiFunctionId.MsiRecordGetString, + RemotableNativeMethods.GetRemoteHandle(hRecord), + (int) iField, + szValueBuf, + ref cchValueBuf); + } + } + + internal static uint MsiRecordSetInteger(int hRecord, uint iField, int iValue) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hRecord)) + return NativeMethods.MsiRecordSetInteger(hRecord, iField, iValue); + else + { + return RemotableNativeMethods.MsiFunc_III( + RemoteMsiFunctionId.MsiRecordSetInteger, + RemotableNativeMethods.GetRemoteHandle(hRecord), + (int) iField, + iValue); + } + } + + internal static uint MsiRecordSetString(int hRecord, uint iField, string szValue) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hRecord)) + return NativeMethods.MsiRecordSetString(hRecord, iField, szValue); + else + { + return RemotableNativeMethods.MsiFunc_IIS( + RemoteMsiFunctionId.MsiRecordSetString, + RemotableNativeMethods.GetRemoteHandle(hRecord), + (int) iField, + szValue); + } + } + + internal static int MsiGetActiveDatabase(int hInstall) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiGetActiveDatabase(hInstall); + else + { + int hDatabase = (int)RemotableNativeMethods.MsiFunc_III( + RemoteMsiFunctionId.MsiGetActiveDatabase, + RemotableNativeMethods.GetRemoteHandle(hInstall), + 0, + 0); + return RemotableNativeMethods.MakeRemoteHandle(hDatabase); + } + } + + internal static uint MsiDatabaseOpenView(int hDatabase, string szQuery, out int hView) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hDatabase)) + return NativeMethods.MsiDatabaseOpenView(hDatabase, szQuery, out hView); + else + { + uint err = RemotableNativeMethods.MsiFunc_ISII_I( + RemoteMsiFunctionId.MsiDatabaseOpenView, + RemotableNativeMethods.GetRemoteHandle(hDatabase), + szQuery, + 0, + 0, + out hView); + hView = RemotableNativeMethods.MakeRemoteHandle(hView); + return err; + } + } + + internal static uint MsiViewExecute(int hView, int hRecord) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hView)) + return NativeMethods.MsiViewExecute(hView, hRecord); + else + { + return RemotableNativeMethods.MsiFunc_III( + RemoteMsiFunctionId.MsiViewExecute, + RemotableNativeMethods.GetRemoteHandle(hView), + RemotableNativeMethods.GetRemoteHandle(hRecord), + 0); + } + } + + internal static uint MsiViewFetch(int hView, out int hRecord) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hView)) + return NativeMethods.MsiViewFetch(hView, out hRecord); + else + { + uint err = RemotableNativeMethods.MsiFunc_II_I( + RemoteMsiFunctionId.MsiViewFetch, + RemotableNativeMethods.GetRemoteHandle(hView), + 0, + out hRecord); + hRecord = RemotableNativeMethods.MakeRemoteHandle(hRecord); + return err; + } + } + + internal static uint MsiViewModify(int hView, int iModifyMode, int hRecord) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hView)) + return NativeMethods.MsiViewModify(hView, iModifyMode, hRecord); + else + { + return RemotableNativeMethods.MsiFunc_III( + RemoteMsiFunctionId.MsiViewModify, + RemotableNativeMethods.GetRemoteHandle(hView), + iModifyMode, + RemotableNativeMethods.GetRemoteHandle(hRecord)); + } + } + + internal static int MsiViewGetError(int hView, StringBuilder szColumnNameBuffer, ref uint cchBuf) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hView)) + return NativeMethods.MsiViewGetError(hView, szColumnNameBuffer, ref cchBuf); + else + { + return unchecked ((int) RemotableNativeMethods.MsiFunc_II_S( + RemoteMsiFunctionId.MsiViewGetError, + RemotableNativeMethods.GetRemoteHandle(hView), + 0, + szColumnNameBuffer, + ref cchBuf)); + } + } + + internal static uint MsiViewGetColumnInfo(int hView, uint eColumnInfo, out int hRecord) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hView)) + return NativeMethods.MsiViewGetColumnInfo(hView, eColumnInfo, out hRecord); + else + { + uint err = RemotableNativeMethods.MsiFunc_II_I( + RemoteMsiFunctionId.MsiViewGetColumnInfo, + RemotableNativeMethods.GetRemoteHandle(hView), + (int) eColumnInfo, + out hRecord); + hRecord = RemotableNativeMethods.MakeRemoteHandle(hRecord); + return err; + } + } + + internal static uint MsiFormatRecord(int hInstall, int hRecord, StringBuilder szResultBuf, ref uint cchResultBuf) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hRecord)) + return NativeMethods.MsiFormatRecord(hInstall, hRecord, szResultBuf, ref cchResultBuf); + else + { + return RemotableNativeMethods.MsiFunc_II_S( + RemoteMsiFunctionId.MsiFormatRecord, + RemotableNativeMethods.GetRemoteHandle(hInstall), + RemotableNativeMethods.GetRemoteHandle(hRecord), + szResultBuf, + ref cchResultBuf); + } + } + + internal static uint MsiRecordClearData(int hRecord) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hRecord)) + return NativeMethods.MsiRecordClearData(hRecord); + else + { + return RemotableNativeMethods.MsiFunc_III( + RemoteMsiFunctionId.MsiRecordClearData, + RemotableNativeMethods.GetRemoteHandle(hRecord), + 0, + 0); + } + } + + internal static bool MsiRecordIsNull(int hRecord, uint iField) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hRecord)) + return NativeMethods.MsiRecordIsNull(hRecord, iField); + else + { + return 0 != RemotableNativeMethods.MsiFunc_III( + RemoteMsiFunctionId.MsiRecordIsNull, + RemotableNativeMethods.GetRemoteHandle(hRecord), + (int) iField, + 0); + } + } + + internal static uint MsiDatabaseGetPrimaryKeys(int hDatabase, string szTableName, out int hRecord) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hDatabase)) + return NativeMethods.MsiDatabaseGetPrimaryKeys(hDatabase, szTableName, out hRecord); + else + { + uint err = RemotableNativeMethods.MsiFunc_ISII_I( + RemoteMsiFunctionId.MsiDatabaseGetPrimaryKeys, + RemotableNativeMethods.GetRemoteHandle(hDatabase), + szTableName, + 0, + 0, + out hRecord); + hRecord = RemotableNativeMethods.MakeRemoteHandle(hRecord); + return err; + } + } + + internal static uint MsiDatabaseIsTablePersistent(int hDatabase, string szTableName) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hDatabase)) + return NativeMethods.MsiDatabaseIsTablePersistent(hDatabase, szTableName); + else + { + return RemotableNativeMethods.MsiFunc_ISI( + RemoteMsiFunctionId.MsiDatabaseIsTablePersistent, + RemotableNativeMethods.GetRemoteHandle(hDatabase), + szTableName, + 0); + } + } + + internal static uint MsiDoAction(int hInstall, string szAction) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiDoAction(hInstall, szAction); + else + { + return RemotableNativeMethods.MsiFunc_ISI( + RemoteMsiFunctionId.MsiDoAction, + RemotableNativeMethods.GetRemoteHandle(hInstall), + szAction, + 0); + } + } + + internal static uint MsiEnumComponentCosts(int hInstall, string szComponent, uint dwIndex, int iState, StringBuilder lpDriveBuf, ref uint cchDriveBuf, out int iCost, out int iTempCost) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiEnumComponentCosts(hInstall, szComponent, dwIndex, iState, lpDriveBuf, ref cchDriveBuf, out iCost, out iTempCost); + else + { + return RemotableNativeMethods.MsiFunc_ISII_SII( + RemoteMsiFunctionId.MsiEvaluateCondition, + RemotableNativeMethods.GetRemoteHandle(hInstall), + szComponent, (int) dwIndex, iState, lpDriveBuf, ref cchDriveBuf, out iCost, out iTempCost); + } + } + + internal static uint MsiEvaluateCondition(int hInstall, string szCondition) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiEvaluateCondition(hInstall, szCondition); + else + { + return RemotableNativeMethods.MsiFunc_ISI( + RemoteMsiFunctionId.MsiEvaluateCondition, + RemotableNativeMethods.GetRemoteHandle(hInstall), + szCondition, + 0); + } + } + + internal static uint MsiGetComponentState(int hInstall, string szComponent, out int iInstalled, out int iAction) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiGetComponentState(hInstall, szComponent, out iInstalled, out iAction); + else + { + return RemotableNativeMethods.MsiFunc_IS_II( + RemoteMsiFunctionId.MsiGetComponentState, + RemotableNativeMethods.GetRemoteHandle(hInstall), + szComponent, + out iInstalled, + out iAction); + } + } + + internal static uint MsiGetFeatureCost(int hInstall, string szFeature, int iCostTree, int iState, out int iCost) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiGetFeatureCost(hInstall, szFeature, iCostTree, iState, out iCost); + else + { + return RemotableNativeMethods.MsiFunc_ISII_I( + RemoteMsiFunctionId.MsiGetFeatureCost, + RemotableNativeMethods.GetRemoteHandle(hInstall), + szFeature, + iCostTree, + iState, + out iCost); + } + } + + internal static uint MsiGetFeatureState(int hInstall, string szFeature, out int iInstalled, out int iAction) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiGetFeatureState(hInstall, szFeature, out iInstalled, out iAction); + else + { + return RemotableNativeMethods.MsiFunc_IS_II( + RemoteMsiFunctionId.MsiGetFeatureState, + RemotableNativeMethods.GetRemoteHandle(hInstall), + szFeature, + out iInstalled, + out iAction); + } + } + + internal static uint MsiGetFeatureValidStates(int hInstall, string szFeature, out uint dwInstalledState) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiGetFeatureValidStates(hInstall, szFeature, out dwInstalledState); + else + { + int iTemp; + uint ret = RemotableNativeMethods.MsiFunc_ISII_I( + RemoteMsiFunctionId.MsiGetFeatureValidStates, + RemotableNativeMethods.GetRemoteHandle(hInstall), + szFeature, + 0, + 0, + out iTemp); + dwInstalledState = (uint) iTemp; + return ret; + } + } + + internal static int MsiGetLanguage(int hInstall) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiGetLanguage(hInstall); + else + { + return unchecked((int)RemotableNativeMethods.MsiFunc_III( + RemoteMsiFunctionId.MsiGetLanguage, + RemotableNativeMethods.GetRemoteHandle(hInstall), + 0, + 0)); + } + } + + internal static int MsiGetLastErrorRecord(int hAny) + { + // When remoting is enabled, we might need to create either a local or + // remote record, depending on the handle it is to have an affinity with. + // If no affinity handle is specified, create a remote record (the 99% case). + if (!RemotingEnabled || + (hAny != 0 && !RemotableNativeMethods.IsRemoteHandle(hAny))) + { + return NativeMethods.MsiGetLastErrorRecord(); + } + else + { + int hRecord = unchecked((int) RemotableNativeMethods.MsiFunc_III( + RemoteMsiFunctionId.MsiGetLastErrorRecord, 0, 0, 0)); + return RemotableNativeMethods.MakeRemoteHandle(hRecord); + } + } + + internal static bool MsiGetMode(int hInstall, uint iRunMode) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiGetMode(hInstall, iRunMode); + else + { + return 0 != RemotableNativeMethods.MsiFunc_III( + RemoteMsiFunctionId.MsiGetMode, + RemotableNativeMethods.GetRemoteHandle(hInstall), + (int) iRunMode, + 0); + } + } + + internal static uint MsiGetSourcePath(int hInstall, string szFolder, StringBuilder szPathBuf, ref uint cchPathBuf) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiGetSourcePath(hInstall, szFolder, szPathBuf, ref cchPathBuf); + else + { + return RemotableNativeMethods.MsiFunc_IS_S( + RemoteMsiFunctionId.MsiGetSourcePath, + RemotableNativeMethods.GetRemoteHandle(hInstall), + szFolder, + szPathBuf, + ref cchPathBuf); + } + } + + internal static uint MsiGetSummaryInformation(int hDatabase, string szDatabasePath, uint uiUpdateCount, out int hSummaryInfo) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hDatabase)) + return NativeMethods.MsiGetSummaryInformation(hDatabase, szDatabasePath, uiUpdateCount, out hSummaryInfo); + else + { + uint err = RemotableNativeMethods.MsiFunc_ISII_I( + RemoteMsiFunctionId.MsiGetSummaryInformation, + RemotableNativeMethods.GetRemoteHandle(hDatabase), + szDatabasePath, + (int)uiUpdateCount, + 0, + out hSummaryInfo); + hSummaryInfo = RemotableNativeMethods.MakeRemoteHandle(hSummaryInfo); + return err; + } + } + + internal static uint MsiGetTargetPath(int hInstall, string szFolder, StringBuilder szPathBuf, ref uint cchPathBuf) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiGetTargetPath(hInstall, szFolder, szPathBuf, ref cchPathBuf); + else + { + return RemotableNativeMethods.MsiFunc_IS_S( + RemoteMsiFunctionId.MsiGetTargetPath, + RemotableNativeMethods.GetRemoteHandle(hInstall), + szFolder, + szPathBuf, + ref cchPathBuf); + } + } + + internal static uint MsiRecordDataSize(int hRecord, uint iField) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hRecord)) + return NativeMethods.MsiRecordDataSize(hRecord, iField); + else + { + return RemotableNativeMethods.MsiFunc_III( + RemoteMsiFunctionId.MsiRecordDataSize, + RemotableNativeMethods.GetRemoteHandle(hRecord), + (int) iField, 0); + } + } + + internal static uint MsiRecordReadStream(int hRecord, uint iField, byte[] szDataBuf, ref uint cbDataBuf) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hRecord)) + { + return NativeMethods.MsiRecordReadStream(hRecord, iField, szDataBuf, ref cbDataBuf); + } + else lock (RemotableNativeMethods.remotingDelegate) + { + ClearData(requestBuf); + unchecked + { + WriteInt(requestBuf, 0, RemotableNativeMethods.GetRemoteHandle(hRecord)); + WriteInt(requestBuf, 1, (int) iField); + WriteInt(requestBuf, 2, (int) cbDataBuf); + IntPtr resp; + remotingDelegate(RemoteMsiFunctionId.MsiRecordReadStream, requestBuf, out resp); + uint ret = (uint) ReadInt(resp, 0); + if (ret == 0) + { + cbDataBuf = (uint) ReadInt(resp, 2); + if (cbDataBuf > 0) + { + RemotableNativeMethods.ReadStream(resp, 1, szDataBuf, (int) cbDataBuf); + } + } + return ret; + } + } + } + + internal static uint MsiRecordSetStream(int hRecord, uint iField, string szFilePath) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hRecord)) + return NativeMethods.MsiRecordSetStream(hRecord, iField, szFilePath); + else + { + return RemotableNativeMethods.MsiFunc_IIS( + RemoteMsiFunctionId.MsiRecordSetStream, + RemotableNativeMethods.GetRemoteHandle(hRecord), + (int) iField, + szFilePath); + } + } + + internal static uint MsiSequence(int hInstall, string szTable, int iSequenceMode) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiSequence(hInstall, szTable, iSequenceMode); + else + { + return RemotableNativeMethods.MsiFunc_ISI( + RemoteMsiFunctionId.MsiSequence, + RemotableNativeMethods.GetRemoteHandle(hInstall), + szTable, + iSequenceMode); + } + } + + internal static uint MsiSetComponentState(int hInstall, string szComponent, int iState) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiSetComponentState(hInstall, szComponent, iState); + else + { + return RemotableNativeMethods.MsiFunc_ISI( + RemoteMsiFunctionId.MsiSetComponentState, + RemotableNativeMethods.GetRemoteHandle(hInstall), + szComponent, + iState); + } + } + + internal static uint MsiSetFeatureAttributes(int hInstall, string szFeature, uint dwAttributes) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiSetFeatureAttributes(hInstall, szFeature, dwAttributes); + else + { + return RemotableNativeMethods.MsiFunc_ISI( + RemoteMsiFunctionId.MsiSetFeatureAttributes, + RemotableNativeMethods.GetRemoteHandle(hInstall), + szFeature, + (int) dwAttributes); + } + } + + internal static uint MsiSetFeatureState(int hInstall, string szFeature, int iState) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiSetFeatureState(hInstall, szFeature, iState); + else + { + return RemotableNativeMethods.MsiFunc_ISI( + RemoteMsiFunctionId.MsiSetFeatureState, + RemotableNativeMethods.GetRemoteHandle(hInstall), szFeature, iState); + } + } + + internal static uint MsiSetInstallLevel(int hInstall, int iInstallLevel) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiSetInstallLevel(hInstall, iInstallLevel); + else + { + return RemotableNativeMethods.MsiFunc_III( + RemoteMsiFunctionId.MsiSetInstallLevel, + RemotableNativeMethods.GetRemoteHandle(hInstall), + iInstallLevel, + 0); + } + } + + internal static uint MsiSetMode(int hInstall, uint iRunMode, bool fState) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiSetMode(hInstall, iRunMode, fState); + else + { + return RemotableNativeMethods.MsiFunc_III( + RemoteMsiFunctionId.MsiSetMode, + RemotableNativeMethods.GetRemoteHandle(hInstall), + (int) iRunMode, + fState ? 1 : 0); + } + } + + internal static uint MsiSetTargetPath(int hInstall, string szFolder, string szFolderPath) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiSetTargetPath(hInstall, szFolder, szFolderPath); + else + { + return RemotableNativeMethods.MsiFunc_ISS( + RemoteMsiFunctionId.MsiSetTargetPath, + RemotableNativeMethods.GetRemoteHandle(hInstall), + szFolder, + szFolderPath); + } + } + + internal static uint MsiSummaryInfoGetProperty(int hSummaryInfo, uint uiProperty, out uint uiDataType, out int iValue, ref long ftValue, StringBuilder szValueBuf, ref uint cchValueBuf) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hSummaryInfo)) + { + return NativeMethods.MsiSummaryInfoGetProperty(hSummaryInfo, uiProperty, out uiDataType, out iValue, ref ftValue, szValueBuf, ref cchValueBuf); + } + else lock (RemotableNativeMethods.remotingDelegate) + { + ClearData(requestBuf); + WriteInt(requestBuf, 0, RemotableNativeMethods.GetRemoteHandle(hSummaryInfo)); + WriteInt(requestBuf, 1, (int) uiProperty); + IntPtr resp; + remotingDelegate(RemoteMsiFunctionId.MsiSummaryInfoGetProperty, requestBuf, out resp); + unchecked + { + uint ret = (uint) ReadInt(resp, 0); + if (ret == 0) + { + uiDataType = (uint) ReadInt(resp, 1); + switch ((VarEnum) uiDataType) + { + case VarEnum.VT_I2: + case VarEnum.VT_I4: + iValue = ReadInt(resp, 2); + break; + + case VarEnum.VT_FILETIME: + uint ftHigh = (uint) ReadInt(resp, 2); + uint ftLow = (uint) ReadInt(resp, 3); + ftValue = ((long) ftHigh) << 32 | ((long) ftLow); + iValue = 0; + break; + + case VarEnum.VT_LPSTR: + ReadString(resp, 2, szValueBuf, ref cchValueBuf); + iValue = 0; + break; + + default: + iValue = 0; + break; + } + } + else + { + uiDataType = 0; + iValue = 0; + } + return ret; + } + } + } + + internal static uint MsiVerifyDiskSpace(int hInstall) + { + if (!RemotingEnabled || !RemotableNativeMethods.IsRemoteHandle(hInstall)) + return NativeMethods.MsiVerifyDiskSpace(hInstall); + else + { + return RemotableNativeMethods.MsiFunc_III( + RemoteMsiFunctionId.MsiVerifyDiskSpace, + RemotableNativeMethods.GetRemoteHandle(hInstall), + 0, + 0); + } + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Session.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Session.cs new file mode 100644 index 00000000..875e49a6 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Session.cs @@ -0,0 +1,946 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.Text; + using System.Collections.Generic; + using System.Globalization; + using System.Runtime.InteropServices; + using System.Diagnostics.CodeAnalysis; + + /// + /// The implementation of this delegate is provided by the + /// custom action host DLL. + ///
+ /// The Session object controls the installation process. It opens the + /// install database, which contains the installation tables and data. + /// + ///+ public sealed class Session : InstallerHandle, IFormatProvider + { + private Database database; + private CustomActionData customActionData; + private bool sessionAccessValidated = false; + + internal Session(IntPtr handle, bool ownsHandle) + : base(handle, ownsHandle) + { + } + + /// + /// This object is associated with a standard set of action functions, + /// each performing particular operations on data from one or more tables. Additional + /// custom actions may be added for particular product installations. The basic engine + /// function is a sequencer that fetches sequential records from a designated sequence + /// table, evaluates any specified condition expression, and executes the designated + /// action. Actions not recognized by the engine are deferred to the UI handler object + /// for processing, usually dialog box sequences. + ///
+ /// Note that only one Session object can be opened by a single process. + ///
+ /// Gets the Database for the install session. + /// + ///the Session handle is invalid + ///the Database cannot be accessed + ///+ [SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")] + public Database Database + { + get + { + if (this.database == null || this.database.IsClosed) + { + lock (this.Sync) + { + if (this.database == null || this.database.IsClosed) + { + this.ValidateSessionAccess(); + + int hDb = RemotableNativeMethods.MsiGetActiveDatabase((int) this.Handle); + if (hDb == 0) + { + throw new InstallerException(); + } + this.database = new Database((IntPtr) hDb, true, "", DatabaseOpenMode.ReadOnly); + } + } + } + return this.database; + } + } + + /// + /// Normally there is no need to close this Database object. The same object can be + /// used throughout the lifetime of the Session, and it will be closed when the Session + /// is closed. + ///
+ /// Win32 MSI API: + /// MsiGetActiveDatabase + ///
+ /// Gets the numeric language ID used by the current install session. + /// + ///+ public int Language + { + get + { + return (int) RemotableNativeMethods.MsiGetLanguage((int) this.Handle); + } + } + + /// + /// Win32 MSI API: + /// MsiGetLanguage + ///
+ /// Gets or sets the string value of a named installer property, as maintained by the + /// Session object in the in-memory Property table, or, if it is prefixed with a percent + /// sign (%), the value of a system environment variable for the current process. + /// + ///the Session handle is invalid + ///+ public string this[string property] + { + get + { + if (String.IsNullOrEmpty(property)) + { + throw new ArgumentNullException("property"); + } + + if (!this.sessionAccessValidated && + !Session.NonImmediatePropertyNames.Contains(property)) + { + this.ValidateSessionAccess(); + } + + StringBuilder buf = new StringBuilder(); + uint bufSize = 0; + uint ret = RemotableNativeMethods.MsiGetProperty((int) this.Handle, property, buf, ref bufSize); + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + buf.Capacity = (int) ++bufSize; + ret = RemotableNativeMethods.MsiGetProperty((int) this.Handle, property, buf, ref bufSize); + } + + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + return buf.ToString(); + } + + set + { + if (String.IsNullOrEmpty(property)) + { + throw new ArgumentNullException("property"); + } + + this.ValidateSessionAccess(); + + if (value == null) + { + value = String.Empty; + } + + uint ret = RemotableNativeMethods.MsiSetProperty((int) this.Handle, property, value); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + } + + /// + /// Win32 MSI APIs: + /// MsiGetProperty, + /// MsiSetProperty + ///
+ /// Creates a new Session object from an integer session handle. + /// + /// Integer session handle + /// true to close the handle when this object is disposed or finalized + ///+ public static Session FromHandle(IntPtr handle, bool ownsHandle) + { + return new Session(handle, ownsHandle); + } + + /// + /// This method is only provided for interop purposes. A Session object + /// should normally be obtained by calling
+ /// or . + /// + /// Performs any enabled logging operations and defers execution to the UI handler + /// object associated with the engine. + /// + /// Type of message to be processed + /// Contains message-specific fields + ///A message-dependent return value + ///the Session or Record handle is invalid + ///an invalid message kind is specified + ///the user exited the installation + ///the message-handler failed for an unknown reason + ///+ [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public MessageResult Message(InstallMessage messageType, Record record) + { + if (record == null) + { + throw new ArgumentNullException("record"); + } + + int ret = RemotableNativeMethods.MsiProcessMessage((int) this.Handle, (uint) messageType, (int) record.Handle); + if (ret < 0) + { + throw new InstallerException(); + } + else if (ret == (int) MessageResult.Cancel) + { + throw new InstallCanceledException(); + } + return (MessageResult) ret; + } + + /// + /// Logging may be selectively enabled for the various message types. + /// See the
method. + /// + /// If record field 0 contains a formatting string, it is used to format the data in + /// the other fields. Else if the message is an error, warning, or user message, an attempt + /// is made to find a message template in the Error table for the current database using the + /// error number found in field 1 of the record for message types and return values. + ///
+ /// The
parameter may also include message-box flags from + /// the following enumerations: System.Windows.Forms.MessageBoxButtons, + /// System.Windows.Forms.MessageBoxDefaultButton, System.Windows.Forms.MessageBoxIcon. These + /// flags can be combined with the InstallMessage with a bitwise OR. + /// + /// Note, this method never returns Cancel or Error values. Instead, appropriate + /// exceptions are thrown in those cases. + ///
+ /// Win32 MSI API: + /// MsiProcessMessage + ///
+ /// Writes a message to the log, if logging is enabled. + /// + /// The line to be written to the log + ///+ public void Log(string msg) + { + if (msg == null) + { + throw new ArgumentNullException("msg"); + } + + using (Record rec = new Record(0)) + { + rec.FormatString = msg; + this.Message(InstallMessage.Info, rec); + } + } + + /// + /// Win32 MSI API: + /// MsiProcessMessage + ///
+ /// Writes a formatted message to the log, if logging is enabled. + /// + /// The line to be written to the log, containing 0 or more format specifiers + /// An array containing 0 or more objects to be formatted + ///+ public void Log(string format, params object[] args) + { + this.Log(String.Format(CultureInfo.InvariantCulture, format, args)); + } + + /// + /// Win32 MSI API: + /// MsiProcessMessage + ///
+ /// Evaluates a logical expression containing symbols and values. + /// + /// conditional expression + ///The result of the condition evaluation + ///the Session handle is invalid + ///the condition is null or empty + ///the conditional expression is invalid + ///+ public bool EvaluateCondition(string condition) + { + if (String.IsNullOrEmpty(condition)) + { + throw new ArgumentNullException("condition"); + } + + uint value = RemotableNativeMethods.MsiEvaluateCondition((int) this.Handle, condition); + if (value == 0) + { + return false; + } + else if (value == 1) + { + return true; + } + else + { + throw new InvalidOperationException(); + } + } + + /// + /// Win32 MSI API: + /// MsiEvaluateCondition + ///
+ /// Evaluates a logical expression containing symbols and values, specifying a default + /// value to be returned in case the condition is empty. + /// + /// conditional expression + /// value to return if the condition is empty + ///The result of the condition evaluation + ///the Session handle is invalid + ///the conditional expression is invalid + ///+ public bool EvaluateCondition(string condition, bool defaultValue) + { + if (condition == null) + { + throw new ArgumentNullException("condition"); + } + else if (condition.Length == 0) + { + return defaultValue; + } + else + { + this.ValidateSessionAccess(); + return this.EvaluateCondition(condition); + } + } + + /// + /// Win32 MSI API: + /// MsiEvaluateCondition + ///
+ /// Formats a string containing installer properties. + /// + /// A format string containing property tokens + ///A formatted string containing property data + ///the Record handle is invalid + ///+ [SuppressMessage("Microsoft.Naming", "CA1719:ParameterNamesShouldNotMatchMemberNames")] + public string Format(string format) + { + if (format == null) + { + throw new ArgumentNullException("format"); + } + + using (Record formatRec = new Record(0)) + { + formatRec.FormatString = format; + return formatRec.ToString(this); + } + } + + /// + /// Win32 MSI API: + /// MsiFormatRecord + ///
+ /// Returns a formatted string from record data. + /// + /// Record object containing a template and data to be formatted. + /// The template string must be set in field 0 followed by any referenced data parameters. + ///A formatted string containing the record data + ///the Record handle is invalid + ///+ public string FormatRecord(Record record) + { + if (record == null) + { + throw new ArgumentNullException("record"); + } + + return record.ToString(this); + } + + /// + /// Win32 MSI API: + /// MsiFormatRecord + ///
+ /// Returns a formatted string from record data using a specified format. + /// + /// Record object containing a template and data to be formatted + /// Format string to be used instead of field 0 of the Record + ///A formatted string containing the record data + ///the Record handle is invalid + ///+ [Obsolete("This method is obsolete because it has undesirable side-effects. As an alternative, set the Record's " + + "FormatString property separately before calling the FormatRecord() override that takes only the Record parameter.")] + public string FormatRecord(Record record, string format) + { + if (record == null) + { + throw new ArgumentNullException("record"); + } + + return record.ToString(format, this); + } + + /// + /// Win32 MSI API: + /// MsiFormatRecord + ///
+ /// Retrieves product properties (not session properties) from the product database. + /// + ///Value of the property, or an empty string if the property is not set. + ///+ public string GetProductProperty(string property) + { + if (String.IsNullOrEmpty(property)) + { + throw new ArgumentNullException("property"); + } + + this.ValidateSessionAccess(); + + StringBuilder buf = new StringBuilder(); + uint bufSize = (uint) buf.Capacity; + uint ret = NativeMethods.MsiGetProductProperty((int) this.Handle, property, buf, ref bufSize); + + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + buf.Capacity = (int) ++bufSize; + ret = NativeMethods.MsiGetProductProperty((int) this.Handle, property, buf, ref bufSize); + } + + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + return buf.ToString(); + } + + /// + /// Note this is not the correct method for getting ordinary session properties. For that, + /// see the indexer on the Session class. + ///
+ /// Win32 MSI API: + /// MsiGetProductProperty + ///
+ /// Gets an accessor for components in the current session. + /// + public ComponentInfoCollection Components + { + get + { + this.ValidateSessionAccess(); + return new ComponentInfoCollection(this); + } + } + + ///+ /// Gets an accessor for features in the current session. + /// + public FeatureInfoCollection Features + { + get + { + this.ValidateSessionAccess(); + return new FeatureInfoCollection(this); + } + } + + ///+ /// Checks to see if sufficient disk space is present for the current installation. + /// + ///True if there is sufficient disk space; false otherwise. + ///+ public bool VerifyDiskSpace() + { + this.ValidateSessionAccess(); + + uint ret = RemotableNativeMethods.MsiVerifyDiskSpace((int)this.Handle); + if (ret == (uint) NativeMethods.Error.DISK_FULL) + { + return false; + } + else if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + return true; + } + + /// + /// Win32 MSI API: + /// MsiVerifyDiskSpace + ///
+ /// Gets the total disk space per drive required for the installation. + /// + ///A list of InstallCost structures, specifying the cost for each drive + ///+ [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public IList + /// Win32 MSI API: + /// MsiEnumComponentCosts + ///
GetTotalCost() + { + this.ValidateSessionAccess(); + + IList costs = new List (); + StringBuilder driveBuf = new StringBuilder(20); + for (uint i = 0; true; i++) + { + int cost, tempCost; + uint driveBufSize = (uint) driveBuf.Capacity; + uint ret = RemotableNativeMethods.MsiEnumComponentCosts( + (int) this.Handle, + null, + i, + (int) InstallState.Default, + driveBuf, + ref driveBufSize, + out cost, + out tempCost); + if (ret == (uint) NativeMethods.Error.NO_MORE_ITEMS) break; + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + driveBuf.Capacity = (int) ++driveBufSize; + ret = RemotableNativeMethods.MsiEnumComponentCosts( + (int) this.Handle, + null, + i, + (int) InstallState.Default, + driveBuf, + ref driveBufSize, + out cost, + out tempCost); + } + + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + costs.Add(new InstallCost(driveBuf.ToString(), cost * 512L, tempCost * 512L)); + } + return costs; + } + + /// + /// Gets the designated mode flag for the current install session. + /// + /// The type of mode to be checked. + ///The value of the designated mode flag. + ///the Session handle is invalid + ///an invalid mode flag was specified + ///+ public bool GetMode(InstallRunMode mode) + { + return RemotableNativeMethods.MsiGetMode((int) this.Handle, (uint) mode); + } + + /// + /// Note that only the following run modes are available to read from + /// a deferred custom action:
+ ///
+ ///- + ///
- + ///
- + ///
+ /// Win32 MSI API: + /// MsiGetMode + ///
+ /// Sets the designated mode flag for the current install session. + /// + /// The type of mode to be set. + /// The desired value of the mode. + ///the Session handle is invalid + ///an invalid mode flag was specified + ///the mode cannot not be set + ///+ public void SetMode(InstallRunMode mode, bool value) + { + this.ValidateSessionAccess(); + + uint ret = RemotableNativeMethods.MsiSetMode((int) this.Handle, (uint) mode, value); + if (ret != 0) + { + if (ret == (uint) NativeMethods.Error.ACCESS_DENIED) + { + throw new InvalidOperationException(); + } + else + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + } + + /// + /// Win32 MSI API: + /// MsiSetMode + ///
+ /// Gets the full path to the designated folder on the source media or server image. + /// + ///the folder was not found in the Directory table + ///the Session handle is invalid + ///+ public string GetSourcePath(string directory) + { + if (String.IsNullOrEmpty(directory)) + { + throw new ArgumentNullException("directory"); + } + + this.ValidateSessionAccess(); + + StringBuilder buf = new StringBuilder(); + uint bufSize = 0; + uint ret = RemotableNativeMethods.MsiGetSourcePath((int) this.Handle, directory, buf, ref bufSize); + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + buf.Capacity = (int) ++bufSize; + ret = ret = RemotableNativeMethods.MsiGetSourcePath((int) this.Handle, directory, buf, ref bufSize); + } + + if (ret != 0) + { + if (ret == (uint) NativeMethods.Error.DIRECTORY) + { + throw InstallerException.ExceptionFromReturnCode(ret, directory); + } + else + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + return buf.ToString(); + } + + /// + /// Win32 MSI API: + /// MsiGetSourcePath + ///
+ /// Gets the full path to the designated folder on the installation target drive. + /// + ///the folder was not found in the Directory table + ///the Session handle is invalid + ///+ public string GetTargetPath(string directory) + { + if (String.IsNullOrEmpty(directory)) + { + throw new ArgumentNullException("directory"); + } + + this.ValidateSessionAccess(); + + StringBuilder buf = new StringBuilder(); + uint bufSize = 0; + uint ret = RemotableNativeMethods.MsiGetTargetPath((int) this.Handle, directory, buf, ref bufSize); + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + buf.Capacity = (int) ++bufSize; + ret = ret = RemotableNativeMethods.MsiGetTargetPath((int) this.Handle, directory, buf, ref bufSize); + } + + if (ret != 0) + { + if (ret == (uint) NativeMethods.Error.DIRECTORY) + { + throw InstallerException.ExceptionFromReturnCode(ret, directory); + } + else + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + return buf.ToString(); + } + + /// + /// Win32 MSI API: + /// MsiGetTargetPath + ///
+ /// Sets the full path to the designated folder on the installation target drive. + /// + ///the folder was not found in the Directory table + ///the Session handle is invalid + ///+ public void SetTargetPath(string directory, string value) + { + if (String.IsNullOrEmpty(directory)) + { + throw new ArgumentNullException("directory"); + } + + if (value == null) + { + throw new ArgumentNullException("value"); + } + + this.ValidateSessionAccess(); + + uint ret = RemotableNativeMethods.MsiSetTargetPath((int) this.Handle, directory, value); + if (ret != 0) + { + if (ret == (uint) NativeMethods.Error.DIRECTORY) + { + throw InstallerException.ExceptionFromReturnCode(ret, directory); + } + else + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + } + + /// + /// Setting the target path of a directory changes the path specification for the directory + /// in the in-memory Directory table. Also, the path specifications of all other path objects + /// in the table that are either subordinate or equivalent to the changed path are updated + /// to reflect the change. The properties for each affected path are also updated. + ///
+ /// If an error occurs in this function, all updated paths and properties revert to + /// their previous values. Therefore, it is safe to treat errors returned by this function + /// as non-fatal. + ///
+ /// Do not attempt to configure the target path if the components using those paths + /// are already installed for the current user or for a different user. Check the + /// ProductState property before setting the target path to determine if the product + /// containing this component is installed. + ///
+ /// Win32 MSI API: + /// MsiSetTargetPath + ///
+ /// Sets the install level for the current installation to a specified value and + /// recalculates the Select and Installed states for all features in the Feature + /// table. Also sets the Action state of each component in the Component table based + /// on the new level. + /// + /// New install level + ///the Session handle is invalid + ///+ public void SetInstallLevel(int installLevel) + { + this.ValidateSessionAccess(); + + uint ret = RemotableNativeMethods.MsiSetInstallLevel((int) this.Handle, installLevel); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// The SetInstallLevel method sets the following:
+ ///
+ /// If 0 or a negative number is passed in the ilnstallLevel parameter, + /// the current installation level does not change, but all features are still + /// updated based on the current installation level. + ///- + ///
The installation level for the current installation to a specified value - + ///
The Select and Installed states for all features in the Feature table - + ///
The Action state of each component in the Component table, based on the new level + /// Win32 MSI API: + /// MsiSetInstallLevel + ///
+ /// Executes a built-in action, custom action, or user-interface wizard action. + /// + /// Name of the action to execute. Case-sensitive. + ///the Session handle is invalid + ///the user exited the installation + ///+ public void DoAction(string action) + { + this.DoAction(action, null); + } + + /// + /// The DoAction method executes the action that corresponds to the name supplied. If the + /// name is not recognized by the installer as a built-in action or as a custom action in + /// the CustomAction table, the name is passed to the user-interface handler object, which + /// can invoke a function or a dialog box. If a null action name is supplied, the installer + /// uses the upper-case value of the ACTION property as the action to perform. If no property + /// value is defined, the default action is performed, defined as "INSTALL". + ///
+ /// Actions that update the system, such as the InstallFiles and WriteRegistryValues + /// actions, cannot be run by calling MsiDoAction. The exception to this rule is if DoAction + /// is called from a custom action that is scheduled in the InstallExecuteSequence table + /// between the InstallInitialize and InstallFinalize actions. Actions that do not update the + /// system, such as AppSearch or CostInitialize, can be called. + ///
+ /// Win32 MSI API: + /// MsiDoAction + ///
+ /// Executes a built-in action, custom action, or user-interface wizard action. + /// + /// Name of the action to execute. Case-sensitive. + /// Optional data to be passed to a deferred custom action. + ///the Session handle is invalid + ///the user exited the installation + ///+ public void DoAction(string action, CustomActionData actionData) + { + if (String.IsNullOrEmpty(action)) + { + throw new ArgumentNullException("action"); + } + + this.ValidateSessionAccess(); + + if (actionData != null) + { + this[action] = actionData.ToString(); + } + + uint ret = RemotableNativeMethods.MsiDoAction((int) this.Handle, action); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// The DoAction method executes the action that corresponds to the name supplied. If the + /// name is not recognized by the installer as a built-in action or as a custom action in + /// the CustomAction table, the name is passed to the user-interface handler object, which + /// can invoke a function or a dialog box. If a null action name is supplied, the installer + /// uses the upper-case value of the ACTION property as the action to perform. If no property + /// value is defined, the default action is performed, defined as "INSTALL". + ///
+ /// Actions that update the system, such as the InstallFiles and WriteRegistryValues + /// actions, cannot be run by calling MsiDoAction. The exception to this rule is if DoAction + /// is called from a custom action that is scheduled in the InstallExecuteSequence table + /// between the InstallInitialize and InstallFinalize actions. Actions that do not update the + /// system, such as AppSearch or CostInitialize, can be called. + ///
+ /// If the called action is a deferred, rollback, or commit custom action, then the supplied + ///
will be available via the + /// property of that custom action's session. + /// + /// Win32 MSI API: + /// MsiDoAction + ///
+ /// Executes an action sequence described in the specified table. + /// + /// Name of the table containing the action sequence. + ///the Session handle is invalid + ///the user exited the installation + ///+ public void DoActionSequence(string sequenceTable) + { + if (String.IsNullOrEmpty(sequenceTable)) + { + throw new ArgumentNullException("sequenceTable"); + } + + this.ValidateSessionAccess(); + + uint ret = RemotableNativeMethods.MsiSequence((int) this.Handle, sequenceTable, 0); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// This method queries the specified table, ordering the actions by the numbers in the Sequence column. + /// For each row retrieved, an action is executed, provided that any supplied condition expression does + /// not evaluate to FALSE. + ///
+ /// An action sequence containing any actions that update the system, such as the InstallFiles and + /// WriteRegistryValues actions, cannot be run by calling DoActionSequence. The exception to this rule is if + /// DoActionSequence is called from a custom action that is scheduled in the InstallExecuteSequence table + /// between the InstallInitialize and InstallFinalize actions. Actions that do not update the system, such + /// as AppSearch or CostInitialize, can be called. + ///
+ /// Win32 MSI API: + /// MsiSequence + ///
+ /// Gets custom action data for the session that was supplied by the caller. + /// + ///+ public CustomActionData CustomActionData + { + get + { + if (this.customActionData == null) + { + this.customActionData = new CustomActionData(this[CustomActionData.PropertyName]); + } + + return this.customActionData; + } + } + + /// + /// Implements formatting for + /// Type of format object to get. + ///data. + /// The the current instance, if + object IFormatProvider.GetFormat(Type formatType) + { + return formatType == typeof(Session) ? this : null; + } + + ///is the same type + /// as the current instance; otherwise, null. + /// Closes the session handle. Also closes the active database handle, if it is open. + /// After closing a handle, further method calls may throw an + /// If true, the method has been called directly + /// or indirectly by a user's code, so managed and unmanaged resources will + /// be disposed. If false, only unmanaged resources will be disposed. + protected override void Dispose(bool disposing) + { + try + { + if (disposing) + { + if (this.database != null) + { + this.database.Dispose(); + this.database = null; + } + } + } + finally + { + base.Dispose(disposing); + } + } + + ///. + /// + /// Gets the (short) list of properties that are available from non-immediate custom actions. + /// + private static IListNonImmediatePropertyNames + { + get + { + return new string[] { + CustomActionData.PropertyName, + "ProductCode", + "UserSID" + }; + } + } + + /// + /// Throws an exception if the custom action is not able to access immedate session details. + /// + private void ValidateSessionAccess() + { + if (!this.sessionAccessValidated) + { + if (this.GetMode(InstallRunMode.Scheduled) || + this.GetMode(InstallRunMode.Rollback) || + this.GetMode(InstallRunMode.Commit)) + { + throw new InstallerException("Cannot access session details from a non-immediate custom action"); + } + + this.sessionAccessValidated = true; + } + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/ShortcutTarget.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/ShortcutTarget.cs new file mode 100644 index 00000000..4c043bf2 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/ShortcutTarget.cs @@ -0,0 +1,104 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + ///+ /// Holds information about the target of a shortcut file. + /// + public struct ShortcutTarget + { + private string productCode; + private string feature; + private string componentCode; + + internal ShortcutTarget(string productCode, string feature, string componentCode) + { + this.productCode = productCode; + this.feature = feature; + this.componentCode = componentCode; + } + + ///+ /// Gets the target product code of the shortcut, or null if not available. + /// + public string ProductCode + { + get + { + return this.productCode; + } + } + + ///+ /// Gets the name of the target feature of the shortcut, or null if not available. + /// + public string Feature + { + get + { + return this.feature; + } + } + + ///+ /// Gets the target component code of the shortcut, or null if not available. + /// + public string ComponentCode + { + get + { + return this.componentCode; + } + } + + ///+ /// Tests whether two shortcut targets have the same product code, feature, and/or component code. + /// + /// The first shortcut target to compare. + /// The second shortcut target to compare. + ///True if all parts of the targets are the same, else false. + public static bool operator ==(ShortcutTarget st1, ShortcutTarget st2) + { + return st1.Equals(st2); + } + + ///+ /// Tests whether two shortcut targets have the same product code, feature, and/or component code. + /// + /// The first shortcut target to compare. + /// The second shortcut target to compare. + ///True if any parts of the targets are different, else false. + public static bool operator !=(ShortcutTarget st1, ShortcutTarget st2) + { + return !st1.Equals(st2); + } + + ///+ /// Tests whether two shortcut targets have the same product code, feature, and/or component code. + /// + /// The shortcut target to compare to the current object. + ///True if + public override bool Equals(object obj) + { + if (obj == null || obj.GetType() != typeof(ShortcutTarget)) + { + return false; + } + ShortcutTarget st = (ShortcutTarget) obj; + return this.productCode == st.productCode + && this.feature == st.feature + && this.componentCode == st.componentCode; + } + + ///is a shortcut target and all parts of the targets are the same, else false. + /// Generates a hash code using all parts of the shortcut target. + /// + ///An integer suitable for hashing the shortcut target. + public override int GetHashCode() + { + return (this.productCode != null ? this.productCode.GetHashCode() : 0) + ^ (this.feature != null ? this.feature.GetHashCode() : 0) + ^ (this.componentCode != null ? this.componentCode.GetHashCode() : 0); + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/SourceList.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/SourceList.cs new file mode 100644 index 00000000..16ec22e8 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/SourceList.cs @@ -0,0 +1,525 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.Text; + using System.Collections.Generic; + using System.Globalization; + using System.Diagnostics.CodeAnalysis; + + ///+ /// A list of sources for an installed product or patch. + /// + [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] + public class SourceList : ICollection+ { + private Installation installation; + private SourceMediaList mediaList; + + internal SourceList(Installation installation) + { + this.installation = installation; + } + + /// + /// Gets the list of disks registered for the media source of + /// the patch or product installation. + /// + public SourceMediaList MediaList + { + get + { + if (this.mediaList == null) + { + this.mediaList = new SourceMediaList(this.installation); + } + return this.mediaList; + } + } + + ///+ /// Gets the number of network and URL sources in the list. + /// + public int Count + { + get + { + int count = 0; + IEnumeratore = this.GetEnumerator(); + while (e.MoveNext()) + { + count++; + } + return count; + } + } + + /// + /// Gets a boolean value indicating whether the list is read-only. + /// A SourceList is never read-only. + /// + ///read-only status of the list + public bool IsReadOnly + { + get { return false; } + } + + ///+ /// Adds a network or URL source to the source list of the installed product. + /// + /// Path to the source to be added. This parameter is + /// expected to contain only the path without the filename. + ///+ /// + /// If this method is called with a new source, the installer adds the source + /// to the end of the source list. + ///
+ /// If this method is called with a source already existing in the source + /// list, it has no effect. + ///
+ /// Win32 MSI APIs: + /// MsiSourceListAddSource, + /// MsiSourceListAddSourceEx + ///
+ public void Add(string item) + { + if (!this.Contains(item)) + { + this.Insert(item, 0); + } + } + + /// + /// Adds or reorders a network or URL source for the product or patch. + /// + /// Path to the source to be added. This parameter is + /// expected to contain only the path without the filename. + /// Specifies the priority order in which the source + /// will be inserted + ///+ public void Insert(string item, int index) + { + if (item == null) + { + throw new ArgumentNullException("item"); + } + + NativeMethods.SourceType type = item.Contains("://") ? NativeMethods.SourceType.Url : NativeMethods.SourceType.Network; + + uint ret = NativeMethods.MsiSourceListAddSourceEx( + this.installation.InstallationCode, + this.installation.UserSid, + this.installation.Context, + (uint) type | (uint) this.installation.InstallationType, + item, + (uint) index); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// If this method is called with a new source and
+ /// is set to 0, the installer adds the source to the end of the source list. + /// + /// If this method is called with a source already existing in the source + /// list and
is set to 0, the installer retains the + /// source's existing index. + /// + /// If the method is called with an existing source in the source list + /// and
is set to a non-zero value, the source is + /// removed from its current location in the list and inserted at the position + /// specified by Index, before any source that already exists at that position. + /// + /// If the method is called with a new source and Index is set to a + /// non-zero value, the source is inserted at the position specified by + ///
, before any source that already exists at + /// that position. The index value for all sources in the list after the + /// index specified by Index are updated to ensure unique index values and + /// the pre-existing order is guaranteed to remain unchanged. + /// + /// If
is greater than the number of sources + /// in the list, the source is placed at the end of the list with an index + /// value one larger than any existing source. + /// + /// Win32 MSI API: + /// MsiSourceListAddSourceEx + ///
+ /// Clears sources of all types: network, url, and media. + /// + ///+ public void Clear() + { + this.ClearSourceType(NativeMethods.SourceType.Url); + this.ClearSourceType(NativeMethods.SourceType.Network); + this.MediaList.Clear(); + } + + /// + /// Win32 MSI API: + /// MsiSourceListClearAll + ///
+ /// Removes all network sources from the list. URL sources are not affected. + /// + ///+ public void ClearNetworkSources() + { + this.ClearSourceType(NativeMethods.SourceType.Network); + } + + /// + /// Win32 MSI API: + /// MsiSourceListClearAllEx + ///
+ /// Removes all URL sources from the list. Network sources are not affected. + /// + ///+ public void ClearUrlSources() + { + this.ClearSourceType(NativeMethods.SourceType.Url); + } + + /// + /// Win32 MSI API: + /// MsiSourceListClearAllEx + ///
+ /// Checks if the specified source exists in the list. + /// + /// case-insensitive source to look for + ///true if the source exists in the list, false otherwise + public bool Contains(string item) + { + if (String.IsNullOrEmpty(item)) + { + throw new ArgumentNullException("item"); + } + + foreach (string s in this) + { + if (s.Equals(item, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + return false; + } + + ///+ /// Copies the network and URL sources from this list into an array. + /// + /// destination array to be filed + /// offset into the destination array where copying begins + public void CopyTo(string[] array, int arrayIndex) + { + foreach (string source in this) + { + array[arrayIndex++] = source; + } + } + + ///+ /// Removes a network or URL source. + /// + ///+ public bool Remove(string item) + { + if (String.IsNullOrEmpty(item)) + { + throw new ArgumentNullException("item"); + } + + NativeMethods.SourceType type = item.Contains("://") ? NativeMethods.SourceType.Url : NativeMethods.SourceType.Network; + + uint ret = NativeMethods.MsiSourceListClearSource( + this.installation.InstallationCode, + this.installation.UserSid, + this.installation.Context, + (uint) type | (uint) this.installation.InstallationType, + item); + if (ret != 0) + { + // TODO: Figure out when to return false. + throw InstallerException.ExceptionFromReturnCode(ret); + } + return true; + } + + /// + /// Win32 MSI API: + /// MsiSourceListClearSource + ///
+ /// Enumerates the network and URL sources in the source list of the patch or product installation. + /// + ///+ public IEnumerator + /// Win32 MSI API: + /// MsiSourceListEnumSources + ///
GetEnumerator() + { + StringBuilder sourceBuf = new StringBuilder(256); + uint sourceBufSize = (uint) sourceBuf.Capacity; + for (uint i = 0; true; i++) + { + uint ret = this.EnumSources(sourceBuf, i, NativeMethods.SourceType.Network); + if (ret == (uint) NativeMethods.Error.NO_MORE_ITEMS) + { + break; + } + else if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + else + { + yield return sourceBuf.ToString(); + } + } + + for (uint i = 0; true; i++) + { + uint ret = this.EnumSources(sourceBuf, i, NativeMethods.SourceType.Url); + if (ret == (uint) NativeMethods.Error.NO_MORE_ITEMS) + { + break; + } + else if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + else + { + yield return sourceBuf.ToString(); + } + } + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + /// + /// Forces the installer to search the source list for a valid + /// source the next time a source is required. For example, when the + /// installer performs an installation or reinstallation, or when it + /// requires the path for a component that is set to run from source. + /// + ///+ public void ForceResolution() + { + uint ret = NativeMethods.MsiSourceListForceResolutionEx( + this.installation.InstallationCode, + this.installation.UserSid, + this.installation.Context, + (uint) this.installation.InstallationType); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// Win32 MSI APIs: + /// MsiSourceListForceResolution, + /// MsiSourceListForceResolutionEx + ///
+ /// Gets or sets the path relative to the root of the installation media. + /// + public string MediaPackagePath + { + get + { + return this["MediaPackagePath"]; + } + set + { + this["MediaPackagePath"] = value; + } + } + + ///+ /// Gets or sets the prompt template that is used when prompting the user + /// for installation media. + /// + public string DiskPrompt + { + get + { + return this["DiskPrompt"]; + } + set + { + this["DiskPrompt"] = value; + } + } + + ///+ /// Gets or sets the most recently used source location for the product. + /// + public string LastUsedSource + { + get + { + return this["LastUsedSource"]; + } + set + { + this["LastUsedSource"] = value; + } + } + + ///+ /// Gets or sets the name of the Windows Installer package or patch package + /// on the source. + /// + public string PackageName + { + get + { + return this["PackageName"]; + } + set + { + this["PackageName"] = value; + } + } + + ///+ /// Gets the type of the last-used source. + /// + ///+ public string LastUsedType + { + get + { + return this["LastUsedType"]; + } + } + + /// + ///
+ ///
+ ///- "n" = network location
+ ///- "u" = URL location
+ ///- "m" = media location
+ ///- (empty string) = no last used source
+ ///+ /// Gets or sets source list information properties of a product or patch installation. + /// + /// The source list information property name. + ///An unknown product, patch, or property was requested + ///+ public string this[string property] + { + get + { + StringBuilder buf = new StringBuilder(""); + uint bufSize = 0; + uint ret = NativeMethods.MsiSourceListGetInfo( + this.installation.InstallationCode, + this.installation.UserSid, + this.installation.Context, + (uint) this.installation.InstallationType, + property, + buf, + ref bufSize); + if (ret != 0) + { + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + buf.Capacity = (int) ++bufSize; + ret = NativeMethods.MsiSourceListGetInfo( + this.installation.InstallationCode, + this.installation.UserSid, + this.installation.Context, + (uint) this.installation.InstallationType, + property, + buf, + ref bufSize); + } + + if (ret != 0) + { + if (ret == (uint) NativeMethods.Error.UNKNOWN_PRODUCT || + ret == (uint) NativeMethods.Error.UNKNOWN_PROPERTY) + { + throw new ArgumentOutOfRangeException("property"); + } + else + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + } + return buf.ToString(); + } + set + { + uint ret = NativeMethods.MsiSourceListSetInfo( + this.installation.InstallationCode, + this.installation.UserSid, + this.installation.Context, + (uint) this.installation.InstallationType, + property, + value); + if (ret != 0) + { + if (ret == (uint) NativeMethods.Error.UNKNOWN_PRODUCT || + ret == (uint) NativeMethods.Error.UNKNOWN_PROPERTY) + { + throw new ArgumentOutOfRangeException("property"); + } + else + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + } + } + + private void ClearSourceType(NativeMethods.SourceType type) + { + uint ret = NativeMethods.MsiSourceListClearAllEx( + this.installation.InstallationCode, + this.installation.UserSid, + this.installation.Context, + (uint) type | (uint) this.installation.InstallationType); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + private uint EnumSources(StringBuilder sourceBuf, uint i, NativeMethods.SourceType sourceType) + { + int enumType = (this.installation.InstallationType | (int) sourceType); + uint sourceBufSize = (uint) sourceBuf.Capacity; + uint ret = NativeMethods.MsiSourceListEnumSources( + this.installation.InstallationCode, + this.installation.UserSid, + this.installation.Context, + (uint) enumType, + i, + sourceBuf, + ref sourceBufSize); + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + sourceBuf.Capacity = (int) ++sourceBufSize; + ret = NativeMethods.MsiSourceListEnumSources( + this.installation.InstallationCode, + this.installation.UserSid, + this.installation.Context, + (uint) enumType, + i, + sourceBuf, + ref sourceBufSize); + } + return ret; + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/SourceMediaList.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/SourceMediaList.cs new file mode 100644 index 00000000..cf7b7ec5 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/SourceMediaList.cs @@ -0,0 +1,229 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.Collections.Generic; + using System.Text; + using System.Globalization; + using System.Diagnostics.CodeAnalysis; + + /// + /// Win32 MSI API: + /// MsiSourceListGetInfo + ///
+ /// A list of source media for an installed product or patch. + /// + [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] + public class SourceMediaList : ICollection+ { + private Installation installation; + + internal SourceMediaList(Installation installation) + { + this.installation = installation; + } + + /// + /// Gets the number of source media in the list. + /// + public int Count + { + get + { + int count = 0; + IEnumeratore = this.GetEnumerator(); + while (e.MoveNext()) + { + count++; + } + return count; + } + } + + /// + /// Gets a boolean value indicating whether the list is read-only. + /// A SourceMediaList is never read-only. + /// + ///read-only status of the list + public bool IsReadOnly + { + get + { + return false; + } + } + + ///+ /// Adds or updates a disk of the media source for the product or patch. + /// + ///+ public void Add(MediaDisk item) + { + uint ret = NativeMethods.MsiSourceListAddMediaDisk( + this.installation.InstallationCode, + this.installation.UserSid, + this.installation.Context, + (uint) this.installation.InstallationType, + (uint) item.DiskId, + item.VolumeLabel, + item.DiskPrompt); + + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// Win32 MSI API: + /// MsiSourceListAddMediaDisk + ///
+ /// Removes all source media from the list. + /// + ///+ public void Clear() + { + uint ret = NativeMethods.MsiSourceListClearAllEx( + this.installation.InstallationCode, + this.installation.UserSid, + this.installation.Context, + (uint) NativeMethods.SourceType.Media | (uint) this.installation.InstallationType); + + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// Win32 MSI API: + /// MsiSourceListClearAllEx + ///
+ /// Checks if the specified media disk id exists in the list. + /// + /// disk id of the media to look for + ///true if the media exists in the list, false otherwise + public bool Contains(int diskId) + { + foreach (MediaDisk mediaDisk in this) + { + if (mediaDisk.DiskId == diskId) + { + return true; + } + } + return false; + } + + bool ICollection.Contains(MediaDisk mediaDisk) + { + return this.Contains(mediaDisk.DiskId); + } + + /// + /// Copies the source media info from this list into an array. + /// + /// destination array to be filed + /// offset into the destination array where copying begins + public void CopyTo(MediaDisk[] array, int arrayIndex) + { + foreach (MediaDisk mediaDisk in this) + { + array[arrayIndex++] = mediaDisk; + } + } + + ///+ /// Removes a specified disk from the set of registered disks. + /// + /// ID of the disk to remove + ///+ public bool Remove(int diskId) + { + uint ret = NativeMethods.MsiSourceListClearMediaDisk( + this.installation.InstallationCode, + this.installation.UserSid, + this.installation.Context, + (uint) this.installation.InstallationType, + (uint) diskId); + + if (ret != 0) + { + // TODO: Figure out when to return false. + throw InstallerException.ExceptionFromReturnCode(ret); + } + return true; + } + + bool ICollection + /// Win32 MSI API: + /// MsiSourceListClearMediaDisk + ///
.Remove(MediaDisk mediaDisk) + { + return this.Remove(mediaDisk.DiskId); + } + + /// + /// Enumerates the source media in the source list of the patch or product installation. + /// + ///+ public IEnumerator + /// Win32 MSI API: + /// MsiSourceListEnumMediaDisks + ///
GetEnumerator() + { + uint diskId; + StringBuilder volumeBuf = new StringBuilder(40); + uint volumeBufSize = (uint) volumeBuf.Capacity; + StringBuilder promptBuf = new StringBuilder(80); + uint promptBufSize = (uint) promptBuf.Capacity; + for (uint i = 0; true; i++) + { + uint ret = NativeMethods.MsiSourceListEnumMediaDisks( + this.installation.InstallationCode, + this.installation.UserSid, + this.installation.Context, + (uint) this.installation.InstallationType, + i, + out diskId, + volumeBuf, + ref volumeBufSize, + promptBuf, + ref promptBufSize); + + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + volumeBuf.Capacity = (int) ++volumeBufSize; + promptBuf.Capacity = (int) ++promptBufSize; + + ret = NativeMethods.MsiSourceListEnumMediaDisks( + this.installation.InstallationCode, + this.installation.UserSid, + this.installation.Context, + (uint) this.installation.InstallationType, + i, + out diskId, + volumeBuf, + ref volumeBufSize, + promptBuf, + ref promptBufSize); + } + + if (ret == (uint) NativeMethods.Error.NO_MORE_ITEMS) + { + break; + } + + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + + yield return new MediaDisk((int) diskId, volumeBuf.ToString(), promptBuf.ToString()); + } + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/SummaryInfo.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/SummaryInfo.cs new file mode 100644 index 00000000..4dbff93f --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/SummaryInfo.cs @@ -0,0 +1,612 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.IO; + using System.Text; + using System.Globalization; + using System.Runtime.InteropServices; + + /// + /// Provides access to summary information of a Windows Installer database. + /// + public class SummaryInfo : InstallerHandle + { + internal const int MAX_PROPERTIES = 20; + + ///+ /// Gets a SummaryInfo object that can be used to examine, update, and add + /// properties to the summary information stream of a package or transform. + /// + /// Path to the package (database) or transform + /// True to reserve resources for writing summary information properties. + ///the package does not exist or could not be read + ///the package is an invalid format + ///+ public SummaryInfo(string packagePath, bool enableWrite) + : base((IntPtr) SummaryInfo.OpenSummaryInfo(packagePath, enableWrite), true) + { + } + + internal SummaryInfo(IntPtr handle, bool ownsHandle) : base(handle, ownsHandle) + { + } + + /// + /// The SummaryInfo object should be
d after use. + /// It is best that the handle be closed manually as soon as it is no longer + /// needed, as leaving lots of unused handles open can degrade performance. + /// + /// Win32 MSI API: + /// MsiGetSummaryInformation + ///
Gets or sets the Title summary information property. + ///+ public string Title + { + get { return this[2]; } + set { this[2] = value; } + } + + /// + /// The Title summary information property briefly describes the type of installer package. Phrases + /// such as "Installation Database" or "Transform" or "Patch" may be used for this property. + ///
+ /// Win32 MSI APIs: + /// MsiSummaryInfoGetProperty, + /// MsiSummaryInfoSetProperty + ///
Gets or sets the Subject summary information property. + ///+ public string Subject + { + get { return this[3]; } + set { this[3] = value; } + } + + /// + /// The Subject summary information property conveys to a file browser the product that can be installed using + /// the logic and data in this installer database. For example, the value of the summary property for + /// Microsoft Office 97 would be "Microsoft Office 97 Professional". This value is typically set from the + /// installer property ProductName. + ///
+ /// Win32 MSI APIs: + /// MsiSummaryInfoGetProperty, + /// MsiSummaryInfoSetProperty + ///
Gets or sets the Author summary information property. + ///+ public string Author + { + get { return this[4]; } + set { this[4] = value; } + } + + /// + /// The Author summary information property conveys to a file browser the manufacturer of the installation + /// database. This value is typically set from the installer property Manufacturer. + ///
+ /// Win32 MSI APIs: + /// MsiSummaryInfoGetProperty, + /// MsiSummaryInfoSetProperty + ///
Gets or sets the Keywords summary information property. + ///+ public string Keywords + { + get { return this[5]; } + set { this[5] = value; } + } + + /// + /// The Keywords summary information property is used by file browsers to hold keywords that permit the + /// database file to be found in a keyword search. The set of keywords typically includes "Installer" as + /// well as product-specific keywords, and may be localized. + ///
+ /// Win32 MSI APIs: + /// MsiSummaryInfoGetProperty, + /// MsiSummaryInfoSetProperty + ///
Gets or sets the Comments summary information property. + ///+ public string Comments + { + get { return this[6]; } + set { this[6] = value; } + } + + /// + /// The Comments summary information property conveys the general purpose of the installer database. By convention, + /// the value for this summary property is set to the following: + ///
+ /// "This installer database contains the logic and data required to install <product name>." + ///
+ /// where <product name> is the name of the product being installed. In general the value for this summary + /// property only changes in the product name, nothing else. + ///
+ /// Win32 MSI APIs: + /// MsiSummaryInfoGetProperty, + /// MsiSummaryInfoSetProperty + ///
Gets or sets the Template summary information property. + ///+ public string Template + { + get { return this[7]; } + set { this[7] = value; } + } + + /// + /// The Template summary information propery indicates the platform and language versions supported by the database. + ///
+ /// The syntax of the Template Summary property information is: + /// [platform property][,platform property][,...];[language id][,language id][,...] + ///
+ /// For example, the following are all valid values for the Template Summary property: + ///
+ ///
+ ///- Intel;1033
+ ///- Intel64;1033
+ ///- ;1033
+ ///- ;
+ ///- Intel ;1033,2046
+ ///- Intel64;1033,2046
+ ///- Intel;0
+ ///+ /// If this is a 64-bit Windows Installer, enter Intel64 in the Template summary information property. Note that an + /// installation package cannot have both the Intel and Intel64 properties set. + ///
+ /// If the current platform does not match one of the platforms specified then the installer will not process the + /// package. Not specifying a platform implies that the package is platform-independent. + ///
+ /// Entering 0 in the language ID field of the Template summary information property, or leaving this field empty, + /// indicates that the package is language neutral. + ///
+ /// There are variations of this property depending on whether it is in a source installer database or a transform. + ///
+ /// Source Installer Database - Only one language can be specified in a source installer database. Merge Modules are + /// the only packages that may have multiple languages. For more information, see Multiple Language Merge Modules. + ///
+ /// Transform - In a transform file, only one language may be specified. The specified platform and language determine + /// whether a transform can be applied to a particular database. The platform property and the language property can + /// be left blank if no transform restriction relies on them to validate the transform. + ///
+ /// This summary property is REQUIRED. + ///
+ /// Win32 MSI APIs: + /// MsiSummaryInfoGetProperty, + /// MsiSummaryInfoSetProperty + ///
Gets or sets the LastSavedBy summary information property. + ///+ public string LastSavedBy + { + get { return this[8]; } + set { this[8] = value; } + } + + /// + /// The installer sets the Last Saved By summary information property to the value of the LogonUser property during + /// an administrative installation. The installer never uses this property and a user never needs to modify it. + /// Developers of a database editing tool may use this property to track the last person to modify the database. + /// This property should be left set to null in a final shipping database. + ///
+ /// In a transform, this summary property contains the platform and language ID(s) that a database should have + /// after it has been transformed. The property specifies to what the Template should be set in the new database. + ///
+ /// Win32 MSI APIs: + /// MsiSummaryInfoGetProperty, + /// MsiSummaryInfoSetProperty + ///
Gets or sets the RevisionNumber summary information property. + ///+ public string RevisionNumber + { + get { return this[9]; } + set { this[9] = value; } + } + + /// + /// The Revision Number summary information property contains the package code for the installer package. The + /// package code is a unique identifier of the installer package. + ///
+ /// The Revision Number summary information property of a patch package specifies the GUID patch code for + /// the patch. This is followed by a list of patch code GUIDs for obsolete patches that are removed when this + /// patch is applied. The patch codes are concatenated with no delimiters separating GUIDs in the list. + ///
+ /// The Revision Number summary information property of a transform package lists the product code GUIDs + /// and version of the new and original products and the upgrade code GUID. The list is separated with + /// semicolons as follows. + ///
+ /// Original-Product-Code Original-Product-Version ; New-Product Code New-Product-Version; Upgrade-Code + ///
+ /// This summary property is REQUIRED. + ///
+ /// Win32 MSI APIs: + /// MsiSummaryInfoGetProperty, + /// MsiSummaryInfoSetProperty + ///
Gets or sets the CreatingApp summary information property. + ///+ public string CreatingApp + { + get { return this[18]; } + set { this[18] = value; } + } + + /// + /// The CreatingApp summary information property conveys which application created the installer database. + /// In general the value for this summary property is the name of the software used to author this database. + ///
+ /// Win32 MSI APIs: + /// MsiSummaryInfoGetProperty, + /// MsiSummaryInfoSetProperty + ///
Gets or sets the LastPrintTime summary information property. + ///+ public DateTime LastPrintTime + { + get { return (DateTime) this[11, typeof(DateTime)]; } + set { this[11, typeof(DateTime)] = value; } + } + + /// + /// The LastPrintTime summary information property can be set to the date and time during an administrative + /// installation to record when the administrative image was created. For non-administrative installations + /// this property is the same as the CreateTime summary information property. + ///
+ /// Win32 MSI APIs: + /// MsiSummaryInfoGetProperty, + /// MsiSummaryInfoSetProperty + ///
Gets or sets the CreateTime summary information property. + ///+ public DateTime CreateTime + { + get { return (DateTime) this[12, typeof(DateTime)]; } + set { this[12, typeof(DateTime)] = value; } + } + + /// + /// The CreateTime summary information property conveys when the installer database was created. + ///
+ /// Win32 MSI APIs: + /// MsiSummaryInfoGetProperty, + /// MsiSummaryInfoSetProperty + ///
Gets or sets the LastSaveTime summary information property. + ///+ public DateTime LastSaveTime + { + get { return (DateTime) this[13, typeof(DateTime)]; } + set { this[13, typeof(DateTime)] = value; } + } + + /// + /// The LastSaveTime summary information property conveys when the last time the installer database was + /// modified. Each time a user changes an installation the value for this summary property is updated to + /// the current system time/date at the time the installer database was saved. Initially the value for + /// this summary property is set to null to indicate that no changes have yet been made. + ///
+ /// Win32 MSI APIs: + /// MsiSummaryInfoGetProperty, + /// MsiSummaryInfoSetProperty + ///
Gets or sets the CodePage summary information property. + ///+ public short CodePage + { + get { return (short) this[1, typeof(short)]; } + set { this[1, typeof(short)] = value; } + } + + /// + /// The Codepage summary information property is the numeric value of the ANSI code page used for any + /// strings that are stored in the summary information. Note that this is not the same code page for + /// strings in the installation database. The Codepage summary information property is used to translate + /// the strings in the summary information into Unicode when calling the Unicode API functions. The + /// Codepage summary information property must be set before any string properties are set in the + /// summary information. + ///
+ /// Win32 MSI APIs: + /// MsiSummaryInfoGetProperty, + /// MsiSummaryInfoSetProperty + ///
Gets or sets the PageCount summary information property. + ///+ public int PageCount + { + get { return (int) this[14, typeof(int)]; } + set { this[14, typeof(int)] = value; } + } + + /// + /// For an installation package, the PageCount summary information property contains the minimum + /// installer version required. For Windows Installer version 1.0, this property must be set to the + /// integer 100. For 64-bit Windows Installer Packages, this property must be set to the integer 200. + ///
+ /// For a transform package, the PageCount summary information property contains minimum installer + /// version required to process the transform. Set to the greater of the two PageCount summary information + /// property values belonging to the databases used to generate the transform. + ///
+ /// The PageCount summary information property is set to null in patch packages. + ///
+ /// This summary property is REQUIRED. + ///
+ /// Win32 MSI APIs: + /// MsiSummaryInfoGetProperty, + /// MsiSummaryInfoSetProperty + ///
Gets or sets the WordCount summary information property. + ///+ public int WordCount + { + get { return (int) this[15, typeof(int)]; } + set { this[15, typeof(int)] = value; } + } + + /// + /// The WordCount summary information property indicates the type of source file image. If this property is + /// not present, it defaults to 0. Note that this property is stored in place of the standard Count property. + ///
+ /// This property is a bit field. New bits may be added in the future. At present the following bits are + /// available: + ///
+ ///
+ ///- Bit 0: 0 = long file names, 1 = short file names
+ ///- Bit 1: 0 = source is uncompressed, 1 = source is compressed
+ ///- Bit 2: 0 = source is original media, 1 = source is administrative installation
+ ///- [MSI 4.0] Bit 3: 0 = elevated privileges can be required to install, 1 = elevated privileges are not required to install
+ ///+ /// These are combined to give the WordCount summary information property one of the following values + /// indicating a type of source file image: + ///
+ ///
+ ///- 0 - Original source using long file names. Matches tree in Directory table.
+ ///- 1 - Original source using short file names. Matches tree in Directory table.
+ ///- 2 - Compressed source files using long file names. Matches cabinets and files in the Media table.
+ ///- 3 - Compressed source files using short file names. Matches cabinets and files in the Media table.
+ ///- 4 - Administrative image using long file names. Matches tree in Directory table.
+ ///- 5 - Administrative image using short file names. Matches tree in Directory table.
+ ///+ /// Note that if the package is marked as compressed (bit 1 is set), the installer only installs files + /// located at the root of the source. In this case, even files marked as uncompressed in the File table must + /// be located at the root to be installed. To specify a source image that has both a cabinet file (compressed + /// files) and uncompressed files that match the tree in the Directory table, mark the package as uncompressed + /// by leaving bit 1 unset (value=0) in the WordCount summary information property and set + ///
(value=16384) in the Attributes column of the File table + /// for each file in the cabinet. + /// + /// For a patch package, the WordCount summary information property specifies the patch engine that was used + /// to create the patch files. The default value is 1 and indicates that MSPATCH was used to create the patch + /// A value of "2" means that the patch is using smaller, optimized, files available only with Windows Installer + /// version 1.2 or later. A patch with a WordCount of "2" fails immediately if used with a Windows Installer + /// version earlier than 1.2. A patch with a WordCount of "3" fails immediately if used with a Windows Installer + /// version earlier than 2.0. + ///
+ /// This summary property is REQUIRED. + ///
+ /// Win32 MSI APIs: + /// MsiSummaryInfoGetProperty, + /// MsiSummaryInfoSetProperty + ///
Gets or sets the CharacterCount summary information property. + ///+ public int CharacterCount + { + get { return (int) this[16, typeof(int)]; } + set { this[16, typeof(int)] = value; } + } + + /// + /// The CharacterCount summary information property is only used in transforms. This part of the summary + /// information stream is divided into two 16-bit words. The upper word contains the transform validation + /// flags. The lower word contains the transform error condition flags. + ///
+ /// Win32 MSI APIs: + /// MsiSummaryInfoGetProperty, + /// MsiSummaryInfoSetProperty + ///
Gets or sets the Security summary information property. + ///+ public int Security + { + get { return (int) this[19, typeof(int)]; } + set { this[19, typeof(int)] = value; } + } + + private object this[uint property, Type type] + { + get + { + uint dataType; + StringBuilder stringValue = new StringBuilder(""); + uint bufSize = 0; + int intValue; + long timeValue = 0; + + uint ret = RemotableNativeMethods.MsiSummaryInfoGetProperty( + (int) this.Handle, + property, + out dataType, + out intValue, + ref timeValue, + stringValue, + ref bufSize); + if (ret != 0 && dataType != (uint) VarEnum.VT_LPSTR) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + + switch ((VarEnum) dataType) + { + case VarEnum.VT_EMPTY: + { + if (type == typeof(DateTime)) + { + return DateTime.MinValue; + } + else if (type == typeof(string)) + { + return String.Empty; + } + else if (type == typeof(short)) + { + return (short) 0; + } + else + { + return (int) 0; + } + } + + case VarEnum.VT_LPSTR: + { + if (ret == (uint) NativeMethods.Error.MORE_DATA) + { + stringValue.Capacity = (int) ++bufSize; + ret = RemotableNativeMethods.MsiSummaryInfoGetProperty( + (int) this.Handle, + property, + out dataType, + out intValue, + ref timeValue, + stringValue, + ref bufSize); + } + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + return stringValue.ToString(); + } + + case VarEnum.VT_I2: + case VarEnum.VT_I4: + { + if (type == typeof(string)) + { + return intValue.ToString(CultureInfo.InvariantCulture); + } + else if (type == typeof(short)) + { + return (short) intValue; + } + else + { + return intValue; + } + } + + case VarEnum.VT_FILETIME: + { + if (type == typeof(string)) + { + return DateTime.FromFileTime(timeValue).ToString(CultureInfo.InvariantCulture); + } + else + { + return DateTime.FromFileTime(timeValue); + } + } + + default: + { + throw new InstallerException(); + } + } + } + + set + { + uint dataType = (uint) VarEnum.VT_NULL; + string stringValue = ""; + int intValue = 0; + long timeValue = 0; + + if (type == typeof(short)) + { + dataType = (uint) VarEnum.VT_I2; + intValue = (int)(short) value; // Double cast because value is a *boxed* short. + } + else if (type == typeof(int)) + { + dataType = (uint) VarEnum.VT_I4; + intValue = (int) value; + } + else if (type == typeof(string)) + { + dataType = (uint) VarEnum.VT_LPSTR; + stringValue = (string) value; + } + else // (type == typeof(DateTime)) + { + dataType = (uint) VarEnum.VT_FILETIME; + timeValue = ((DateTime) value).ToFileTime(); + } + + uint ret = NativeMethods.MsiSummaryInfoSetProperty( + (int) this.Handle, + property, + dataType, + intValue, + ref timeValue, + stringValue); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + } + + private string this[uint property] + { + get { return (string) this[property, typeof(string)]; } + set { this[property, typeof(string)] = value; } + } + + /// + /// The Security summary information property conveys whether the package should be opened as read-only. The database + /// editing tool should not modify a read-only enforced database and should issue a warning at attempts to modify a + /// read-only recommended database. The following values of this property are applicable to Windows Installer files: + ///
+ ///
+ ///- 0 - no restriction
+ ///- 2 - read only recommended
+ ///- 4 - read only enforced
+ ///+ /// This property should be set to read-only recommended (2) for an installation database and to read-only + /// enforced (4) for a transform or patch. + ///
+ /// Win32 MSI APIs: + /// MsiSummaryInfoGetProperty, + /// MsiSummaryInfoSetProperty + ///
+ /// Formats and writes the previously stored properties into the standard summary information stream. + /// + ///The stream cannot be successfully written. + ///+ public void Persist() + { + uint ret = NativeMethods.MsiSummaryInfoPersist((int) this.Handle); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + private static int OpenSummaryInfo(string packagePath, bool enableWrite) + { + int summaryInfoHandle; + int maxProperties = !enableWrite ? 0 : SummaryInfo.MAX_PROPERTIES; + uint ret = RemotableNativeMethods.MsiGetSummaryInformation( + 0, + packagePath, + (uint) maxProperties, + out summaryInfoHandle); + if (ret != 0) + { + if (ret == (uint) NativeMethods.Error.FILE_NOT_FOUND || + ret == (uint) NativeMethods.Error.ACCESS_DENIED) + { + throw new FileNotFoundException(null, packagePath); + } + else + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + return summaryInfoHandle; + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/TableCollection.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/TableCollection.cs new file mode 100644 index 00000000..95176ea0 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/TableCollection.cs @@ -0,0 +1,192 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.Collections.Generic; + using System.Text; + + /// + /// This method may only be called once after all the property values have been set. Properties may + /// still be read after the stream is written. + ///
+ /// Win32 MSI API: + /// MsiSummaryInfoPersist + ///
+ /// Contains information about all the tables in a Windows Installer database. + /// + public class TableCollection : ICollection+ { + private Database db; + + internal TableCollection(Database db) + { + this.db = db; + } + + /// + /// Gets the number of tables in the database. + /// + public int Count + { + get + { + return this.GetTables().Count; + } + } + + ///+ /// Gets a boolean value indicating whether the collection is read-only. + /// A TableCollection is read-only when the database is read-only. + /// + ///read-only status of the collection + public bool IsReadOnly + { + get + { + return this.db.IsReadOnly; + } + } + + ///+ /// Gets information about a given table. + /// + /// case-sensitive name of the table + ///information about the requested table, or null if the table does not exist in the database + public TableInfo this[string table] + { + get + { + if (String.IsNullOrEmpty(table)) + { + throw new ArgumentNullException("table"); + } + + if (!this.Contains(table)) + { + return null; + } + + return new TableInfo(this.db, table); + } + } + + ///+ /// Adds a new table to the database. + /// + /// information about the table to be added + ///a table with the same name already exists in the database + public void Add(TableInfo item) + { + if (item == null) + { + throw new ArgumentNullException("item"); + } + + if (this.Contains(item.Name)) + { + throw new InvalidOperationException(); + } + + this.db.Execute(item.SqlCreateString); + } + + ///+ /// Removes all tables (and all data) from the database. + /// + public void Clear() + { + foreach (string table in this.GetTables()) + { + this.Remove(table); + } + } + + ///+ /// Checks if the database contains a table with the given name. + /// + /// case-sensitive name of the table to search for + ///True if the table exists, false otherwise. + public bool Contains(string item) + { + if (String.IsNullOrEmpty(item)) + { + throw new ArgumentNullException("item"); + } + uint ret = RemotableNativeMethods.MsiDatabaseIsTablePersistent((int) this.db.Handle, item); + if (ret == 3) // MSICONDITION_ERROR + { + throw new InstallerException(); + } + return ret != 2; // MSICONDITION_NONE + } + + bool ICollection.Contains(TableInfo item) + { + return this.Contains(item.Name); + } + + /// + /// Copies the table information from this collection into an array. + /// + /// destination array to be filed + /// offset into the destination array where copying begins + public void CopyTo(TableInfo[] array, int arrayIndex) + { + if (array == null) + { + throw new ArgumentNullException("array"); + } + + foreach (string table in this.GetTables()) + { + array[arrayIndex++] = new TableInfo(this.db, table); + } + } + + ///+ /// Removes a table from the database. + /// + /// case-sensitive name of the table to be removed + ///true if the table was removed, false if the table did not exist + public bool Remove(string item) + { + if (String.IsNullOrEmpty(item)) + { + throw new ArgumentNullException("item"); + } + + if (!this.Contains(item)) + { + return false; + } + this.db.Execute("DROP TABLE `{0}`", item); + return true; + } + + bool ICollection.Remove(TableInfo item) + { + if (item == null) + { + throw new ArgumentNullException("item"); + } + + return this.Remove(item.Name); + } + + /// + /// Enumerates the tables in the database. + /// + public IEnumeratorGetEnumerator() + { + foreach (string table in this.GetTables()) + { + yield return new TableInfo(this.db, table); + } + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + private IList GetTables() + { + return this.db.ExecuteStringQuery("SELECT `Name` FROM `_Tables`"); + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/TableInfo.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/TableInfo.cs new file mode 100644 index 00000000..e5a850b0 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/TableInfo.cs @@ -0,0 +1,264 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.Text; + using System.Collections.Generic; + using System.Collections.ObjectModel; + + /// + /// Defines a table in an installation database. + /// + public class TableInfo + { + private string name; + private ColumnCollection columns; + private ReadOnlyCollectionprimaryKeys; + + /// + /// Creates a table definition. + /// + /// Name of the table. + /// Columns in the table. + /// The primary keys of the table. + public TableInfo(string name, ICollectioncolumns, IList primaryKeys) + { + if (String.IsNullOrEmpty(name)) + { + throw new ArgumentNullException("name"); + } + + if (columns == null || columns.Count == 0) + { + throw new ArgumentNullException("columns"); + } + + if (primaryKeys == null || primaryKeys.Count == 0) + { + throw new ArgumentNullException("primaryKeys"); + } + + this.name = name; + this.columns = new ColumnCollection(columns); + this.primaryKeys = new List (primaryKeys).AsReadOnly(); + foreach (string primaryKey in this.primaryKeys) + { + if (!this.columns.Contains(primaryKey)) + { + throw new ArgumentOutOfRangeException("primaryKeys"); + } + } + } + + internal TableInfo(Database db, string name) + { + if (db == null) + { + throw new ArgumentNullException("db"); + } + + if (String.IsNullOrEmpty(name)) + { + throw new ArgumentNullException("name"); + } + + this.name = name; + + using (View columnsView = db.OpenView("SELECT * FROM `{0}`", name)) + { + this.columns = new ColumnCollection(columnsView); + } + + this.primaryKeys = new ReadOnlyCollection ( + TableInfo.GetTablePrimaryKeys(db, name)); + } + + /// + /// Gets the name of the table. + /// + public string Name + { + get + { + return this.name; + } + } + + ///+ /// Gets information about the columns in this table. + /// + ///+ public ColumnCollection Columns + { + get + { + return this.columns; + } + } + + /// + /// This property queries the database every time it is called, + /// to ensure the returned values are up-to-date. For best performance, + /// hold onto the returned collection if using it more than once. + ///
+ /// Gets the names of the columns that are primary keys of the table. + /// + public IListPrimaryKeys + { + get + { + return this.primaryKeys; + } + } + + /// + /// Gets an SQL CREATE string that can be used to create the table. + /// + public string SqlCreateString + { + get + { + StringBuilder s = new StringBuilder("CREATE TABLE `"); + s.Append(this.name); + s.Append("` ("); + int count = 0; + foreach (ColumnInfo col in this.Columns) + { + if (count > 0) + { + s.Append(", "); + } + s.Append(col.SqlCreateString); + count++; + } + s.Append(" PRIMARY KEY "); + count = 0; + foreach (string key in this.PrimaryKeys) + { + if (count > 0) + { + s.Append(", "); + } + s.AppendFormat("`{0}`", key); + count++; + } + s.Append(')'); + return s.ToString(); + } + } + + ///+ /// Gets an SQL INSERT string that can be used insert a new record into the table. + /// + ///+ public string SqlInsertString + { + get + { + StringBuilder s = new StringBuilder("INSERT INTO `"); + s.Append(this.name); + s.Append("` ("); + int count = 0; + foreach (ColumnInfo col in this.Columns) + { + if (count > 0) + { + s.Append(", "); + } + + s.AppendFormat("`{0}`", col.Name); + count++; + } + s.Append(") VALUES ("); + while (count > 0) + { + count--; + s.Append("?"); + + if (count > 0) + { + s.Append(", "); + } + } + s.Append(')'); + return s.ToString(); + } + } + + /// + /// The values are expressed as question-mark tokens, to be supplied by the record. + ///
+ /// Gets an SQL SELECT string that can be used to select all columns of the table. + /// + ///+ public string SqlSelectString + { + get + { + StringBuilder s = new StringBuilder("SELECT "); + int count = 0; + foreach (ColumnInfo col in this.Columns) + { + if (count > 0) s.Append(", "); + s.AppendFormat("`{0}`", col.Name); + count++; + } + s.AppendFormat(" FROM `{0}`", this.Name); + return s.ToString(); + } + } + + /// + /// The columns are listed explicitly in the SELECT string, as opposed to using "SELECT *". + ///
+ /// Gets a string representation of the table. + /// + ///The name of the table. + public override string ToString() + { + return this.name; + } + + private static IListGetTablePrimaryKeys(Database db, string table) + { + if (table == "_Tables") + { + return new string[] { "Name" }; + } + else if (table == "_Columns") + { + return new string[] { "Table", "Number" }; + } + else if (table == "_Storages") + { + return new string[] { "Name" }; + } + else if (table == "_Streams") + { + return new string[] { "Name" }; + } + else + { + int hrec; + uint ret = RemotableNativeMethods.MsiDatabaseGetPrimaryKeys( + (int) db.Handle, table, out hrec); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + + using (Record rec = new Record((IntPtr) hrec, true, null)) + { + string[] keys = new string[rec.FieldCount]; + for (int i = 0; i < keys.Length; i++) + { + keys[i] = rec.GetString(i + 1); + } + + return keys; + } + } + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Transaction.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Transaction.cs new file mode 100644 index 00000000..798dc79e --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/Transaction.cs @@ -0,0 +1,201 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.Runtime.InteropServices; + using System.Threading; + + /// + /// [MSI 4.5] Handle to a multi-session install transaction. + /// + ///+ public class Transaction : InstallerHandle + { + private string name; + private IntPtr ownerChangeEvent; + private IList + /// Win32 MSI APIs: + /// MsiBeginTransaction + /// MsiJoinTransaction + /// MsiEndTransaction + ///
> ownerChangeListeners; + + /// + /// [MSI 4.5] Begins transaction processing of a multi-package installation. + /// + /// Name of the multi-package installation. + /// Select optional behavior when beginning the transaction. + ///The transaction could not be initialized. + ///+ public Transaction(string name, TransactionAttributes attributes) + : this(name, Transaction.Begin(name, attributes), true) + { + } + + /// + /// Win32 MSI API: + /// MsiBeginTransaction + ///
+ /// Internal constructor. + /// + ///+ /// The second parameter is an array in order to receive multiple values from the initialization method. + /// + private Transaction(string name, IntPtr[] handles, bool ownsHandle) + : base(handles[0], ownsHandle) + { + this.name = name; + this.ownerChangeEvent = handles[1]; + this.ownerChangeListeners = new List>(); + } + + /// + /// Creates a new Transaction object from an integer handle. + /// + /// Integer transaction handle + /// true to close the handle when this object is disposed + public static Transaction FromHandle(IntPtr handle, bool ownsHandle) + { + return new Transaction(handle.ToString(), new IntPtr[] { handle, IntPtr.Zero }, ownsHandle); + } + + ///+ /// Gets the name of the transaction. + /// + public string Name + { + get + { + return name; + } + } + + ///+ /// Notifies listeners when the process that owns the transaction changed. + /// + public event EventHandlerOwnerChanged + { + add + { + this.ownerChangeListeners.Add(value); + + if (this.ownerChangeEvent != IntPtr.Zero && this.ownerChangeListeners.Count == 1) + { + new Thread(this.WaitForOwnerChange).Start(); + } + } + remove + { + this.ownerChangeListeners.Remove(value); + } + } + + private void OnOwnerChanged() + { + EventArgs e = new EventArgs(); + foreach (EventHandler handler in this.ownerChangeListeners) + { + handler(this, e); + } + } + + private void WaitForOwnerChange() + { + int ret = NativeMethods.WaitForSingleObject(this.ownerChangeEvent, -1); + if (ret == 0) + { + this.OnOwnerChanged(); + } + else + { + throw new InstallerException(); + } + } + + /// + /// Makes the current process the owner of the multi-package installation transaction. + /// + /// Select optional behavior when joining the transaction. + ///The transaction handle is not valid. + ///The transaction could not be joined. + ///+ public void Join(TransactionAttributes attributes) + { + IntPtr hChangeOfOwnerEvent; + uint ret = NativeMethods.MsiJoinTransaction((int) this.Handle, (int) attributes, out hChangeOfOwnerEvent); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + + this.ownerChangeEvent = hChangeOfOwnerEvent; + if (this.ownerChangeEvent != IntPtr.Zero && this.ownerChangeListeners.Count >= 1) + { + new Thread(this.WaitForOwnerChange).Start(); + } + } + + /// + /// Win32 MSI API: + /// MsiJoinTransaction + ///
+ /// Ends the install transaction and commits all changes to the system belonging to the transaction. + /// + ///The transaction could not be committed. + ///+ public void Commit() + { + this.End(true); + } + + /// + /// Runs any Commit Custom Actions and commits to the system any changes to Win32 or common language + /// runtime assemblies. Deletes the rollback script, and after using this option, the transaction's + /// changes can no longer be undone with a Rollback Installation. + ///
+ /// This method can only be called by the current owner of the transaction. + ///
+ /// Win32 MSI API: + /// MsiEndTransaction + ///
+ /// Ends the install transaction and undoes changes to the system belonging to the transaction. + /// + ///The transaction could not be rolled back. + ///+ public void Rollback() + { + this.End(false); + } + + private static IntPtr[] Begin(string transactionName, TransactionAttributes attributes) + { + int hTransaction; + IntPtr hChangeOfOwnerEvent; + uint ret = NativeMethods.MsiBeginTransaction(transactionName, (int) attributes, out hTransaction, out hChangeOfOwnerEvent); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + + return new IntPtr[] { (IntPtr) hTransaction, hChangeOfOwnerEvent }; + } + + [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")] + private void End(bool commit) + { + uint ret = NativeMethods.MsiEndTransaction(commit ? 1 : 0); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/ValidationErrorInfo.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/ValidationErrorInfo.cs new file mode 100644 index 00000000..3f75326e --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/ValidationErrorInfo.cs @@ -0,0 +1,46 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System.Diagnostics.CodeAnalysis; + + /// + /// This method can only be called by the current owner of the transaction. + ///
+ /// Win32 MSI API: + /// MsiEndTransaction + ///
+ /// Contains specific information about an error encountered by the + [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] + public struct ValidationErrorInfo + { + private ValidationError error; + private string column; + + internal ValidationErrorInfo(ValidationError error, string column) + { + this.error = error; + this.column = column; + } + + ///, + /// , or methods of the + /// class. + /// + /// Gets the type of validation error encountered. + /// + public ValidationError Error + { + get + { + return this.error; + } + } + + ///+ /// Gets the column containing the error, or null if the error applies to the whole row. + /// + public string Column + { + get + { + return this.column; + } + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/View.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/View.cs new file mode 100644 index 00000000..21e8543e --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/View.cs @@ -0,0 +1,625 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.Text; + using System.Collections.Generic; + using System.Globalization; + using System.Diagnostics.CodeAnalysis; + + ///+ /// A View represents a result set obtained when processing a query using the + /// + [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] + public class View : InstallerHandle, IEnumerablemethod of a + /// . Before any data can be transferred, + /// the query must be executed using the method, passing to + /// it all replaceable parameters designated within the SQL query string. + /// + { + private Database database; + private string sql; + private IList tables; + private ColumnCollection columns; + + internal View(IntPtr handle, string sql, Database database) + : base(handle, true) + { + this.sql = sql; + this.database = database; + } + + /// + /// Gets the Database on which this View was opened. + /// + public Database Database + { + get { return this.database; } + } + + ///+ /// Gets the SQL query string used to open this View. + /// + public string QueryString + { + get { return this.sql; } + } + + ///+ /// Gets the set of tables that were included in the SQL query for this View. + /// + public IListTables + { + get + { + if (this.tables == null) + { + if (this.sql == null) + { + return null; + } + + // Parse the table names out of the SQL query string by looking + // for tokens that can come before or after the list of tables. + + string parseSql = this.sql.Replace('\t', ' ').Replace('\r', ' ').Replace('\n', ' '); + string upperSql = parseSql.ToUpper(CultureInfo.InvariantCulture); + + string[] prefixes = new string[] { " FROM ", " INTO ", " TABLE " }; + string[] suffixes = new string[] { " WHERE ", " ORDER ", " SET ", " (", " ADD " }; + + int index; + + for (int i = 0; i < prefixes.Length; i++) + { + if ((index = upperSql.IndexOf(prefixes[i], StringComparison.Ordinal)) > 0) + { + parseSql = parseSql.Substring(index + prefixes[i].Length); + upperSql = upperSql.Substring(index + prefixes[i].Length); + } + } + + if (upperSql.StartsWith("UPDATE ", StringComparison.Ordinal)) + { + parseSql = parseSql.Substring(7); + upperSql = upperSql.Substring(7); + } + + for (int i = 0; i < suffixes.Length; i++) + { + if ((index = upperSql.IndexOf(suffixes[i], StringComparison.Ordinal)) > 0) + { + parseSql = parseSql.Substring(0, index); + upperSql = upperSql.Substring(0, index); + } + } + + if (upperSql.EndsWith(" HOLD", StringComparison.Ordinal) || + upperSql.EndsWith(" FREE", StringComparison.Ordinal)) + { + parseSql = parseSql.Substring(0, parseSql.Length - 5); + upperSql = upperSql.Substring(0, upperSql.Length - 5); + } + + // At this point we should be left with a comma-separated list of table names, + // optionally quoted with grave accent marks (`). + + string[] tableNames = parseSql.Split(','); + IList tableList = new List (tableNames.Length); + for (int i = 0; i < tableNames.Length; i++) + { + string tableName = tableNames[i].Trim(' ', '`'); + tableList.Add(new TableInfo(this.database, tableName)); + } + this.tables = tableList; + } + return new List (this.tables); + } + } + + /// + /// Gets the set of columns that were included in the query for this View, + /// or null if this view is not a SELECT query. + /// + ///the View is not in an active state + ///the View handle is invalid + ///+ public ColumnCollection Columns + { + get + { + if (this.columns == null) + { + this.columns = new ColumnCollection(this); + } + return this.columns; + } + } + + /// + /// Win32 MSI API: + /// MsiViewGetColumnInfo + ///
+ /// Executes a SQL View query and supplies any required parameters. The query uses the + /// question mark token to represent parameters as described in SQL Syntax. The values of + /// these parameters are passed in as the corresponding fields of a parameter record. + /// + /// Optional Record that supplies the parameters. This + /// Record contains values to replace the parameter tokens in the SQL query. + ///the View could not be executed + ///the View handle is invalid + ///+ [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Params"), SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public void Execute(Record executeParams) + { + uint ret = RemotableNativeMethods.MsiViewExecute( + (int) this.Handle, + (executeParams != null ? (int) executeParams.Handle : 0)); + if (ret == (uint) NativeMethods.Error.BAD_QUERY_SYNTAX) + { + throw new BadQuerySyntaxException(this.sql); + } + else if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// Win32 MSI API: + /// MsiViewExecute + ///
+ /// Executes a SQL View query. + /// + ///the View could not be executed + ///the View handle is invalid + ///+ public void Execute() { this.Execute(null); } + + /// + /// Win32 MSI API: + /// MsiViewExecute + ///
+ /// Fetches the next sequential record from the view, or null if there are no more records. + /// + ///the View is not in an active state + ///the View handle is invalid + ///+ public Record Fetch() + { + int recordHandle; + uint ret = RemotableNativeMethods.MsiViewFetch((int) this.Handle, out recordHandle); + if (ret == (uint) NativeMethods.Error.NO_MORE_ITEMS) + { + return null; + } + else if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + + Record r = new Record((IntPtr) recordHandle, true, this); + r.IsFormatStringInvalid = true; + return r; + } + + /// + /// The Record object should be
d after use. + /// It is best that the handle be closed manually as soon as it is no longer + /// needed, as leaving lots of unused handles open can degrade performance. + /// + /// Win32 MSI API: + /// MsiViewFetch + ///
+ /// Updates a fetched Record. + /// + /// specifies the modify mode + /// the Record to modify + ///the modification failed, + /// or a validation was requested and the data did not pass + ///the View handle is invalid + ///+ /// + /// You can update or delete a record immediately after inserting, or seeking provided you + /// have NOT modified the 0th field of the inserted or sought record. + ///
+ /// To execute any SQL statement, a View must be created. However, a View that does not + /// create a result set, such as CREATE TABLE, or INSERT INTO, cannot be used with any of + /// the Modify methods to update tables though the view. + ///
+ /// You cannot fetch a record containing binary data from one database and then use + /// that record to insert the data into another database. To move binary data from one database + /// to another, you should export the data to a file and then import it into the new database + /// using a query and the
. This ensures that each database has + /// its own copy of the binary data. + /// + /// Note that custom actions can only add, modify, or remove temporary rows, columns, + /// or tables from a database. Custom actions cannot modify persistent data in a database, + /// such as data that is a part of the database stored on disk. + ///
+ /// Win32 MSI API: + /// MsiViewModify + ///
+ /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public void Modify(ViewModifyMode mode, Record record) + { + if (record == null) + { + throw new ArgumentNullException("record"); + } + + uint ret = RemotableNativeMethods.MsiViewModify((int) this.Handle, (int) mode, (int) record.Handle); + if (mode == ViewModifyMode.Insert || mode == ViewModifyMode.InsertTemporary) + { + record.IsFormatStringInvalid = true; + } + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + } + + /// + /// Refreshes the data in a Record. + /// + /// the Record to be refreshed + ///the refresh failed + ///the View handle is invalid + ///+ public void Refresh(Record record) { this.Modify(ViewModifyMode.Refresh, record); } + + /// + /// The Record must have been obtained by calling
. Fails with + /// a deleted Record. Works only with read-write Records. + /// + /// See
for more remarks. + /// + /// Win32 MSI API: + /// MsiViewModify + ///
+ /// Inserts a Record into the view. + /// + /// the Record to be inserted + ///the insertion failed + ///the View handle is invalid + ///+ public void Insert(Record record) { this.Modify(ViewModifyMode.Insert, record); } + + /// + /// Fails if a row with the same primary keys exists. Fails with a read-only database. + /// This method cannot be used with a View containing joins. + ///
+ /// See
for more remarks. + /// + /// Win32 MSI API: + /// MsiViewModify + ///
+ /// Updates the View with new data from the Record. + /// + /// the new data + ///the update failed + ///the View handle is invalid + ///+ public void Update(Record record) { this.Modify(ViewModifyMode.Update, record); } + + /// + /// Only non-primary keys can be updated. The Record must have been obtained by calling + ///
. Fails with a deleted Record. Works only with read-write Records. + /// + /// See
for more remarks. + /// + /// Win32 MSI API: + /// MsiViewModify + ///
+ /// Updates or inserts a Record into the View. + /// + /// the Record to be assigned + ///the assignment failed + ///the View handle is invalid + ///+ public void Assign(Record record) { this.Modify(ViewModifyMode.Assign, record); } + + /// + /// Updates record if the primary keys match an existing row and inserts if they do not match. + /// Fails with a read-only database. This method cannot be used with a View containing joins. + ///
+ /// See
for more remarks. + /// + /// Win32 MSI API: + /// MsiViewModify + ///
+ /// Updates or deletes and inserts a Record into the View. + /// + /// the Record to be replaced + ///the replacement failed + ///the View handle is invalid + ///+ public void Replace(Record record) { this.Modify(ViewModifyMode.Replace, record); } + + /// + /// The Record must have been obtained by calling
. Updates record if the + /// primary keys are unchanged. Deletes old row and inserts new if primary keys have changed. + /// Fails with a read-only database. This method cannot be used with a View containing joins. + /// + /// See
for more remarks. + /// + /// Win32 MSI API: + /// MsiViewModify + ///
+ /// Deletes a Record from the View. + /// + /// the Record to be deleted + ///the deletion failed + ///the View handle is invalid + ///+ public void Delete(Record record) { this.Modify(ViewModifyMode.Delete, record); } + + /// + /// The Record must have been obtained by calling
. Fails if the row has been + /// deleted. Works only with read-write records. This method cannot be used with a View containing joins. + /// + /// See
for more remarks. + /// + /// Win32 MSI API: + /// MsiViewModify + ///
+ /// Inserts a Record into the View. The inserted data is not persistent. + /// + /// the Record to be inserted + ///the insertion failed + ///the View handle is invalid + ///+ public void InsertTemporary(Record record) { this.Modify(ViewModifyMode.InsertTemporary, record); } + + /// + /// Fails if a row with the same primary key exists. Works only with read-write records. + /// This method cannot be used with a View containing joins. + ///
+ /// See
for more remarks. + /// + /// Win32 MSI API: + /// MsiViewModify + ///
+ /// Refreshes the information in the supplied record without changing the position + /// in the result set and without affecting subsequent fetch operations. + /// + /// the Record to be filled with the result of the seek + ///the seek failed + ///the View handle is invalid + ///+ [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public bool Seek(Record record) + { + if (record == null) + { + throw new ArgumentNullException("record"); + } + + uint ret = RemotableNativeMethods.MsiViewModify((int) this.Handle, (int) ViewModifyMode.Seek, (int) record.Handle); + record.IsFormatStringInvalid = true; + if (ret == (uint) NativeMethods.Error.FUNCTION_FAILED) + { + return false; + } + else if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + + return true; + } + + /// + /// After seeking, the Record may then be used for subsequent Update, Delete, and Refresh + /// operations. All primary key columns of the table must be in the query and the Record must + /// have at least as many fields as the query. Seek cannot be used with multi-table queries. + /// This method cannot be used with a View containing joins. + ///
+ /// See
for more remarks. + /// + /// Win32 MSI API: + /// MsiViewModify + ///
+ /// Inserts or validates a record. + /// + /// the Record to be merged + ///true if the record was inserted or validated, false if there is an existing + /// record with the same primary keys that is not identical + ///the merge failed (for a reason other than invalid data) + ///the View handle is invalid + ///+ [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public bool Merge(Record record) + { + if (record == null) + { + throw new ArgumentNullException("record"); + } + + uint ret = RemotableNativeMethods.MsiViewModify((int) this.Handle, (int) ViewModifyMode.Merge, (int) record.Handle); + if (ret == (uint) NativeMethods.Error.FUNCTION_FAILED) + { + return false; + } + else if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + return true; + } + + /// + /// Works only with read-write records. This method cannot be used with a + /// View containing joins. + ///
+ /// See
for more remarks. + /// + /// Win32 MSI API: + /// MsiViewModify + ///
+ /// Validates a record, returning information about any errors. + /// + /// the Record to be validated + ///null if the record was validated; if there is an existing record with + /// the same primary keys that has conflicting data then error information is returned + ///the validation failed (for a reason other than invalid data) + ///the View handle is invalid + ///+ public ICollection + /// The Record must have been obtained by calling
. + /// Works with read-write and read-only records. This method cannot be used + /// with a View containing joins. + /// + /// See
for more remarks. + /// + /// Win32 MSI APIs: + /// MsiViewModify, + /// MsiViewGetError + ///
Validate(Record record) { return this.InternalValidate(ViewModifyMode.Validate, record); } + + /// + /// Validates a new record, returning information about any errors. + /// + /// the Record to be validated + ///null if the record was validated; if there is an existing + /// record with the same primary keys then error information is returned + ///the validation failed (for a reason other than invalid data) + ///the View handle is invalid + ///+ [SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")] + public ICollection + /// Checks for duplicate keys. The Record must have been obtained by + /// calling
. Works with read-write and read-only records. + /// This method cannot be used with a View containing joins. + /// + /// See
for more remarks. + /// + /// Win32 MSI APIs: + /// MsiViewModify, + /// MsiViewGetError + ///
ValidateNew(Record record) { return this.InternalValidate(ViewModifyMode.ValidateNew, record); } + + /// + /// Validates fields of a fetched or new record, returning information about any errors. + /// Can validate one or more fields of an incomplete record. + /// + /// the Record to be validated + ///null if the record was validated; if there is an existing record with + /// the same primary keys that has conflicting data then error information is returned + ///the validation failed (for a reason other than invalid data) + ///the View handle is invalid + ///+ public ICollection + /// Works with read-write and read-only records. This method cannot be used with + /// a View containing joins. + ///
+ /// See
for more remarks. + /// + /// Win32 MSI APIs: + /// MsiViewModify, + /// MsiViewGetError + ///
ValidateFields(Record record) { return this.InternalValidate(ViewModifyMode.ValidateField, record); } + + /// + /// Validates a record that will be deleted later, returning information about any errors. + /// + /// the Record to be validated + ///null if the record is safe to delete; if another row refers to + /// the primary keys of this row then error information is returned + ///the validation failed (for a reason other than invalid data) + ///the View handle is invalid + ///+ public ICollection + /// Validation does not check for the existence of the primary keys of this row in properties + /// or strings. Does not check if a column is a foreign key to multiple tables. Works with + /// read-write and read-only records. This method cannot be used with a View containing joins. + ///
+ /// See
for more remarks. + /// + /// Win32 MSI APIs: + /// MsiViewModify, + /// MsiViewGetError + ///
ValidateDelete(Record record) { return this.InternalValidate(ViewModifyMode.ValidateDelete, record); } + + /// + /// Enumerates over the Records retrieved by the View. + /// + ///An enumerator of Record objects. + ///The View was not + ///d before attempting the enumeration. + public IEnumerator + /// Each Record object should be
d after use. + /// It is best that the handle be closed manually as soon as it is no longer + /// needed, as leaving lots of unused handles open can degrade performance. + /// However, note that it is not necessary to complete the enumeration just + /// for the purpose of closing handles, because Records are fetched lazily + /// on each step of the enumeration. + /// + /// Win32 MSI API: + /// MsiViewFetch + ///
GetEnumerator() + { + Record rec; + while ((rec = this.Fetch()) != null) + { + yield return rec; + } + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + private ICollection InternalValidate(ViewModifyMode mode, Record record) + { + uint ret = RemotableNativeMethods.MsiViewModify((int) this.Handle, (int) mode, (int) record.Handle); + if (ret == (uint) NativeMethods.Error.INVALID_DATA) + { + ICollection errorInfo = new List (); + while (true) + { + uint bufSize = 40; + StringBuilder column = new StringBuilder("", (int) bufSize); + int error = RemotableNativeMethods.MsiViewGetError((int) this.Handle, column, ref bufSize); + if (error == -2 /*MSIDBERROR_MOREDATA*/) + { + column.Capacity = (int) ++bufSize; + error = RemotableNativeMethods.MsiViewGetError((int) this.Handle, column, ref bufSize); + } + + if (error == -3 /*MSIDBERROR_INVALIDARG*/) + { + throw InstallerException.ExceptionFromReturnCode((uint) NativeMethods.Error.INVALID_PARAMETER); + } + else if (error == 0 /*MSIDBERROR_NOERROR*/) + { + break; + } + + errorInfo.Add(new ValidationErrorInfo((ValidationError) error, column.ToString())); + } + + return errorInfo; + } + else if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + return null; + } + } +} diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/WindowsInstaller.cd b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/WindowsInstaller.cd new file mode 100644 index 00000000..01b68153 --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/WindowsInstaller.cd @@ -0,0 +1,943 @@ + + + \ No newline at end of file diff --git a/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/customactiondata.cs b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/customactiondata.cs new file mode 100644 index 00000000..88a0295d --- /dev/null +++ b/BurnOutSharp/External/WixToolset/WixToolset.Dtf.WindowsInstaller/customactiondata.cs @@ -0,0 +1,469 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Dtf.WindowsInstaller +{ + using System; + using System.IO; + using System.Xml; + using System.Xml.Serialization; + using System.Text; + using System.Collections.Generic; + using System.Globalization; + using System.Diagnostics.CodeAnalysis; + + ///+ ++ + ++ + ++ + ++ + ++ + ++ + ++ + ++ + ++ + + + + + + + + + ++ ++ + + + + ++ ++ + + + ++ + ++ ++ + + ++ + +QABACUgAACAAIAVUIAgQREACAAIAk0ABAIhmoEAAAAA= +Database.cs ++ ++ + ++ + ++ + ++ + + + + + + +AAAAAAAAACAAAACAgAAAAAAAAAAAAMIAAAACAACAAAA= +Handle.cs ++ + ++ + ++ + + + + + + + + +IAQBiIgAgAKAAAAELEAAPBgJAUAAYAAAAOQDagAgAQE= +ExternalUIHandler.cs ++ ++ + ++ + + + + + ++ ++ + + + + +AIAAAAAAAAAAAIAEiEIAJAAAAQgIEIAIIQCAAABIAAA= +Record.cs ++ ++ + ++ + + + + ++ ++ + + + ++ ++ + + + ++ + ++ ++ + + ++ + ++ ++ + +AAAAEAAAKGAAAoDADIBBAAAAAAgIEABBEIAAIAAACAA= +Session.cs ++ ++ + ++ + + + ++ + ++ + + + + ++ ++ + + + +AQAAAAAAAEAAAEAAjMgAAJIAAAEAAAAAAAAEhAAAoCI= +SummaryInfo.cs ++ ++ + ++ + + + + + + + ++ ++ + + ++ ++ + + + ++ + ++ ++ + + + ++ + +ICQAIEQAAEDgABRACQEAQECBAAEAAQAACAAAAAgAACA= +View.cs ++ ++ + ++ + + ++ + ++ + + + + + + ++ ++ + + + ++ + +AAAAAAAAAEAAAAAEACAAAAQAQAAEAAAASAAAAAgAAAA= +TableInfo.cs ++ ++ + ++ + ++ + + + + + + + + +AgAAAAAAAAAAgCAEEIAAABQgQAAFIAAAAQAAAAIAEAA= +ColumnInfo.cs ++ ++ + ++ + + +AAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAAAAAAAAAAAAA= +CustomActionAttribute.cs ++ ++ + ++ + + + + + + + ++ ++ + + + ++ + +AAACIhAAAoAQAACACAAAAABAAAAAAAAAAAAEAAAAAAA= +Installation.cs ++ ++ + ++ + ++ + + + + + ++ ++ + + + + + ++ + +AAAiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAIgA= +InstallationPart.cs ++ ++ + ++ + ++ + + + + + + ++ ++ + + + ++ ++ + + + + ++ + ++ ++ + + ++ + +UAIEYrAGAAAACQBAKEABAAoASA0ARQAASUIGBAAIIAA= +ProductInstallation.cs ++ ++ + + ++ + ++ + + + + + ++ ++ + + ++ ++ + + + + ++ + +AAAgsgCACAAAAAAAKEAAAgAAAgAAAAAAAgIAFAAAIAA= +PatchInstallation.cs ++ ++ + ++ + ++ + + + + + ++ + ++ ++ +ComponentInstallation.cs ++ ++ ++ + + ++ ++ + + + + ++ + ++ ++ + + ++ + +AUAAAAACAAAAAAIAEAgQAAQAAAAAAAAEAAAABAAAAAA= +ComponentInstallation.cs ++ ++ + + ++ + ++ + ++ + ++ ++ +FeatureInstallation.cs ++ ++ ++ + + + +AAAAAAAAAAAAAAAAAAAAAAAEAAAAACAAAAAABAAAAAA= +FeatureInstallation.cs ++ ++ + ++ + + + + + + + + ++ ++ + + + ++ + +BCIAAEAAEABAABgQCAAABIQAAFAQAAAAAAAABARwIgA= +SourceList.cs ++ ++ + + ++ + ++ + + + +AQAAAAIAAAAAAAAAAAEAACQAAAAEAAAAAAAAAAAAAAA= +ComponentInfo.cs ++ ++ + ++ + + + +AQAAAAIAAAggAEAAAAEAACQQAAAEAAAAAAAAAAAAAAA= +FeatureInfo.cs ++ ++ + ++ + + + + + + + + +hAAAAAAAAAAAAAQAAAAAAAAgAAgIAAAIAAABIAAAQAA= +Exceptions.cs ++ ++ + ++ + ++ ++ + + +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= +Exceptions.cs ++ ++ + ++ + ++ ++ + + + + +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= +Exceptions.cs ++ ++ + ++ + ++ ++ + + + +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= +Exceptions.cs ++ ++ + ++ + + + + ++ ++ + + +AAAAAAAAAAAAAEAAEABAABAgAAAAAAAAAAAAIAAAAAA= +Exceptions.cs ++ ++ + ++ + + + + +AgAAAAAAAAAAAAAAAgAAIAAAACAAAAAEAAAABAAAAAA= +MediaDisk.cs ++ ++ + ++ + + + + +AAAAAAAAAgAAAAIAAAAACBAAAAgQAAAAAAAAAAAAAAA= +InstallCost.cs ++ ++ + ++ + + + + + + + + +AAAgAAACAAAAAAAAgAAAAAAAAAAAAIAIAAIACAAAIiA= +ShortcutTarget.cs ++ ++ + +AAAAAAAAAAAAAAQgAAAAAAAAAgAAAACAAAAAAAACAAA= +Enums.cs ++ ++ + +AADAAlQAAAEgAoNFAAgAACAgAQAAAooMAAAAgCkCAkA= +ColumnEnums.cs ++ ++ + +AABCCFAAAAAhJAAHAAAAAoAAAAAAAAABCAIEEQEAgAA= +ColumnEnums.cs ++ ++ + +AAAKAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAYAAAAAAA= +Enums.cs ++ ++ + +AAABgEBAAIAAAQBAAAAAABEAAQAAABSAgAAEAEWQAAA= +Enums.cs ++ ++ + +AAABgABAAAAAAQBAAAAAABEAAQAAABSAgAAEAECAAAA= +Enums.cs ++ ++ + +AAAABAAAQAAAAAAAAAAAIAAAACAAAAAAAAAAAAAAAAA= +Enums.cs ++ ++ + +AAgAIEACAAQAAAQCAAAAAQAACEAABAQAgAECAAAAAgA= +Enums.cs ++ ++ + +AAAAABAAAgAAAFACgACQJAAAAABQAAQAAAAAAAAAABA= +Enums.cs ++ ++ + +AAAAAAAAAAAAAAAAIAAAIAAAAAAAAAAAAgAAAAAAAAA= +Enums.cs ++ ++ + +AAAAAAAIACAAAAAAQAAAIACEAAAAAAAAAgIAAAGAAAA= +Enums.cs ++ ++ + +AAAAAAAASAAQASBAAAAAAAAAACAAAAAAAAABAAEAAAA= +Enums.cs ++ ++ + +IAAAAAAAAACAAAAAAAAQAAAQBAAAABAAAAEAAgAIABA= +Enums.cs ++ ++ + +AAIEAAAAAAABAAAAAAAAAAQAAAAAAAACAAAgAAEAABA= +Enums.cs ++ ++ + +AAACAAAACAQIAAAAAAAAAAAAAEgAAAQAAIAQAQEAAAQ= +Enums.cs ++ ++ + +AAAAAAgAAAAAAAAEAAAAAAIAAAAAAAAAAIAAQAEAAAA= +Enums.cs ++ ++ + +oCMBAAABEAMAAAAAAAAQAAIASigAABKBABgCgEEAAA4= +Enums.cs ++ ++ + +IAQAAEQAAADgAAAACAAAAACAAAEAAQAAAAAAAAAAACA= +Enums.cs ++ ++ + +AAABAAAAIAAAAAAAEAAACAAAIAAAgQCAAAAgAAEAAAA= +ColumnEnums.cs ++ ++ + +AAAIAAQAAAAAAQIEAAAAACAAEAAAAAAIgAAggAAAAgA= +ColumnEnums.cs ++ ++ + +AAAAQEAAAEAAAAAAAAAAAAAAEAAAAAABABAAAAEAAAA= +ColumnEnums.cs ++ ++ + +AAAAAABAAIAIAAAAAAAAAgAAAAAEAAAAAAEIAAEEAAA= +ColumnEnums.cs ++ ++ + +AggAAAAAAAAAEAEAAAAAAAAAAAABAAAAAAAAAAAAAAA= +ColumnEnums.cs ++ ++ + +ABAAABAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAABAAAA= +ColumnEnums.cs ++ ++ + +AACgACAAAIAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAA= +ColumnEnums.cs ++ ++ + +AAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAACAAAEAAAA= +ColumnEnums.cs ++ ++ + +AQCAAAAAQAAAAAAAAACAAAgAAAAAAAAAAgAAABEAAAI= +ColumnEnums.cs ++ ++ + +AAAAAAAAACAAAAAAAAAAEAAAAAEAAgAAJAAAAAEAAAA= +ColumnEnums.cs ++ ++ + +AAAAAAAAAAAAACAAAIAAAAAAAAACAAAAAAAAAAAAAAE= +ColumnEnums.cs ++ ++ + +AEAAAAAAAAAAAAAQAAAAAAAAAAgIAAAAABAAAAAAIAA= +ColumnEnums.cs ++ ++ + +AAAAAAAAAACAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAA= +Installer.cs ++ ++ + +AAAEAAAAAAAAABAAAAAABAAAAACBAAAAAAAAAAAAAAA= +ExternalUIHandler.cs ++ + ++ + +AAAEAAAAAAAAAAAAAAAABAAAAACBAAAAAAAAAAAAAAA= +ExternalUIHandler.cs ++ /// Contains a collection of key-value pairs suitable for passing between + /// immediate and deferred/rollback/commit custom actions. + /// + ///+ /// Call the + ///method to get a string + /// suitable for storing in a property and reconstructing the custom action data later. + /// + /// + [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] + public sealed class CustomActionData : IDictionary + { + /// + /// "CustomActionData" literal property name. + /// + public const string PropertyName = "CustomActionData"; + + private const char DataSeparator = ';'; + private const char KeyValueSeparator = '='; + + private IDictionarydata; + + /// + /// Creates a new empty custom action data object. + /// + public CustomActionData() : this(null) + { + } + + ///+ /// Reconstructs a custom action data object from data that was previously + /// persisted in a string. + /// + /// Previous output from. + public CustomActionData(string keyValueList) + { + this.data = new Dictionary (); + + if (keyValueList != null) + { + this.Parse(keyValueList); + } + } + + /// + /// Adds a key and value to the data collection. + /// + /// Case-sensitive data key. + /// Data value (may be null). + ///the key does not consist solely of letters, + /// numbers, and the period, underscore, and space characters. + public void Add(string key, string value) + { + CustomActionData.ValidateKey(key); + this.data.Add(key, value); + } + + ///+ /// Adds a value to the data collection, using XML serialization to persist the object as a string. + /// + /// Case-sensitive data key. + /// Data value (may be null). + ///the key does not consist solely of letters, + /// numbers, and the period, underscore, and space characters. + ///The value type does not support XML serialization. + ///The value could not be serialized. + public void AddObject(string key, T value) + { + if (value == null) + { + this.Add(key, null); + } + else if (typeof(T) == typeof(string) || + typeof(T) == typeof(CustomActionData)) // Serialize nested CustomActionData + { + this.Add(key, value.ToString()); + } + else + { + string valueString = CustomActionData.Serialize (value); + this.Add(key, valueString); + } + } + + /// + /// Gets a value from the data collection, using XML serialization to load the object from a string. + /// + /// Case-sensitive data key. + ///The value could not be deserialized. + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + public T GetObject(string key) + { + string value = this[key]; + if (value == null) + { + return default(T); + } + else if (typeof(T) == typeof(string)) + { + // Funny casting because the compiler doesn't know T is string here. + return (T) (object) value; + } + else if (typeof(T) == typeof(CustomActionData)) + { + // Deserialize nested CustomActionData. + return (T) (object) new CustomActionData(value); + } + else if (value.Length == 0) + { + return default(T); + } + else + { + return CustomActionData.Deserialize (value); + } + } + + /// + /// Determines whether the data contains an item with the specified key. + /// + /// Case-sensitive data key. + ///true if the data contains an item with the key; otherwise, false + public bool ContainsKey(string key) + { + return this.data.ContainsKey(key); + } + + ///+ /// Gets a collection object containing all the keys of the data. + /// + public ICollectionKeys + { + get + { + return this.data.Keys; + } + } + + /// + /// Removes the item with the specified key from the data. + /// + /// Case-sensitive data key. + ///true if the item was successfully removed from the data; + /// false if an item with the specified key was not found + public bool Remove(string key) + { + return this.data.Remove(key); + } + + ///+ /// Gets the value with the specified key. + /// + /// Case-sensitive data key. + /// Value associated with the specified key, or + /// null if an item with the specified key was not found + ///true if the data contains an item with the specified key; otherwise, false. + public bool TryGetValue(string key, out string value) + { + return this.data.TryGetValue(key, out value); + } + + ///+ /// Gets a collection containing all the values of the data. + /// + public ICollectionValues + { + get + { + return this.data.Values; + } + } + + /// + /// Gets or sets a data value with a specified key. + /// + /// Case-sensitive data key. + ///the key does not consist solely of letters, + /// numbers, and the period, underscore, and space characters. + public string this[string key] + { + get + { + return this.data[key]; + } + set + { + CustomActionData.ValidateKey(key); + this.data[key] = value; + } + } + + ///+ /// Adds an item with key and value to the data collection. + /// + /// Case-sensitive data key, with a data value that may be null. + ///the key does not consist solely of letters, + /// numbers, and the period, underscore, and space characters. + public void Add(KeyValuePairitem) + { + CustomActionData.ValidateKey(item.Key); + this.data.Add(item); + } + + /// + /// Removes all items from the data. + /// + public void Clear() + { + if (this.data.Count > 0) + { + this.data.Clear(); + } + } + + ///+ /// Determines whether the data contains a specified item. + /// + /// The data item to locate. + ///true if the data contains the item; otherwise, false + public bool Contains(KeyValuePairitem) + { + return this.data.Contains(item); + } + + /// + /// Copies the data to an array, starting at a particular array index. + /// + /// Destination array. + /// Index in the array at which copying begins. + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + this.data.CopyTo(array, arrayIndex); + } + + /// + /// Gets the number of items in the data. + /// + public int Count + { + get + { + return this.data.Count; + } + } + + ///+ /// Gets a value indicating whether the data is read-only. + /// + public bool IsReadOnly + { + get + { + return false; + } + } + + ///+ /// Removes an item from the data. + /// + /// The item to remove. + ///true if the item was successfully removed from the data; + /// false if the item was not found + public bool Remove(KeyValuePairitem) + { + return this.data.Remove(item); + } + + /// + /// Returns an enumerator that iterates through the collection. + /// + ///An enumerator that can be used to iterate through the collection. + public IEnumerator> GetEnumerator() + { + return this.data.GetEnumerator(); + } + + /// + /// Returns an enumerator that iterates through the collection. + /// + ///An enumerator that can be used to iterate through the collection. + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return ((System.Collections.IEnumerable) this.data).GetEnumerator(); + } + + ///+ /// Gets a string representation of the data suitable for persisting in a property. + /// + ///Data string in the form "Key1=Value1;Key2=Value2" + public override string ToString() + { + StringBuilder buf = new StringBuilder(); + + foreach (KeyValuePairitem in this.data) + { + if (buf.Length > 0) + { + buf.Append(CustomActionData.DataSeparator); + } + + buf.Append(item.Key); + + if (item.Value != null) + { + buf.Append(CustomActionData.KeyValueSeparator); + buf.Append(CustomActionData.Escape(item.Value)); + } + } + + return buf.ToString(); + } + + /// + /// Ensures that a key contains valid characters. + /// + /// key to be validated + ///the key does not consist solely of letters, + /// numbers, and the period, underscore, and space characters. + private static void ValidateKey(string key) + { + if (String.IsNullOrEmpty(key)) + { + throw new ArgumentNullException("key"); + } + + for (int i = 0; i < key.Length; i++) + { + char c = key[i]; + if (!Char.IsLetterOrDigit(c) && c != '_' && c != '.' && + !(i > 0 && i < key.Length - 1 && c == ' ')) + { + throw new ArgumentOutOfRangeException("key"); + } + } + } + + ///+ /// Serializes a value into an XML string. + /// + ///Type of the value. + /// Value to be serialized. + ///Serialized value data as a string. + private static string Serialize(T value) + { + XmlWriterSettings xws = new XmlWriterSettings(); + xws.OmitXmlDeclaration = true; + + StringWriter sw = new StringWriter(CultureInfo.InvariantCulture); + using (XmlWriter xw = XmlWriter.Create(sw, xws)) + { + XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); + ns.Add(string.Empty, String.Empty); // Prevent output of any namespaces + + XmlSerializer ser = new XmlSerializer(typeof(T)); + ser.Serialize(xw, value, ns); + + return sw.ToString(); + } + } + + /// + /// Deserializes a value from an XML string. + /// + ///Expected type of the value. + /// Serialized value data. + ///Deserialized value object. + private static T Deserialize(string value) + { + StringReader sr = new StringReader(value); + using (XmlReader xr = XmlReader.Create(sr)) + { + XmlSerializer ser = new XmlSerializer(typeof(T)); + return (T) ser.Deserialize(xr); + } + } + + /// + /// Escapes a value string by doubling any data-separator (semicolon) characters. + /// + /// + ///Escaped value string + private static string Escape(string value) + { + value = value.Replace(String.Empty + CustomActionData.DataSeparator, String.Empty + CustomActionData.DataSeparator + CustomActionData.DataSeparator); + return value; + } + + ///+ /// Unescapes a value string by undoubling any doubled data-separator (semicolon) characters. + /// + /// + ///Unescaped value string + private static string Unescape(string value) + { + value = value.Replace(String.Empty + CustomActionData.DataSeparator + CustomActionData.DataSeparator, String.Empty + CustomActionData.DataSeparator); + return value; + } + + ///+ /// Loads key-value pairs from a string into the data collection. + /// + /// key-value pair list of the form returned by+ private void Parse(string keyValueList) + { + int itemStart = 0; + while (itemStart < keyValueList.Length) + { + // Find the next non-escaped data separator. + int semi = itemStart - 2; + do + { + semi = keyValueList.IndexOf(CustomActionData.DataSeparator, semi + 2); + } + while (semi >= 0 && semi < keyValueList.Length - 1 && keyValueList[semi + 1] == CustomActionData.DataSeparator); + + if (semi < 0) + { + semi = keyValueList.Length; + } + + // Find the next non-escaped key-value separator. + int equals = itemStart - 2; + do + { + equals = keyValueList.IndexOf(CustomActionData.KeyValueSeparator, equals + 2); + } + while (equals >= 0 && equals < keyValueList.Length - 1 && keyValueList[equals + 1] == CustomActionData.KeyValueSeparator); + + if (equals < 0 || equals > semi) + { + equals = semi; + } + + string key = keyValueList.Substring(itemStart, equals - itemStart); + string value = null; + + // If there's a key-value separator before the next data separator, then the item has a value. + if (equals < semi) + { + value = keyValueList.Substring(equals + 1, semi - (equals + 1)); + value = CustomActionData.Unescape(value); + } + + // Add non-duplicate items to the collection. + if (key.Length > 0 && !this.data.ContainsKey(key)) + { + this.data.Add(key, value); + } + + // Move past the data separator to the next item. + itemStart = semi + 1; + } + } + } +} diff --git a/BurnOutSharp/FileType/MSI.cs b/BurnOutSharp/FileType/MSI.cs index 9c129e2f..23dd897d 100644 --- a/BurnOutSharp/FileType/MSI.cs +++ b/BurnOutSharp/FileType/MSI.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; using System.IO; -#if NET_FRAMEWORK -using Microsoft.Deployment.WindowsInstaller; -#endif +using WixToolset.Dtf.WindowsInstaller; namespace BurnOutSharp.FileType { @@ -12,10 +10,8 @@ namespace BurnOutSharp.FileType /// public bool ShouldScan(byte[] magic) { -#if NET_FRAMEWORK if (magic.StartsWith(new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 })) return true; -#endif return false; } @@ -36,7 +32,6 @@ namespace BurnOutSharp.FileType /// public Dictionary > Scan(Scanner scanner, Stream stream, string file) { -#if NET_FRAMEWORK // If the MSI file itself fails try { @@ -64,7 +59,6 @@ namespace BurnOutSharp.FileType return protections; } catch { } -#endif return null; } diff --git a/BurnOutSharp/FileType/MicrosoftCAB.cs b/BurnOutSharp/FileType/MicrosoftCAB.cs index 15af2669..a2c46205 100644 --- a/BurnOutSharp/FileType/MicrosoftCAB.cs +++ b/BurnOutSharp/FileType/MicrosoftCAB.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; using System.IO; -#if NET_FRAMEWORK using LibMSPackN; -#endif namespace BurnOutSharp.FileType { @@ -13,10 +11,8 @@ namespace BurnOutSharp.FileType /// public bool ShouldScan(byte[] magic) { -#if NET_FRAMEWORK if (magic.StartsWith(new byte[] { 0x4d, 0x53, 0x43, 0x46 })) return true; -#endif return false; } @@ -37,7 +33,6 @@ namespace BurnOutSharp.FileType /// public Dictionary > Scan(Scanner scanner, Stream stream, string file) { -#if NET_FRAMEWORK // If the cab file itself fails try { @@ -75,7 +70,6 @@ namespace BurnOutSharp.FileType return protections; } catch { } -#endif return null; } diff --git a/README.md b/README.md index cb875671..dedcb629 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ In addition to the original BurnOut code, the following libraries (or ports ther - [StormLibSharp](https://github.com/robpaveza/stormlibsharp) - MPQ extraction - [UnshieldSharp](https://github.com/mnadareski/UnshieldSharp) - InstallShield CAB extraction - [WiseUnpacker](https://github.com/mnadareski/WiseUnpacker) - Wise Installer extraction -- [wix-libs](https://wixtoolset.org/) - MSI extraction +- [WixToolset.Dtf](https://github.com/wixtoolset/Dtf) - MSI extraction ## Protections Detected @@ -105,7 +105,7 @@ Below is a list of archive or archive-like formats that can be extracted and hav - InstallShield CAB - Microsoft CAB - MPQ -- Microsoft Installer (MSI) (.NET Framework 4.7.2 and 4.8 only) +- Microsoft Installer (MSI) - PKZIP and derived files - RAR - TAR