Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1691 lines
51 KiB

  1. #include "headers.hxx"
  2. #include "..\CSVDSReader.hpp"
  3. #include "..\constants.hpp"
  4. #include "..\global.hpp"
  5. #include <winnls.h>
  6. ///////////// Basic Functions ///////////////
  7. // included so that sizeof(guids) works properlly
  8. #include "..\guids.inc"
  9. // used for parameter checking in wmain
  10. bool fileExists(const wchar_t *fileName,const wchar_t *mode=L"r")
  11. {
  12. FILE *f=_wfopen(fileName,mode);
  13. if(f==NULL) return false;
  14. fclose(f);
  15. return true;
  16. }
  17. // used for parameter checking in wmain
  18. #define BREAK_IF_MISSING(hr,fileName) \
  19. if(!fileExists(fileName.c_str())) \
  20. { \
  21. hr=E_FAIL; \
  22. wprintf(L"\n File Missing: %s.\n",fileName.c_str()); \
  23. break; \
  24. } \
  25. // used for parameter checking in wmain
  26. #define BREAK_IF_MISSING_OR_READONLY(hr,fileName) \
  27. BREAK_IF_MISSING(hr,fileName) \
  28. if(!fileExists(fileName.c_str(),L"a+")) \
  29. { \
  30. hr=E_FAIL; \
  31. wprintf(L"\n Read Only: %s.\n",fileName.c_str()); \
  32. break; \
  33. } \
  34. // converts outStr to AnsiString and writes to fileOut
  35. // Fails if conversion or writing fails
  36. HRESULT writeStringAsAnsi(HANDLE fileOut,const String& outStr)
  37. {
  38. AnsiString ansiStr;
  39. String::ConvertResult res=outStr.convert(ansiStr);
  40. if(res!=String::CONVERT_SUCCESSFUL)
  41. {
  42. ASSERT(res==String::CONVERT_SUCCESSFUL);
  43. error=L"Ansi conversion failed";
  44. return E_FAIL;
  45. }
  46. return FS::Write(fileOut,ansiStr);
  47. }
  48. // converts outStr to AnsiString and writes to fileOut
  49. // Fails if conversion or writing fails
  50. HRESULT printStringAsAnsi(const String& outStr)
  51. {
  52. AnsiString ansiStr;
  53. String::ConvertResult res=outStr.convert(ansiStr);
  54. if(res!=String::CONVERT_SUCCESSFUL)
  55. {
  56. ASSERT(res==String::CONVERT_SUCCESSFUL);
  57. error=L"Ansi conversion failed";
  58. return E_FAIL;
  59. }
  60. return printf(ansiStr.c_str());
  61. }
  62. // performs a-b, keys in a but not in b go to out
  63. template <class T,class Y,class less,class allocator>
  64. void mapKeyDifference
  65. (
  66. const map <T,Y,less,allocator> &a,
  67. const map <T,Y,less,allocator> &b,
  68. map <T,Y,less,allocator> &out
  69. )
  70. {
  71. out.clear();
  72. map <T,Y,less,allocator>::const_iterator cur=a.begin(),end=a.end();
  73. while(cur!=end)
  74. {
  75. if(b.find(cur->first)==b.end())
  76. {
  77. out[cur->first]=cur->second;
  78. }
  79. cur++;
  80. }
  81. }
  82. // true if all keys in a are in b and a.size()=b.size()
  83. template <class T,class Y,class less,class allocator>
  84. bool mapKeyEqual
  85. (
  86. const map <T,Y,less,allocator> &a,
  87. const map <T,Y,less,allocator> &b
  88. )
  89. {
  90. if (a.size()!=b.size()) return false;
  91. map <T,Y,less,allocator>::const_iterator cur=a.begin(),end=a.end();
  92. while(cur!=end)
  93. {
  94. if(b.find(cur->first)==b.end())
  95. {
  96. return false;
  97. }
  98. cur++;
  99. }
  100. return true;
  101. }
  102. // performs a ^ b, keys in both a and in b go to out
  103. template <class T,class Y,class less,class allocator>
  104. void mapKeyIntersection
  105. (
  106. const map <T,Y,less,allocator> &a,
  107. const map <T,Y,less,allocator> &b,
  108. map <T,Y,less,allocator> &out
  109. )
  110. {
  111. out.clear();
  112. map <T,Y,less,allocator>::const_iterator cur=a.begin(),end=a.end();
  113. while(cur!=end)
  114. {
  115. if(b.find(cur->first)!=b.end())
  116. {
  117. out[cur->first]=cur->second;
  118. }
  119. cur++;
  120. }
  121. }
  122. String escape(const String &str)
  123. {
  124. LOG_FUNCTION(escape);
  125. String dest;
  126. wchar_t strNum[7];
  127. const wchar_t *csr=str.c_str();
  128. while(*csr!=0)
  129. {
  130. wsprintf(strNum,L"\\x%x",*csr);
  131. dest+=String(strNum);
  132. csr++;
  133. }
  134. return dest;
  135. }
  136. HRESULT
  137. parseGUID
  138. (
  139. const String& str,
  140. long *ordinal,
  141. GUID *guid
  142. )
  143. {
  144. wchar_t *stop;
  145. HRESULT hr=S_OK;
  146. do
  147. {
  148. if (str.size()==0 || str[str.size()-1]!='}')
  149. {
  150. hr=E_FAIL;
  151. break;
  152. }
  153. String strAux=str.substr(0,str.size()-1);
  154. const wchar_t *strGuid=strAux.c_str();
  155. *ordinal=wcstol(strGuid,&stop,10);
  156. if(*stop!=L',' || *(stop+1)!=L'{' || stop==strGuid)
  157. {
  158. hr=E_FAIL;
  159. break;
  160. }
  161. if(UuidFromString(stop+2,guid)!=RPC_S_OK)
  162. {
  163. hr=E_FAIL;
  164. break;
  165. }
  166. } while(0);
  167. return hr;
  168. }
  169. bool isGuid(const String &str)
  170. {
  171. long ordinal;
  172. GUID guid;
  173. return SUCCEEDED(parseGUID(str,&ordinal,&guid));
  174. }
  175. String makeGuidString(long ordinal,GUID guid)
  176. {
  177. String ret;
  178. wchar_t *wRet;
  179. if(UuidToString(&guid,&wRet)!=RPC_S_OK) throw new bad_alloc;
  180. ret=String::format(L"%1!d!,{%2}",ordinal,wRet);
  181. RpcStringFree(&wRet);
  182. return ret;
  183. }
  184. ///////////// Basic Functions End ///////////////
  185. ///////////////////////////////////////////////////
  186. // Return the differences and commonalities between the
  187. // properties in oldCsv and newCsv. Uses csvName to specify
  188. // the csv in error messages.
  189. // Failure cases:
  190. // no common properties
  191. // properties in oldCsv not in newCsv
  192. HRESULT getPropertyChanges
  193. (
  194. const CSVDSReader &oldCsv,
  195. const CSVDSReader &newCsv,
  196. mapOfPositions &commonProperties,
  197. mapOfPositions &newProperties,
  198. const wchar_t *csvName
  199. )
  200. {
  201. const mapOfPositions &oldProps=oldCsv.getProperties();
  202. const mapOfPositions &newProps=newCsv.getProperties();
  203. mapKeyIntersection(oldProps,newProps,commonProperties);
  204. if(commonProperties.size()==0)
  205. {
  206. error=String::format(L"No comon %1!s! properties!",csvName);
  207. return E_FAIL;
  208. }
  209. mapOfPositions deletedProps;
  210. mapKeyDifference(oldProps,newProps,deletedProps);
  211. if(deletedProps.size()!=0)
  212. {
  213. error=String::format
  214. (
  215. L"Properties only in the old %1!s! are not supported, since"
  216. L"there is no operation to delete a property. there are %2!d!"
  217. L"properties like this and \"%3!s!\" is the first property.",
  218. csvName,deletedProps.size(),
  219. deletedProps.begin()->first
  220. );
  221. return E_FAIL;
  222. }
  223. mapKeyDifference(newProps,oldProps,newProperties);
  224. if(newProperties.size()==0)
  225. {
  226. wprintf(L"No new %s properties.\n",csvName);
  227. return S_OK;
  228. }
  229. return S_OK;
  230. }
  231. // Adds to commonProperties the commonProperties between oldDcpromo
  232. // and newDcpromo. and to new properties the properties in oldDcPromo
  233. // not in newDcpromo
  234. // Failure cases:
  235. // dcpromo's common properties are not the same as 409's
  236. // dcpromo's new properties are not the same as 409's
  237. HRESULT getAllPropertyChanges
  238. (
  239. const CSVDSReader &oldDcpromo,
  240. const CSVDSReader &newDcpromo,
  241. const CSVDSReader &old409,
  242. const CSVDSReader &new409,
  243. mapOfPositions &commonProperties,
  244. mapOfPositions &newProperties
  245. )
  246. {
  247. HRESULT hr=S_OK;
  248. do
  249. {
  250. hr=getPropertyChanges(
  251. oldDcpromo,
  252. newDcpromo,
  253. commonProperties,
  254. newProperties,
  255. L"dcpromo"
  256. );
  257. BREAK_ON_FAILED_HRESULT(hr);
  258. mapOfPositions prop409New,prop409Common;
  259. hr=getPropertyChanges(
  260. old409,
  261. new409,
  262. prop409Common,
  263. prop409New,
  264. L"409"
  265. );
  266. BREAK_ON_FAILED_HRESULT(hr);
  267. if(!mapKeyEqual(prop409New,newProperties))
  268. {
  269. error=L"409 and dcpromo new properties are not the same.";
  270. hr=E_FAIL;
  271. break;
  272. }
  273. if(!mapKeyEqual(prop409Common,commonProperties))
  274. {
  275. error=L"409 and dcpromo common properties are not the same.";
  276. hr=E_FAIL;
  277. break;
  278. }
  279. } while (0);
  280. return hr;
  281. }
  282. // Writes the very begining of a computer generated
  283. // file header to fileOut
  284. HRESULT writeHeader(const HANDLE fileOut)
  285. {
  286. char* header;
  287. header ="// This file is generated by preBuild.exe\r\n"
  288. "// Copyright (c) 2001 Microsoft Corporation\r\n"
  289. "// Nov 2001 lucios\r\n"
  290. "\r\n"
  291. "#include \"headers.hxx\"\r\n"
  292. "#include \"constants.hpp\"\r\n"
  293. "\r\n";
  294. return FS::Write(fileOut,AnsiString(header));
  295. }
  296. // Writes the nsetLocaleDependentChangesN function declaration to fileOut,
  297. // where N is the guidNumber.
  298. HRESULT writeChangesHeader(const HANDLE fileOut,int guidNumber)
  299. {
  300. String locDepStr=String::format
  301. (
  302. "\r\nvoid setChanges%1!d!()\r\n{\r\n",
  303. guidNumber
  304. );
  305. return writeStringAsAnsi(fileOut,locDepStr);
  306. }
  307. // Add an entry for the object/locale to fileOut.
  308. HRESULT writeChange
  309. (
  310. HANDLE fileOut,
  311. long locale,
  312. const String &object,
  313. const String &property,
  314. const String &arg1,
  315. const String &arg2,
  316. const String &operation,
  317. int guidNumber
  318. )
  319. {
  320. String entry=String::format
  321. (
  322. L"\r\n"
  323. L" addChange\r\n"
  324. L" (\r\n"
  325. L" guids[%1!d!],\r\n"
  326. L" 0x%2!x!,\r\n"
  327. L" L\"%3\",\r\n"
  328. L" L\"%4\",\r\n"
  329. L" //%5\r\n"
  330. L" L\"%6\",\r\n"
  331. L" //%7\n"
  332. L" L\"%8\",\r\n"
  333. L" %9\r\n"
  334. L" );\r\n\r\n",
  335. guidNumber,
  336. locale,
  337. object.c_str(),
  338. property.c_str(),
  339. arg1.c_str(),
  340. escape(arg1).c_str(),
  341. arg2.c_str(),
  342. escape(arg2).c_str(),
  343. operation.c_str()
  344. );
  345. return writeStringAsAnsi(fileOut,entry);
  346. }
  347. HRESULT dealWithSingleValue
  348. (
  349. HANDLE fileOut,
  350. long locale,
  351. const String &object,
  352. const String &property,
  353. const StringList &valuesOld,
  354. const StringList &valuesNew,
  355. int guidNumber
  356. )
  357. {
  358. // both sizes 0 is ok.
  359. if (valuesOld.size()==0 && valuesNew.size()==0) return S_OK;
  360. if (valuesOld.size()!=1 && valuesNew.size()!=1)
  361. {
  362. // In the future we might want to add ADD_VALUE and REMOVE_VALUE
  363. // operations, for now we just want to be flagged.
  364. error = String::format
  365. (
  366. L"Error in locale %1!x!, object %2,"
  367. L"property %3.Number of values should be 1,1 "
  368. L"instead of %4,%5.",
  369. locale,
  370. object.c_str(),
  371. property.c_str(),
  372. valuesOld.size(),
  373. valuesNew.size()
  374. );
  375. return E_FAIL;
  376. }
  377. // Now we know we have a single value in each
  378. if(*valuesOld.begin()!=*valuesNew.begin())
  379. {
  380. return
  381. (
  382. writeChange
  383. (
  384. fileOut,
  385. locale,
  386. object,
  387. property,
  388. *valuesOld.begin(),
  389. *valuesNew.begin(),
  390. L"REPLACE_W2K_SINGLE_VALUE",
  391. guidNumber
  392. )
  393. );
  394. }
  395. return S_OK;
  396. }
  397. // These are values in the form "root,rest"
  398. // if a value has the same root but a different rest we need to add
  399. // a REPLACE_MULTIPLE_VALUE_OPERATION
  400. // rotts in new that are not in old and roots in old that are not in new
  401. // should be printed for manual inclusion since we don't know how to deal
  402. // with them.
  403. typedef map<
  404. String,
  405. String,
  406. less<String>,
  407. Burnslib::Heap::Allocator<String>
  408. > rootToRest;
  409. HRESULT dealWithMultipleValue
  410. (
  411. HANDLE fileOut,
  412. long locale,
  413. const String &object,
  414. const String &property,
  415. const StringList &valuesOld,
  416. const StringList &valuesNew,
  417. int guidNumber
  418. )
  419. {
  420. HRESULT hr=S_OK;
  421. rootToRest newRoots, oldRoots;
  422. do
  423. {
  424. if(valuesOld.size()!=valuesNew.size())
  425. {
  426. error= String::format
  427. (
  428. L"Error in locale %1!x!, object %2,"
  429. L"property %3. Old has %4 values and new has %5. "
  430. L"They should have the same number of values.",
  431. locale,
  432. object.c_str(),
  433. property.c_str(),
  434. valuesOld.size(),
  435. valuesNew.size()
  436. );
  437. hr=E_FAIL;
  438. break;
  439. }
  440. // first lets add all roots and rests in maps
  441. // Starting by the old values...
  442. StringList::const_iterator csr,end;
  443. for(csr=valuesOld.begin(),end=valuesOld.end();csr!=end;csr++)
  444. {
  445. const String& value=*csr;
  446. long pos=value.find(L',');
  447. if(pos==String::npos) continue;
  448. String root=value.substr(0,pos);
  449. String rest=value.substr(pos+1);
  450. oldRoots[root]=rest;
  451. }
  452. BREAK_ON_FAILED_HRESULT(hr);
  453. //...And then the new values
  454. for(csr=valuesNew.begin(),end=valuesNew.end();csr!=end;csr++)
  455. {
  456. const String& value=*csr;
  457. long pos=value.find(L',');
  458. if(pos==String::npos) continue;
  459. String root=value.substr(0,pos);
  460. String rest=value.substr(pos+1);
  461. newRoots[root]=rest;
  462. }
  463. BREAK_ON_FAILED_HRESULT(hr);
  464. // now lets check all the values in one that are not in the other...
  465. rootToRest::iterator csrRoot=oldRoots.begin(),endRoot=oldRoots.end();
  466. rootToRest oldRootsNotInNew;
  467. for(;csrRoot!=endRoot;csrRoot++)
  468. {
  469. if(newRoots.find(csrRoot->first)==newRoots.end())
  470. {
  471. oldRootsNotInNew[csrRoot->first]=csrRoot->second;
  472. }
  473. }
  474. BREAK_ON_FAILED_HRESULT(hr);
  475. // ..and the values in other that are not in one, and...
  476. rootToRest newRootsNotInOld;
  477. csrRoot=newRoots.begin(),endRoot=newRoots.end();
  478. for(;csrRoot!=endRoot;csrRoot++)
  479. {
  480. if(oldRoots.find(csrRoot->first)==oldRoots.end())
  481. {
  482. newRootsNotInOld[csrRoot->first]=csrRoot->second;
  483. }
  484. }
  485. BREAK_ON_FAILED_HRESULT(hr);
  486. // ..if we have such values we need to investigate it further
  487. if(!oldRootsNotInNew.empty() || !newRootsNotInOld.empty())
  488. {
  489. // if we have exactly one "old value" not in "new" and one
  490. // "new value" not in "old" we are going to assume that the
  491. // "old value" should be replaced by the "new value"...
  492. if(oldRootsNotInNew.size()==1 && newRootsNotInOld.size()==1)
  493. {
  494. String arg1=String::format
  495. (
  496. L"%1,%2",
  497. oldRootsNotInNew.begin()->first.c_str(),
  498. oldRootsNotInNew.begin()->second.c_str()
  499. );
  500. String arg2=String::format
  501. (
  502. L"%1,%2",
  503. newRootsNotInOld.begin()->first.c_str(),
  504. newRootsNotInOld.begin()->second.c_str()
  505. );
  506. String outStr=String::format
  507. (
  508. L"\nAssuming change from:\"%1\" to \"%2\" for "
  509. L"locale %3!lx!, object %4 and property %5.\n",
  510. arg1.c_str(),
  511. arg2.c_str(),
  512. locale,
  513. object.c_str(),
  514. property.c_str()
  515. );
  516. // We are ignoring the result returned here.
  517. printStringAsAnsi(outStr);
  518. hr=writeChange
  519. (
  520. fileOut,
  521. locale,
  522. object,
  523. property,
  524. arg1,
  525. arg2,
  526. L"REPLACE_W2K_MULTIPLE_VALUE",
  527. guidNumber
  528. );
  529. BREAK_ON_FAILED_HRESULT(hr);
  530. }
  531. else // ...otherwise we flag it as an error.
  532. {
  533. error= String::format
  534. (
  535. L"Error in locale %1!x!, object %2,"
  536. L"property %3. There are %4 old values with the pre comma "
  537. L"string not present in the new values and %5 new values "
  538. L"with the pre comma string not present in the old values."
  539. L"Without a common root it is not possible to know what "
  540. L"replacement to make.",
  541. object.c_str(),
  542. property.c_str(),
  543. newRootsNotInOld.size(),
  544. oldRootsNotInNew.size()
  545. );
  546. hr=E_FAIL;
  547. break;
  548. }
  549. }
  550. //Now we detect changes for common root values
  551. csrRoot=newRoots.begin(),endRoot=newRoots.end();
  552. for(;csrRoot!=endRoot;csrRoot++)
  553. {
  554. const String& newRoot=csrRoot->first;
  555. const String& newRest=csrRoot->second;
  556. // if the new root is in old and the value changed
  557. if(
  558. oldRoots.find(newRoot)!=oldRoots.end() &&
  559. newRest!=oldRoots[newRoot]
  560. )
  561. {
  562. hr=writeChange
  563. (
  564. fileOut,
  565. locale,
  566. object,
  567. property,
  568. String::format(L"%1,%2",newRoot.c_str(),
  569. oldRoots[newRoot].c_str()).c_str(),
  570. String::format(L"%1,%2",newRoot.c_str(),
  571. newRest.c_str()).c_str(),
  572. L"REPLACE_W2K_MULTIPLE_VALUE",
  573. guidNumber
  574. );
  575. BREAK_ON_FAILED_HRESULT(hr);
  576. }
  577. }
  578. BREAK_ON_FAILED_HRESULT(hr);
  579. } while (0);
  580. return hr;
  581. }
  582. // if any value in valuesOld or valuesNew does not ressemble a GUID, fails
  583. // since, in order to call this function, we've already checked that at least
  584. // one in valuesOld or valuesNew ressembles a GUID.
  585. // if x,{xxx} is y,{xxx} fails
  586. // if x,{xxx} is x,{yyy} in the new csv REPLACE_GUID
  587. // all {guids} in old not in new(not replaced) REMOVE_GUID
  588. // all {guids} in new not in old(not replaced) ADD_GUID
  589. typedef map<
  590. GUID,
  591. long,
  592. GUIDLess<GUID>,
  593. Burnslib::Heap::Allocator<long>
  594. > guidToOrd;
  595. typedef map<
  596. long,
  597. GUID,
  598. less<long>,
  599. Burnslib::Heap::Allocator<GUID>
  600. > ordToGuid;
  601. HRESULT dealWithGuids
  602. (
  603. HANDLE fileOut,
  604. long locale,
  605. const String &object,
  606. const String &property,
  607. const StringList &valuesOld,
  608. const StringList &valuesNew,
  609. int guidNumber
  610. )
  611. {
  612. HRESULT hr=S_OK;
  613. do
  614. {
  615. guidToOrd guidToOrdNew;
  616. guidToOrd guidToOrdOld;
  617. ordToGuid ordToGuidOld;
  618. guidToOrd replacements;
  619. GUID oldGuid;long oldOrd;
  620. GUID guid;long ordinal;
  621. // First lets add the guids and ordinals to auxilliary maps
  622. // starting with the old values...
  623. StringList::const_iterator cur,end;
  624. cur=valuesOld.begin();end=valuesOld.end();
  625. for(;cur!=end;cur++)
  626. {
  627. const String &guidValue=*cur;
  628. hr=parseGUID(guidValue,&ordinal,&guid);
  629. if(FAILED(hr))
  630. {
  631. error= String::format
  632. (
  633. L"Error in locale %1!x!, object %2,"
  634. L"property %3. Failed to parse old guid: %4",
  635. locale,
  636. object.c_str(),
  637. property.c_str(),
  638. guidValue.c_str()
  639. );
  640. break;
  641. }
  642. guidToOrdOld[guid]=ordinal;
  643. ordToGuidOld[ordinal]=guid;
  644. }
  645. BREAK_ON_FAILED_HRESULT(hr);
  646. // ...and then the new values.
  647. cur=valuesNew.begin();end=valuesNew.end();
  648. for(;cur!=end;cur++)
  649. {
  650. const String &guidValue=*cur;
  651. hr=parseGUID(guidValue,&ordinal,&guid);
  652. if(FAILED(hr))
  653. {
  654. error= String::format
  655. (
  656. L"Error in locale %1!x!, object %2,"
  657. L"property %3. Failed to parse new guid: %4",
  658. locale,
  659. object.c_str(),
  660. property.c_str(),
  661. guidValue.c_str()
  662. );
  663. break;
  664. }
  665. guidToOrdNew[guid]=ordinal;
  666. }
  667. BREAK_ON_FAILED_HRESULT(hr);
  668. // Lets treat replacements and additions first
  669. guidToOrd::iterator csr,endCsr;
  670. csr=guidToOrdNew.begin();
  671. endCsr=guidToOrdNew.end();
  672. for(;csr!=endCsr;csr++)
  673. {
  674. GUID newGuid=csr->first;
  675. long newOrd=csr->second;
  676. // this flag is used not to add a replacement
  677. bool newGuidWasReplaced=false;
  678. //... if ordinal is in old...
  679. if( ordToGuidOld.find(newOrd)!=ordToGuidOld.end() )
  680. {
  681. GUID oldGuid=ordToGuidOld[newOrd];
  682. // ...with a different GUID, this means a replacement.
  683. if(oldGuid!=newGuid)
  684. {
  685. hr=writeChange
  686. (
  687. fileOut,
  688. locale,
  689. object,
  690. property,
  691. makeGuidString(newOrd,oldGuid),
  692. makeGuidString(newOrd,newGuid),
  693. L"REPLACE_GUID",
  694. guidNumber
  695. );
  696. BREAK_ON_FAILED_HRESULT(hr);
  697. replacements[oldGuid]=newOrd;
  698. newGuidWasReplaced=true;
  699. }
  700. // we have no else because if both the ordinal and guid
  701. // are the same there is nothing to do.
  702. }
  703. // if new guid is also in old...
  704. if( guidToOrdOld.find(newGuid)!=guidToOrdOld.end() )
  705. {
  706. long oldOrd=guidToOrdOld[newGuid];
  707. //...with a different ordinal we have a situation we are not
  708. // prepared to deal with for now
  709. if(oldOrd!=newOrd)
  710. {
  711. error= String::format
  712. (
  713. L"Error in locale %1!x!, object %2,"
  714. L"property %3. Guid:%4 has different ordinals in "
  715. L"new and old (ordinal=%5!d!) csv files.",
  716. locale,
  717. object.c_str(),
  718. property.c_str(),
  719. makeGuidString(newOrd,newGuid).c_str(),
  720. oldOrd
  721. );
  722. break;
  723. }
  724. // we have no else because if both the ordinal and guid
  725. // are the same there is nothing to do.
  726. }
  727. else
  728. {
  729. if(!newGuidWasReplaced)
  730. {
  731. hr=writeChange
  732. (
  733. fileOut,
  734. locale,
  735. object,
  736. property,
  737. makeGuidString(newOrd,newGuid),
  738. "",
  739. L"ADD_GUID",
  740. guidNumber
  741. );
  742. BREAK_ON_FAILED_HRESULT(hr);
  743. }
  744. }
  745. }
  746. BREAK_ON_FAILED_HRESULT(hr);
  747. // Now let's check for guids only in the old
  748. csr=guidToOrdOld.begin(),endCsr=guidToOrdOld.end();
  749. for(;csr!=endCsr;csr++)
  750. {
  751. oldGuid=csr->first;
  752. oldOrd=csr->second;
  753. // if oldGuid is not in new and has not already been replaced
  754. if(
  755. guidToOrdNew.find(oldGuid)==guidToOrdNew.end() &&
  756. replacements.find(oldGuid)==replacements.end()
  757. )
  758. {
  759. hr=writeChange
  760. (
  761. fileOut,
  762. locale,
  763. object,
  764. property,
  765. makeGuidString(oldOrd,oldGuid).c_str(),
  766. L"",
  767. L"REMOVE_GUID",
  768. guidNumber
  769. );
  770. BREAK_ON_FAILED_HRESULT(hr);
  771. }
  772. }
  773. BREAK_ON_FAILED_HRESULT(hr);
  774. } while(0);
  775. return hr;
  776. }
  777. BOOL
  778. MyIsNLSDefinedString
  779. (
  780. const String& str,
  781. wchar_t *badChar
  782. )
  783. {
  784. BOOL ret=IsNLSDefinedString
  785. (
  786. COMPARE_STRING,
  787. 0,
  788. NULL,
  789. str.c_str(),
  790. str.length()
  791. );
  792. if(ret==FALSE)
  793. {
  794. wchar_t s[2]={0};
  795. for(long t=0;t<str.length();t++)
  796. {
  797. s[0]=str[t];
  798. ret=IsNLSDefinedString(COMPARE_STRING,0,NULL,s,1);
  799. if(ret==FALSE)
  800. {
  801. *badChar=str[t];
  802. return FALSE;
  803. }
  804. }
  805. // Some character in the for must return before this point
  806. ASSERT(ret!=FALSE);
  807. }
  808. return TRUE;
  809. }
  810. HRESULT
  811. checkValues
  812. (
  813. long locale,
  814. const String &object,
  815. const mapOfProperties &values
  816. )
  817. {
  818. HRESULT hr=S_OK;
  819. do
  820. {
  821. mapOfProperties::const_iterator csr,end;
  822. for(csr=values.begin(),end=values.end();csr!=end;csr++)
  823. {
  824. StringList::const_iterator csrVal=csr->second.begin();
  825. StringList::const_iterator endVal=csr->second.end();
  826. for(;csrVal!=endVal;csrVal++)
  827. {
  828. wchar_t badChar;
  829. if( MyIsNLSDefinedString(*csrVal,&badChar) == FALSE )
  830. {
  831. String outStr=String::format
  832. (
  833. L"\nNon unicode char %1!x! in string:\"%2\" for "
  834. L"locale %3!lx!, object %4 and property %5.\n",
  835. badChar,
  836. csrVal->c_str(),
  837. locale,
  838. object.c_str(),
  839. csr->first.c_str()
  840. );
  841. // We are ignoring the result returned here.
  842. printStringAsAnsi(outStr);
  843. hr=E_FAIL;
  844. break;
  845. }
  846. }
  847. BREAK_ON_FAILED_HRESULT(hr);
  848. }
  849. BREAK_ON_FAILED_HRESULT(hr);
  850. } while(0);
  851. hr=S_OK;
  852. // for now we always return true but we will make this
  853. // a critical error when this checking makes to the AD
  854. return hr;
  855. }
  856. // Reads synchronally csvOld and csvNew adding the necessary changes.
  857. // Objects only in csvOld will cause failure
  858. // For objects only in csvNew call addNewObject to add an ADD_OBJECT entry.
  859. // For each common object betweem csvOld and csvNew:
  860. // For each object property belonging to newProperties and with a non
  861. // empty value add call addAllCsvValues to add an ADD_CSV_VALUES entry.
  862. // for each property in the object belonging to commonProperties
  863. // valuesOld = value of the property in oldCsv
  864. // valuesNew = value of the property in newCsv
  865. // if valuesNew and valuesOld are empty skip this value
  866. // if either first value of valuesNew or valuesOld ressembles a GUID
  867. // call dealWithGuid to add ADD_GUID/REPLACE_GUID/DELETE_GUID as necessary and
  868. // and skip to next.
  869. // if both valuesNew.size and valuesOld.size <= 1 call dealWithSingleValue
  870. // to add REPLACE_SINGLE_VALUE as necessary and skip to next
  871. // dealWithMultipleValue to add REPLACE_MULTIPLE_VALUE as necessary and
  872. // skip to next.
  873. HRESULT addChanges
  874. (
  875. HANDLE fileOut,
  876. const CSVDSReader &csvOld,
  877. const CSVDSReader &csvNew,
  878. const mapOfPositions &commonProperties,
  879. const mapOfPositions &newProperties,
  880. int guidNumber,
  881. const wchar_t *csvName
  882. )
  883. {
  884. HRESULT hr=S_OK;
  885. do
  886. {
  887. // Here we start readding both csv files
  888. hr=csvOld.initializeGetNext();
  889. BREAK_ON_FAILED_HRESULT(hr);
  890. hr=csvNew.initializeGetNext();
  891. BREAK_ON_FAILED_HRESULT(hr);
  892. // The loop bellow will sequentially read objects
  893. // in both csv's making sure the same objects are read.
  894. bool flagEOF=false;
  895. do
  896. {
  897. mapOfProperties oldValues,newValues;
  898. long locOld=0,locNew=0;
  899. String objOld,objNew;
  900. hr=csvOld.getNextObject(locOld,objOld,oldValues);
  901. BREAK_ON_FAILED_HRESULT(hr);
  902. if(hr==S_FALSE) {flagEOF=true;hr=S_OK;}
  903. hr=checkValues(locOld,objOld,oldValues);
  904. BREAK_ON_FAILED_HRESULT(hr);
  905. hr=csvNew.getNextObject(locNew,objNew,newValues);
  906. BREAK_ON_FAILED_HRESULT(hr);
  907. // While we don't find the object from the old csv
  908. // in the new csv we add entries for the new objects found
  909. while(hr!=S_FALSE && (locNew!=locOld || objNew!=objOld) )
  910. {
  911. hr= writeChange
  912. (
  913. fileOut,
  914. locNew,
  915. objNew,
  916. L"",
  917. L"",
  918. L"",
  919. L"ADD_OBJECT",
  920. guidNumber
  921. );
  922. BREAK_ON_FAILED_HRESULT(hr);
  923. hr=checkValues(locNew,objNew,newValues);
  924. BREAK_ON_FAILED_HRESULT(hr);
  925. hr=csvNew.getNextObject(locNew,objNew,newValues);
  926. BREAK_ON_FAILED_HRESULT(hr);
  927. }
  928. BREAK_ON_FAILED_HRESULT(hr);
  929. if(hr==S_FALSE) {flagEOF=true;hr=S_OK;}
  930. hr=checkValues(locNew,objNew,newValues);
  931. BREAK_ON_FAILED_HRESULT(hr);
  932. // This means that we searched the whole new csv file and didn't
  933. // find the object we've read from the old csv file.
  934. if(locNew!=locOld || objNew!=objOld)
  935. {
  936. error=String::format
  937. (
  938. L"Error:%1!d!,%2 was only in the old %3 csv file.",
  939. locOld,objOld.c_str(),
  940. csvName
  941. );
  942. hr=E_FAIL;
  943. break;
  944. }
  945. // From this point on we know the object is
  946. // the same in old and new csv files
  947. // This happens if we have a blank line at the end of the files
  948. if(locNew==0) break;
  949. // now let's check the differences in the common properties
  950. mapOfPositions::const_iterator cur=newProperties.begin();
  951. mapOfPositions::const_iterator end=newProperties.end();
  952. for(;cur!=end;cur++)
  953. {
  954. const String& property=cur->first;
  955. const StringList &valuesNew=newValues[property];
  956. if(!valuesNew.empty())
  957. {
  958. // We only want to use ADD_ALL_CSV_VALUES if it
  959. // is not a guid. It will probably be the same as
  960. // ADD_ALL_CSV_VALUES for most cases but it is
  961. // better policy to keep all guid additions
  962. // with an ADD_GUID change.
  963. if( isGuid(*valuesNew.begin()) )
  964. {
  965. // We know we don't have old values because this is a
  966. // new property
  967. StringList emptyValues;
  968. hr= dealWithGuids
  969. (
  970. fileOut,
  971. locNew,
  972. objNew,
  973. property,
  974. emptyValues,
  975. valuesNew,
  976. guidNumber
  977. );
  978. BREAK_ON_FAILED_HRESULT(hr);
  979. }
  980. else
  981. {
  982. hr= writeChange
  983. (
  984. fileOut,
  985. locNew,
  986. objNew,
  987. property,
  988. L"",
  989. L"",
  990. L"ADD_ALL_CSV_VALUES",
  991. guidNumber
  992. );
  993. BREAK_ON_FAILED_HRESULT(hr);
  994. }
  995. }
  996. }
  997. BREAK_ON_FAILED_HRESULT(hr);
  998. // now let's check the differences in the common properties
  999. cur=commonProperties.begin();
  1000. end=commonProperties.end();
  1001. for(;cur!=end;cur++)
  1002. {
  1003. const String& property=cur->first;
  1004. const StringList &valuesOld=oldValues[property];
  1005. const StringList &valuesNew=newValues[property];
  1006. if (valuesOld.empty() && valuesNew.empty()) continue;
  1007. // The or bellows means either value being guid we want
  1008. // to deal with them in dealWithGuids. Inside it, all non
  1009. // guids would trigger an error.
  1010. if (
  1011. ( !valuesOld.empty() && isGuid(*valuesOld.begin()) ) ||
  1012. ( !valuesNew.empty() && isGuid(*valuesNew.begin()) )
  1013. )
  1014. {
  1015. hr= dealWithGuids
  1016. (
  1017. fileOut,
  1018. locNew,
  1019. objNew,
  1020. property,
  1021. valuesOld,
  1022. valuesNew,
  1023. guidNumber
  1024. );
  1025. BREAK_ON_FAILED_HRESULT(hr);
  1026. continue;
  1027. }
  1028. // Now we know that we don't have a guid change
  1029. if(valuesNew.size()<=1 && valuesOld.size()<=1)
  1030. {
  1031. hr= dealWithSingleValue
  1032. (
  1033. fileOut,
  1034. locNew,
  1035. objNew,
  1036. property,
  1037. valuesOld,
  1038. valuesNew,
  1039. guidNumber
  1040. );
  1041. BREAK_ON_FAILED_HRESULT(hr);
  1042. continue;
  1043. }
  1044. // Now we know that we don't have GUIDS or single values
  1045. hr= dealWithMultipleValue
  1046. (
  1047. fileOut,
  1048. locNew,
  1049. objNew,
  1050. property,
  1051. valuesOld,
  1052. valuesNew,
  1053. guidNumber
  1054. );
  1055. BREAK_ON_FAILED_HRESULT(hr);
  1056. }
  1057. BREAK_ON_FAILED_HRESULT(hr);
  1058. } while (flagEOF==false);
  1059. BREAK_ON_FAILED_HRESULT(hr);
  1060. } while(0);
  1061. return hr;
  1062. }
  1063. // Writes the whole SetChanges function with the locales
  1064. // from dcpromo and 409.
  1065. // Calls writeChangesHeader and then addChanges twice, one
  1066. // for each csv pair. Finally, calls FS::Write(fileOut,L"\n}");.
  1067. HRESULT addAllChanges
  1068. (
  1069. HANDLE fileOut,
  1070. const CSVDSReader &oldDcpromo,
  1071. const CSVDSReader &newDcpromo,
  1072. const CSVDSReader &old409,
  1073. const CSVDSReader &new409,
  1074. const mapOfPositions &commonProperties,
  1075. const mapOfPositions &newProperties,
  1076. int guidNumber
  1077. )
  1078. {
  1079. HRESULT hr=S_OK;
  1080. do
  1081. {
  1082. hr=writeChangesHeader(fileOut,guidNumber);
  1083. BREAK_ON_FAILED_HRESULT(hr);
  1084. hr=addChanges
  1085. (
  1086. fileOut,
  1087. old409,
  1088. new409,
  1089. commonProperties,
  1090. newProperties,
  1091. guidNumber,
  1092. L"409"
  1093. );
  1094. BREAK_ON_FAILED_HRESULT(hr);
  1095. hr=addChanges
  1096. (
  1097. fileOut,
  1098. oldDcpromo,
  1099. newDcpromo,
  1100. commonProperties,
  1101. newProperties,
  1102. guidNumber,
  1103. L"dcpromo"
  1104. );
  1105. BREAK_ON_FAILED_HRESULT(hr);
  1106. hr = writeStringAsAnsi(fileOut,L"\r\n}");
  1107. BREAK_ON_FAILED_HRESULT(hr);
  1108. } while(0);
  1109. return hr;
  1110. }
  1111. // writes setChangesNNN.cpp. Sets up by caling getAllPropertyChanges, calls
  1112. // writeHeader and then addAllChanges
  1113. // Creates the CSVReader objects corresponding to the 4 first parameters
  1114. // to pass to writeGlobalChanges and writeGlobalChanges.
  1115. // guidNumber is repassed to addAllChanges
  1116. HRESULT writeChanges
  1117. (
  1118. const String &oldDcpromoName,
  1119. const String &newDcpromoName,
  1120. const String &old409Name,
  1121. const String &new409Name,
  1122. const String &changesCpp,
  1123. int guidNumber
  1124. )
  1125. {
  1126. HRESULT hr=S_OK;
  1127. HANDLE fChanges = INVALID_HANDLE_VALUE;
  1128. hr=FS::CreateFile
  1129. (
  1130. changesCpp.c_str(),
  1131. fChanges,
  1132. GENERIC_WRITE,
  1133. FILE_SHARE_READ,
  1134. CREATE_ALWAYS
  1135. );
  1136. do
  1137. {
  1138. if (FAILED(hr))
  1139. {
  1140. wprintf(L"Could not create changes file: %s.",changesCpp.c_str());
  1141. break;
  1142. }
  1143. do
  1144. {
  1145. CSVDSReader oldDcpromo;
  1146. hr=oldDcpromo.read(oldDcpromoName.c_str(),LOCALEIDS);
  1147. BREAK_ON_FAILED_HRESULT(hr);
  1148. CSVDSReader newDcpromo;
  1149. hr=newDcpromo.read(newDcpromoName.c_str(),LOCALEIDS);
  1150. BREAK_ON_FAILED_HRESULT(hr);
  1151. CSVDSReader old409;
  1152. hr=old409.read(old409Name.c_str(),LOCALE409);
  1153. BREAK_ON_FAILED_HRESULT(hr);
  1154. CSVDSReader new409;
  1155. hr=new409.read(new409Name.c_str(),LOCALE409);
  1156. BREAK_ON_FAILED_HRESULT(hr);
  1157. mapOfPositions commonProperties,newProperties;
  1158. hr=getAllPropertyChanges
  1159. (
  1160. oldDcpromo,
  1161. newDcpromo,
  1162. old409,
  1163. new409,
  1164. commonProperties,
  1165. newProperties
  1166. );
  1167. BREAK_ON_FAILED_HRESULT(hr);
  1168. hr=writeHeader(fChanges);
  1169. BREAK_ON_FAILED_HRESULT(hr);
  1170. hr=addAllChanges
  1171. (
  1172. fChanges,
  1173. oldDcpromo,
  1174. newDcpromo,
  1175. old409,
  1176. new409,
  1177. commonProperties,
  1178. newProperties,
  1179. guidNumber
  1180. );
  1181. BREAK_ON_FAILED_HRESULT(hr);
  1182. } while(0);
  1183. CloseHandle(fChanges);
  1184. } while(0);
  1185. return hr;
  1186. }
  1187. HRESULT writeGuid(HANDLE fOut,const GUID &guid)
  1188. {
  1189. return
  1190. (
  1191. writeStringAsAnsi
  1192. (
  1193. fOut,
  1194. String::format
  1195. (
  1196. " {0x%1!x!,0x%2!x!,0x%3!x!,{0x%4!x!,0x%5!x!,0x%6!x!,"
  1197. "0x%7!x!,0x%8!x!,0x%9!x!,0x%10!x!,0x%11!x!}},\r\n",
  1198. guid.Data1,guid.Data2,guid.Data3,
  1199. guid.Data4[0],guid.Data4[1],guid.Data4[2],guid.Data4[3],
  1200. guid.Data4[4],guid.Data4[5],guid.Data4[6],guid.Data4[7]
  1201. ).c_str()
  1202. )
  1203. );
  1204. }
  1205. HRESULT writeGuids(const String& guidsInc,const GUID &newGuid)
  1206. {
  1207. HRESULT hr=S_OK;
  1208. HANDLE fOut= INVALID_HANDLE_VALUE;
  1209. hr=FS::CreateFile
  1210. (
  1211. guidsInc.c_str(),
  1212. fOut,
  1213. GENERIC_WRITE,
  1214. FILE_SHARE_READ,
  1215. CREATE_ALWAYS
  1216. );
  1217. do
  1218. {
  1219. if (FAILED(hr))
  1220. {
  1221. wprintf(L"Could not create changes file: %s.",guidsInc.c_str());
  1222. break;
  1223. }
  1224. do
  1225. {
  1226. int sizeGuids=sizeof(guids)/sizeof(*guids);
  1227. hr=FS::Write
  1228. (
  1229. fOut,
  1230. AnsiString
  1231. (
  1232. "// This file is generated by preBuild.exe\r\n"
  1233. "// Copyright (c) 2001 Microsoft Corporation\r\n"
  1234. "// Nov 2001 lucios\r\n\r\n\r\n"
  1235. "GUID guids[]=\r\n"
  1236. "{\r\n"
  1237. )
  1238. );
  1239. BREAK_ON_FAILED_HRESULT(hr);
  1240. for(int ix=0;ix<sizeGuids;ix++)
  1241. {
  1242. hr=writeGuid(fOut,guids[ix]);
  1243. BREAK_ON_FAILED_HRESULT(hr);
  1244. }
  1245. BREAK_ON_FAILED_HRESULT(hr);
  1246. hr=writeGuid(fOut,newGuid);
  1247. BREAK_ON_FAILED_HRESULT(hr);
  1248. hr=FS::Write(fOut,AnsiString("};\r\n"));
  1249. BREAK_ON_FAILED_HRESULT(hr);
  1250. } while(0);
  1251. CloseHandle(fOut);
  1252. BREAK_ON_FAILED_HRESULT(hr);
  1253. } while(0);
  1254. return hr;
  1255. }
  1256. HRESULT writeSetChanges(const String& setChanges)
  1257. {
  1258. HRESULT hr=S_OK;
  1259. HANDLE fOut= INVALID_HANDLE_VALUE;
  1260. hr=FS::CreateFile
  1261. (
  1262. setChanges.c_str(),
  1263. fOut,
  1264. GENERIC_WRITE,
  1265. FILE_SHARE_READ,
  1266. CREATE_ALWAYS
  1267. );
  1268. do
  1269. {
  1270. if (FAILED(hr))
  1271. {
  1272. wprintf(L"Could not create setChanges file: %s.",setChanges.c_str());
  1273. break;
  1274. }
  1275. do
  1276. {
  1277. int sizeGuids=sizeof(guids)/sizeof(*guids);
  1278. hr=FS::Write
  1279. (
  1280. fOut,
  1281. AnsiString
  1282. (
  1283. "// This file is generated by preBuild.exe\r\n"
  1284. "// Copyright (c) 2001 Microsoft Corporation\r\n"
  1285. "// Nov 2001 lucios\r\n\r\n\n"
  1286. "#include \"headers.hxx\"\r\n\r\n"
  1287. )
  1288. );
  1289. BREAK_ON_FAILED_HRESULT(hr);
  1290. for(int ix=0;ix<sizeGuids+1;ix++)
  1291. {
  1292. hr=writeStringAsAnsi
  1293. (
  1294. fOut,
  1295. String::format("void setChanges%1!d!();\r\n",ix)
  1296. );
  1297. BREAK_ON_FAILED_HRESULT(hr);
  1298. }
  1299. BREAK_ON_FAILED_HRESULT(hr);
  1300. hr=FS::Write(fOut,AnsiString("\nvoid setChanges()\r\n{\r\n"));
  1301. BREAK_ON_FAILED_HRESULT(hr);
  1302. for(int ix=0;ix<sizeGuids+1;ix++)
  1303. {
  1304. hr=writeStringAsAnsi
  1305. (
  1306. fOut,
  1307. String::format(" setChanges%1!d!();\r\n",ix)
  1308. );
  1309. }
  1310. BREAK_ON_FAILED_HRESULT(hr);
  1311. hr=FS::Write(fOut,AnsiString("}\r\n"));
  1312. BREAK_ON_FAILED_HRESULT(hr);
  1313. } while(0);
  1314. CloseHandle(fOut);
  1315. BREAK_ON_FAILED_HRESULT(hr);
  1316. } while(0);
  1317. return hr;
  1318. }
  1319. HRESULT writeSources(const String& sources,const String& changesCpp)
  1320. {
  1321. HRESULT hr=S_OK;
  1322. AnsiString ansiStr;
  1323. String::ConvertResult res=changesCpp.convert(ansiStr);
  1324. if(res!=String::CONVERT_SUCCESSFUL)
  1325. {
  1326. ASSERT(res==String::CONVERT_SUCCESSFUL);
  1327. error=L"Ansi conversion failed";
  1328. return E_FAIL;
  1329. }
  1330. FILE *fOut=_wfopen(sources.c_str(),L"a+");
  1331. do
  1332. {
  1333. if (fOut==NULL)
  1334. {
  1335. wprintf(L"Could not create sources file: %s.",sources.c_str());
  1336. break;
  1337. }
  1338. do
  1339. {
  1340. fprintf(fOut," %s \\\r\n" ,ansiStr.c_str());
  1341. BREAK_ON_FAILED_HRESULT(hr);
  1342. } while(0);
  1343. fclose(fOut);
  1344. BREAK_ON_FAILED_HRESULT(hr);
  1345. } while(0);
  1346. return hr;
  1347. }
  1348. ///////////////////////////////////////////////////
  1349. // entry point
  1350. void __cdecl wmain(int argc,wchar_t *argv[])
  1351. {
  1352. HRESULT hr=S_OK;
  1353. do
  1354. {
  1355. if(argc!=7)
  1356. {
  1357. error=L"\nThis program generates a new set of changes to be "
  1358. L"used in dcpromo.lib by comparing the new and previous"
  1359. L" csv files. Usage:\n\n\"preBuild.exe GUID oldDcpromo "
  1360. L"newDcpromo old409 new409 targetFolder\"\n\n"
  1361. L"GUID is the identifier for this set of changes, for example:\n"
  1362. L"8B53221B-EA3C-4638-8D00-7C1BE42B2873\n\n"
  1363. L"oldDcpromo is the previous dcpromo.csv\n"
  1364. L"newDcpromo is the new dcpromo.csv\n"
  1365. L"old409 is the previous 409.csv\n"
  1366. L"new409 is the new 409.csv\n\n"
  1367. L"targetFolder is the sources file for dcpromo.lib,"
  1368. L" where guids.inc,setChanges.cpp, and "
  1369. L"changes.NNN.cpp will be generated and where the sources "
  1370. L"file for the display specifier upgrade library is. "
  1371. L"An entry like: \"changes.NNN.cpp \\\" will be added "
  1372. L"at the end of targetFolder\\sources.\n\n";
  1373. hr=E_FAIL;
  1374. break;
  1375. }
  1376. String guidStr=argv[1],oldDcpromo=argv[2],newDcpromo=argv[3],old409=argv[4];
  1377. String new409=argv[5],targetFolder=argv[6];
  1378. String sources=targetFolder + L"\\sources";
  1379. String guidsInc=targetFolder + L"\\guids.inc";
  1380. String setChanges=targetFolder + L"\\setChanges.cpp";
  1381. GUID guid={0};
  1382. if(UuidFromString((wchar_t*)guidStr.c_str(),&guid)!=RPC_S_OK)
  1383. {
  1384. error=String::format(L"\n Invalid GUID:%s.\n",guidStr.c_str());
  1385. break;
  1386. }
  1387. BREAK_IF_MISSING(hr,oldDcpromo);
  1388. BREAK_IF_MISSING(hr,newDcpromo);
  1389. BREAK_IF_MISSING(hr,old409);
  1390. BREAK_IF_MISSING(hr,new409);
  1391. BREAK_IF_MISSING_OR_READONLY(hr,guidsInc);
  1392. BREAK_IF_MISSING_OR_READONLY(hr,sources);
  1393. BREAK_IF_MISSING_OR_READONLY(hr,setChanges);
  1394. int sizeGuids=sizeof(guids)/sizeof(*guids);
  1395. for(int t=0;t<sizeGuids;t++)
  1396. {
  1397. if (guids[t]==guid)
  1398. {
  1399. hr=E_FAIL;
  1400. error=String::format("The guid you entered (%s) is already present\n");
  1401. break;
  1402. }
  1403. String shouldExist = targetFolder +
  1404. String::format(L"\\changes%1!03d!.cpp",t);
  1405. BREAK_IF_MISSING(hr,shouldExist);
  1406. }
  1407. BREAK_ON_FAILED_HRESULT(hr);
  1408. String changesCppOnly = String::format(L"changes%1!03d!.cpp",t);
  1409. String changesCpp = targetFolder + L"\\" + changesCppOnly;
  1410. if( fileExists(changesCpp.c_str()) )
  1411. {
  1412. hr=E_FAIL;
  1413. error=String::format(L"Change file already exists: %1.",changesCpp.c_str());
  1414. break;
  1415. }
  1416. hr=writeChanges
  1417. (
  1418. oldDcpromo,
  1419. newDcpromo,
  1420. old409,
  1421. new409,
  1422. changesCpp,
  1423. sizeGuids
  1424. );
  1425. hr=writeGuids(guidsInc,guid);
  1426. BREAK_ON_FAILED_HRESULT(hr);
  1427. hr=writeSetChanges(setChanges);
  1428. BREAK_ON_FAILED_HRESULT(hr);
  1429. hr=writeSources(sources,changesCppOnly);
  1430. BREAK_ON_FAILED_HRESULT(hr);
  1431. } while(0);
  1432. if(FAILED(hr)) wprintf(L"\nFailure code: %lx\n",hr);
  1433. else wprintf(L"\nSuccess. Don't forget to bcz this project and targetFolder.\n");
  1434. if(!error.empty()) wprintf(String::format("\n%1\n",error.c_str()).c_str());
  1435. }
  1436. ///////////////////////////////////////////////////////////////////
  1437. // Function: cchLoadHrMsg
  1438. //
  1439. // Given an HRESULT error,
  1440. // it loads the string for the error. It returns the # of characters returned
  1441. int cchLoadHrMsg( HRESULT hr, String &message )
  1442. {
  1443. if(hr == S_OK) return 0;
  1444. wchar_t *msgPtr = NULL;
  1445. // Try from the system table
  1446. int cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  1447. NULL,
  1448. hr,
  1449. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  1450. (LPWSTR)&msgPtr,
  1451. 0,
  1452. NULL);
  1453. if (!cch)
  1454. {
  1455. //try ads errors
  1456. static HMODULE g_adsMod = 0;
  1457. if (0 == g_adsMod)
  1458. {
  1459. g_adsMod = GetModuleHandle (L"activeds.dll");
  1460. }
  1461. cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
  1462. g_adsMod,
  1463. hr,
  1464. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  1465. (LPWSTR)&msgPtr,
  1466. 0,
  1467. NULL);
  1468. }
  1469. if (!cch)
  1470. {
  1471. // Try NTSTATUS error codes
  1472. hr = HRESULT_FROM_WIN32(RtlNtStatusToDosError(hr));
  1473. cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  1474. NULL,
  1475. hr,
  1476. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  1477. (LPWSTR)&msgPtr,
  1478. 0,
  1479. NULL);
  1480. }
  1481. message.erase();
  1482. if(cch!=0)
  1483. {
  1484. if(msgPtr==NULL)
  1485. {
  1486. cch=0;
  1487. }
  1488. else
  1489. {
  1490. message=msgPtr;
  1491. ::LocalFree(msgPtr);
  1492. }
  1493. }
  1494. return cch;
  1495. }