private void newAddressToolStripMenuItem_Click(object sender, EventArgs e) { KeyPair kp = KeyPair.Create(ExtraEntropy.GetEntropy()); KeyCollectionItem item = new KeyCollectionItem(kp); KeyCollection.AddItem(item); }
/// <summary> /// Code which is actually run on the generation thread. /// </summary> private void GenerationThreadProcess() { Bip38Intermediate intermediate = null; if (GenChoice == GenChoices.Encrypted) { intermediate = new Bip38Intermediate(UserText, Bip38Intermediate.Interpretation.Passphrase); } int detcount = 1; while (RemainingToGenerate > 0 && StopRequested == false) { KeyCollectionItem newitem = null; switch (GenChoice) { case GenChoices.Minikey: MiniKeyPair mkp = MiniKeyPair.CreateRandom(ExtraEntropy.GetEntropy()); string s = mkp.AddressBase58; // read the property to entice it to compute everything newitem = new KeyCollectionItem(mkp); break; case GenChoices.WIF: KeyPair kp = KeyPair.Create(ExtraEntropy.GetEntropy()); s = kp.AddressBase58; newitem = new KeyCollectionItem(kp); break; case GenChoices.Deterministic: kp = KeyPair.CreateFromString(UserText + detcount); detcount++; s = kp.AddressBase58; newitem = new KeyCollectionItem(kp); break; case GenChoices.Encrypted: Bip38KeyPair ekp = new Bip38KeyPair(intermediate); newitem = new KeyCollectionItem(ekp); break; case GenChoices.TwoFactor: ekp = new Bip38KeyPair(intermediatesForGeneration[intermediateIdx++]); if (intermediateIdx >= intermediatesForGeneration.Length) { intermediateIdx = 0; } newitem = new KeyCollectionItem(ekp); break; } lock (GeneratedItems) { GeneratedItems.Add(newitem); RemainingToGenerate--; } } GeneratingEnded = true; }
void KeyCollection_ItemAdded(KeyCollectionItem item) { ListViewItem lvi = new ListViewItem(new string[] { item.ToString(), item.PrivateKeyKind, "0.00" }); lvi.Tag = item; lvi.Checked = true; listView1.Items.Add(lvi); UpdateStatusLabel(); }
private List <KeyCollectionItem> getEncryptedItemsToPrint() { List <KeyCollectionItem> itemsToPrint = new List <KeyCollectionItem>(); int Unprintables = 0; //foreach (KeyCollectionItem i in KeyCollection.Items) { foreach (ListViewItem lvi in listView1.Items) { if (lvi.Checked) { KeyCollectionItem i = lvi.Tag as KeyCollectionItem; if (i.EncryptedKeyPair != null || (i.Address != null && i.Address is KeyPair)) { itemsToPrint.Add(i); } else { Unprintables++; } } } if (itemsToPrint.Count == 0) { MessageBox.Show("No items with printable private keys are selected.", "Can't print encrypted keys", MessageBoxButtons.OK, MessageBoxIcon.Warning); return(null); } if (Unprintables != 0) { MessageBox.Show(Unprintables.ToString() + " of the selected items cannot be " + "printed because the private key is not known. These items will be skipped.", "Can't print some items", MessageBoxButtons.OK, MessageBoxIcon.Warning); } return(itemsToPrint); }
/// <summary> /// Takes a KeyCollectionItem from elsewhere in the program for display. /// This gets called if someone doubleclicks an address in the Key Collection View, or chooses Details. /// Item may represent an AddressBase, PublicKey, KeyPair, MiniKey, or an EncryptedKeyPair /// </summary> public void DisplayKeyCollectionItem(KeyCollectionItem item) { try { ChangeFlag++; if (item.EncryptedKeyPair != null) { SetText(txtPrivWIF, item.EncryptedKeyPair.EncryptedPrivateKey); // blank out any validation info of the minikey UpdateMinikeyDescription(); SetText(txtPassphrase, ""); if (item.EncryptedKeyPair.IsUnencryptedPrivateKeyAvailable()) { SetText(txtPrivHex, item.EncryptedKeyPair.GetUnencryptedPrivateKey().PublicKeyHex); } else { SetText(txtPrivHex, ""); } if (item.EncryptedKeyPair.IsPublicKeyAvailable()) { SetText(txtPubHex, item.EncryptedKeyPair.GetPublicKey().PublicKeyHex); } else { SetText(txtPubHex, ""); } if (item.EncryptedKeyPair.IsAddressAvailable()) { AddressBase addr = item.EncryptedKeyPair.GetAddress(); SetText(txtPubHash, addr.Hash160Hex); SetText(txtBtcAddr, addr.AddressBase58); } else { SetText(txtPubHash, ""); SetText(txtBtcAddr, ""); } return; } // Handle whether the item is/isn't a minikey if (item.Address != null && item.Address is MiniKeyPair) { SetText(txtMinikey, ((MiniKeyPair)item.Address).MiniKey); } else { SetText(txtMinikey, ""); } // update the label to indicate whether this is a valid minikey (or blank it out if n/a) UpdateMinikeyDescription(); if (item.Address != null) { // Handle whether item is/isn't a keypair (known private key) if (item.Address is KeyPair) { KeyPair kp = (KeyPair)item.Address; SetText(txtPrivWIF, kp.PrivateKeyBase58); SetText(txtPrivHex, kp.PrivateKeyHex); } else { SetText(txtPrivWIF, ""); SetText(txtPrivHex, ""); } // Handle whether item has/doesn't have known public key if (item.Address is PublicKey) { PublicKey pub = ((PublicKey)item.Address); SetText(txtPubHex, pub.PublicKeyHex); } else { SetText(txtPubHex, ""); } // Handle address SetText(txtPubHash, item.Address.Hash160Hex); SetText(txtBtcAddr, item.Address.AddressBase58); } } finally { ChangeFlag--; } }
protected override void OnPrintPage(System.Drawing.Printing.PrintPageEventArgs e) { base.OnPrintPage(e); int printHeight; int printWidth; int leftMargin; int rightMargin; //Set print area size and margins { printHeight = base.DefaultPageSettings.PaperSize.Height - base.DefaultPageSettings.Margins.Top - base.DefaultPageSettings.Margins.Bottom; printWidth = base.DefaultPageSettings.PaperSize.Width - base.DefaultPageSettings.Margins.Left - base.DefaultPageSettings.Margins.Right; leftMargin = base.DefaultPageSettings.Margins.Left; //X rightMargin = base.DefaultPageSettings.Margins.Top; //Y } for (int i = 0; i < 8; i++) { int eachheight = 120; if (keys.Count == 0) { break; } KeyCollectionItem kci = keys[0]; string address = kci.GetAddressBase58(); string privkey = kci.PrivateKey; string confcode = ""; if (kci.EncryptedKeyPair != null && kci.EncryptedKeyPair is Bip38KeyPair) { confcode = ((Bip38KeyPair)kci.EncryptedKeyPair).GetConfirmationCode() ?? ""; //if (confcode != "") confcode = "Confirmation code:\r\n" + confcode; } keys.RemoveAt(0); int thiscodeX = 0; // 50; int thiscodeY = 50 + eachheight * i; // ---------------------------------------------------------------- // Coin insert with public and private QR codes. Fits 8 to a page. // ---------------------------------------------------------------- float CircleDiameterInches = (7F / 16F); // 7/16" // draw the private key circle using (Pen blackpen = new Pen(Color.Black)) { blackpen.Width = (1F / 72F); e.Graphics.DrawEllipse(blackpen, thiscodeX + 30F, thiscodeY + 10F, CircleDiameterInches * 100F, CircleDiameterInches * 100F); // Over 30 characters? do a folding insert at 95% diameter away if (privkey.Length > 30) { e.Graphics.DrawEllipse(blackpen, thiscodeX + 30F, thiscodeY + 10F + (CircleDiameterInches * 95F), CircleDiameterInches * 100F, CircleDiameterInches * 100F); e.Graphics.FillEllipse(Brushes.White, thiscodeX + 30F, thiscodeY + 10F + (CircleDiameterInches * 95F), CircleDiameterInches * 100F, CircleDiameterInches * 100F); } e.Graphics.FillEllipse(Brushes.White, thiscodeX + 30F, thiscodeY + 10F, CircleDiameterInches * 100F, CircleDiameterInches * 100F); } int[] charsPerLine = new int[] { 4, 7, 8, 7, 4, 0, 4, 7, 8, 7, 4 }; string privkeyleft = privkey; // if it's going to take two circles, add hyphens if (privkeyleft.Length > 30) { privkeyleft = privkeyleft.Substring(0, 29) + "--" + privkeyleft.Substring(29); } string privkeytoprint = ""; for (int c = 0; c < 11; c++) { if (charsPerLine[c] == 0) { privkeytoprint += "\r\n"; } else { if (privkeyleft.Length > charsPerLine[c]) { privkeytoprint += privkeyleft.Substring(0, charsPerLine[c]) + "\r\n"; privkeyleft = privkeyleft.Substring(charsPerLine[c]); } else { privkeytoprint += privkeyleft + "\r\n"; privkeyleft = ""; } } } using (StringFormat sfcenter = new StringFormat()) { sfcenter.Alignment = StringAlignment.Center; e.Graphics.DrawString(privkeytoprint, fontsmall, Brushes.Black, thiscodeX + 30F + (CircleDiameterInches * 100F / 2F), thiscodeY + 14F, sfcenter); } // draw the address QR code using (Bitmap b2 = QR.EncodeQRCode(address)) { e.Graphics.DrawImage(b2, thiscodeX + 100, thiscodeY, 100, 100); } e.Graphics.DrawString("Bitcoin address:\r\n" + address, font, Brushes.Black, thiscodeX + 210, thiscodeY); StringFormat sf = new StringFormat(); sf.Alignment = StringAlignment.Far; // right justify if (confcode != "") { // Print the confirmation QR code using (Bitmap b = QR.EncodeQRCode(confcode)) { e.Graphics.DrawImage(b, thiscodeX + 600, thiscodeY, 100, 100); string whattoprint = "Confirmation code:\r\n" + confcode.Substring(0, 38) + "\r\n" + confcode.Substring(38); e.Graphics.DrawString(whattoprint, font, Brushes.Black, thiscodeX + 597, thiscodeY + 55, sf); } } } if (keys.Count != 0) { e.HasMorePages = true; } }
protected override void OnPrintPage(System.Drawing.Printing.PrintPageEventArgs e) { base.OnPrintPage(e); int printHeight; int printWidth; int leftMargin; int rightMargin; //Set print area size and margins { printHeight = base.DefaultPageSettings.PaperSize.Height - base.DefaultPageSettings.Margins.Top - base.DefaultPageSettings.Margins.Bottom; printWidth = base.DefaultPageSettings.PaperSize.Width - base.DefaultPageSettings.Margins.Left - base.DefaultPageSettings.Margins.Right; leftMargin = base.DefaultPageSettings.Margins.Left; //X rightMargin = base.DefaultPageSettings.Margins.Top; //Y } for (int i = 0; i < 16; i++) { int eachheight = 120; switch (PrintMode) { case PrintModes.PubPrivQR: if (i >= 8) { i = 999; } eachheight = 120; break; case PrintModes.PsyBanknote: if (i >= 3) { i = 999; } eachheight = 365; break; } if (i == 999) { break; } if (PrintMode == PrintModes.PubPrivQR && i >= 8) { break; } if (PrintMode == PrintModes.PsyBanknote && i >= NotesPerPage) { break; } if (keys.Count == 0) { break; } int thiscodeX = 50; int thiscodeY = 50 + eachheight * i; if (i >= 8) { thiscodeX = 450; thiscodeY = 50 + eachheight * (i - 8); } // T-------------------------------| // | | // | | // | | // | | // | | // |-------------------------------| // // T = thiscodeX,thiscodeY // // Load the Ubuntu font directly from a file so it doesn't need to be installed on the system. if (UbuntuFontLoaded == false) { UbuntuFontLoaded = true; try { System.Drawing.Text.PrivateFontCollection pfc = new System.Drawing.Text.PrivateFontCollection(); pfc.AddFontFile("Ubuntu-R.ttf"); } catch { } } ubuntufont = new Font("Ubuntu", 6); ubuntumid = new Font("Ubuntu", 9); ubuntubig = new Font("Ubuntu", 17); KeyCollectionItem k = (KeyCollectionItem)keys[0]; keys.RemoveAt(0); string privkey = k.PrivateKey; if (PreferUnencryptedPrivateKeys) { if (k.EncryptedKeyPair != null && k.EncryptedKeyPair.IsUnencryptedPrivateKeyAvailable()) { privkey = k.EncryptedKeyPair.GetUnencryptedPrivateKey().PrivateKey; } } Bitmap b = QR.EncodeQRCode(privkey); if (PrintMode == PrintModes.PsyBanknote) { if (BitcoinNote == null) { BitcoinNote = Image.FromFile(ImageFilename); } float desiredScale = 550F; float scalefactor = (desiredScale / 650.0F); float leftOffset = (float)printWidth - desiredScale; // draw the note e.Graphics.DrawImage(BitcoinNote, leftOffset + scalefactor * (float)thiscodeX, scalefactor * (float)thiscodeY, (float)650F * scalefactor, (float)650F * scalefactor * (float)BitcoinNote.Height / (float)BitcoinNote.Width); // draw the private QR e.Graphics.DrawImage(b, leftOffset + scalefactor * (float)(thiscodeX + 472), scalefactor * (float)(thiscodeY + 140), scalefactor * 145F, scalefactor * 147F); // draw the public QR Bitmap b2 = QR.EncodeQRCode(k.GetAddressBase58()); e.Graphics.DrawImage(b2, leftOffset + scalefactor * (float)(thiscodeX + 39), scalefactor * (float)(thiscodeY + 90), scalefactor * 128F, scalefactor * 128F); // write bitcoin address StringFormat sf = new StringFormat(); //sf.FormatFlags |= StringFormatFlags.DirectionVertical | StringFormatFlags.DirectionRightToLeft; e.Graphics.RotateTransform(-90F); e.Graphics.DrawString("Bitcoin Address\r\n" + k.GetAddressBase58(), ubuntumid, Brushes.Black, -scalefactor * (float)(thiscodeY + 338), leftOffset + scalefactor * (float)(thiscodeX + 170), sf); // write private key string whattoprint; if (privkey.Length > 30) { whattoprint = privkey.Substring(0, 25) + "\r\n" + privkey.Substring(25); } else { whattoprint = "\r\n" + privkey; } float xpos = 444; if (privkey.StartsWith("6")) { whattoprint = "Password Required\r\n" + whattoprint; xpos -= 10; } e.Graphics.DrawString(whattoprint, ubuntufont, Brushes.Black, -scalefactor * (float)(thiscodeY + 290), leftOffset + scalefactor * (float)(thiscodeX + xpos), sf); e.Graphics.RotateTransform(90F); // write denomination, if any if ((Denomination ?? "") != "") { e.Graphics.DrawString(Denomination, ubuntubig, Brushes.Black, leftOffset + scalefactor * (float)(thiscodeX + 330), scalefactor * (float)(thiscodeY + 310) ); } if (PrintMiniKeysWith1DBarcode && k.Address is MiniKeyPair) { Bitmap barcode1d = Barcode128b.GetBarcode(k.PrivateKey); float aspect1d = (float)barcode1d.Width / (float)barcode1d.Height; e.Graphics.DrawImage(barcode1d, leftOffset + scalefactor * (float)(thiscodeX + 231F), scalefactor * (float)(thiscodeY + 293), scalefactor * 420F, scalefactor * 50F); } } else if (PrintMode == PrintModes.PrivQR) { // ---------------------------------------------------------------- // Paper wallet with only private key QR code. Fits 16 to a page. // ---------------------------------------------------------------- e.Graphics.DrawImage(b, thiscodeX, thiscodeY, 100, 100); e.Graphics.DrawString("Bitcoin address: " + k.GetAddressBase58(), fontsmall, Brushes.Black, thiscodeX + 110, thiscodeY); string whattowrite; if (privkey.Length > 30) { whattowrite = privkey.Substring(0, 25) + "\r\n" + privkey.Substring(25); } else { whattowrite = "\r\n" + privkey; } if (privkey.StartsWith("6")) { whattowrite = whattowrite + "\r\nPassword Required"; } e.Graphics.DrawString(whattowrite, font, Brushes.Black, thiscodeX + 110, thiscodeY + 15); if ((Denomination ?? "") != "") { e.Graphics.DrawString(Denomination + " BTC", fontbig, Brushes.Black, thiscodeX + 110, thiscodeY + 75); } } else if (PrintMode == PrintModes.PubPrivQR) { // ---------------------------------------------------------------- // Paper wallet with public and private QR codes. Fits 8 to a page. // ---------------------------------------------------------------- e.Graphics.DrawImage(b, thiscodeX + 600, thiscodeY, 100, 100); QRCodeEncoder qr2 = new QRCodeEncoder(); qr2.QRCodeVersion = 3; Bitmap b2 = qr2.Encode(k.GetAddressBase58()); e.Graphics.DrawImage(b2, thiscodeX, thiscodeY, 100, 100); e.Graphics.DrawString("Bitcoin address:\r\n" + k.GetAddressBase58(), font, Brushes.Black, thiscodeX + 110, thiscodeY); StringFormat sf = new StringFormat(); sf.Alignment = StringAlignment.Far; // right justify string whattoprint = privkey; if (privkey.StartsWith("6")) { whattoprint = whattoprint + "\r\nPassword Required"; } e.Graphics.DrawString("Private key:\r\n" + whattoprint, font, Brushes.Black, thiscodeX + 597, thiscodeY + 65, sf); } } e.HasMorePages = keys.Count > 0; }
protected override void OnPrintPage(System.Drawing.Printing.PrintPageEventArgs e) { baseOnPrintPage(e); int printHeight; int printWidth; int leftMargin; int rightMargin; Int32 lines; Int32 chars; //Set print area size and margins { printHeight = base.DefaultPageSettings.PaperSize.Height - base.DefaultPageSettings.Margins.Top - base.DefaultPageSettings.Margins.Bottom; printWidth = base.DefaultPageSettings.PaperSize.Width - base.DefaultPageSettings.Margins.Left - base.DefaultPageSettings.Margins.Right; leftMargin = base.DefaultPageSettings.Margins.Left; //X rightMargin = base.DefaultPageSettings.Margins.Top; //Y } int startwidth = 0; int startheight = 50; for (int i = 0; i < 96; i++) { int eachheight = 60, eachwidth = 130; if (keys.Count == 0) { break; } KeyCollectionItem kci = keys[0]; string address = kci.GetAddressBase58(); string privkey = kci.PrivateKey; keys.RemoveAt(0); int thiscodeX = startwidth + eachwidth * (i / 16); int thiscodeY = startheight + eachheight * (i % 16); // ---------------------------------------------------------------- // Coin insert with public and private QR codes. Fits 8 to a page. // ---------------------------------------------------------------- float CircleDiameterInches = (7F / 16F); // 7/16" // draw the private key circle using (Pen blackpen = new Pen(Color.Black)) { // print some alignment marks for use in laser cutting if (i == 0) { e.Graphics.FillRectangle(Brushes.Black, startwidth + eachwidth * 3F, startheight, 0.01F, 0.01F); e.Graphics.FillRectangle(Brushes.Black, startwidth + eachwidth * 3F, (float)startheight + (float)eachheight * 8.5F, 0.01F, 0.01F); e.Graphics.FillRectangle(Brushes.Black, startwidth + eachwidth * 3F, (float)startheight + (float)eachheight * 17F, 0.01F, 0.01F); } blackpen.Width = (1F / 72F); e.Graphics.DrawEllipse(blackpen, thiscodeX + 30F, thiscodeY + 10F, CircleDiameterInches * 100F, CircleDiameterInches * 100F); // Over 30 characters? do a folding insert at 95% diameter away if (privkey.Length > 30) { e.Graphics.DrawEllipse(blackpen, thiscodeX + 30F, thiscodeY + 10F + (CircleDiameterInches * 95F), CircleDiameterInches * 100F, CircleDiameterInches * 100F); e.Graphics.FillEllipse(Brushes.White, thiscodeX + 30F, thiscodeY + 10F + (CircleDiameterInches * 95F), CircleDiameterInches * 100F, CircleDiameterInches * 100F); } e.Graphics.FillEllipse(Brushes.White, thiscodeX + 30F, thiscodeY + 10F, CircleDiameterInches * 100F, CircleDiameterInches * 100F); } int[] charsPerLine = new int[] { 4, 7, 8, 7, 4, 0, 4, 7, 8, 7, 4 }; string privkeyleft = privkey; // if it's going to take two circles, add hyphens if (privkeyleft.Length > 30) { privkeyleft = privkeyleft.Substring(0, 29) + "--" + privkeyleft.Substring(29); } string privkeytoprint = ""; for (int c = 0; c < 11; c++) { if (charsPerLine[c] == 0) { privkeytoprint += "\r\n"; } else { if (privkeyleft.Length > charsPerLine[c]) { privkeytoprint += privkeyleft.Substring(0, charsPerLine[c]) + "\r\n"; privkeyleft = privkeyleft.Substring(charsPerLine[c]); } else { privkeytoprint += privkeyleft + "\r\n"; privkeyleft = ""; } } } using (StringFormat sfcenter = new StringFormat()) { sfcenter.Alignment = StringAlignment.Center; e.Graphics.DrawString(privkeytoprint, fontsmall, Brushes.Black, thiscodeX + 30F + (CircleDiameterInches * 100F / 2F), thiscodeY + 14F, sfcenter); } // draw the address QR code using (Bitmap b2 = QR.EncodeQRCode(address)) { e.Graphics.DrawImage(b2, thiscodeX + 80, thiscodeY + 10, 50, 50); } e.Graphics.RotateTransform(-90F); // transform 90 degrees changes our coordinate space so we can do sideways text. // must swap xy and value supplied as x parameter must be negative // instead of it's now // -Y +X // | | // -X-------+X -Y----------+Y // | PRINT | PRINT // +Y -X using (StringFormat sfright = new StringFormat()) { sfright.Alignment = StringAlignment.Far; e.Graphics.DrawString(address.Substring(0, 12) + "\r\n" + address.Substring(12, 12) + "\r\n" + address.Substring(24), fontsmall, Brushes.Black, -(float)(thiscodeY + 10), (float)(thiscodeX + 130), sfright); } // get out of sideways mode e.Graphics.RotateTransform(90F); } if (keys.Count != 0) { e.HasMorePages = true; } }
/// <summary> /// Code which is actually run on the generation thread. /// </summary> private void GenerationThreadProcess() { Bip38Intermediate intermediate = null; if (GenChoice == GenChoices.Encrypted) { try { intermediate = new Bip38Intermediate(txtTextInput.Text, Bip38Intermediate.Interpretation.IntermediateCode); } catch { } // sink exceptions - just means it's not an intermediate code if (intermediate == null) { intermediate = new Bip38Intermediate(UserText, Bip38Intermediate.Interpretation.Passphrase); } } int detcount = 1; while (RemainingToGenerate > 0 && StopRequested == false) { KeyCollectionItem newitem = null; switch (GenChoice) { case GenChoices.Minikey: MiniKeyPair mkp = MiniKeyPair.CreateRandom(ExtraEntropy.GetEntropy()); string s = mkp.AddressBase58; // read the property to entice it to compute everything newitem = new KeyCollectionItem(mkp); break; case GenChoices.WIF: KeyPair kp = KeyPair.Create(ExtraEntropy.GetEntropy()); s = kp.AddressBase58; newitem = new KeyCollectionItem(kp); break; case GenChoices.Deterministic: kp = KeyPair.CreateFromString(UserText + detcount); detcount++; s = kp.AddressBase58; newitem = new KeyCollectionItem(kp); break; case GenChoices.Encrypted: Bip38KeyPair ekp = new Bip38KeyPair(intermediate); newitem = new KeyCollectionItem(ekp); break; } lock (GeneratedItems) { GeneratedItems.Add(newitem); RemainingToGenerate--; } } GeneratingEnded = true; }
private void btnFirstPrototype_Click(object sender, EventArgs e) { int pagecount; if (!int.TryParse(txtNumberPages.Text, out pagecount)) { MessageBox.Show("Number of Pages is required", "Number of Pages is required", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (pagecount < 1 || pagecount > 99) { MessageBox.Show("Number of Pages must be between 1-99", "Invalid Number of Pages", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // todo: take this out of the UI thread, put it in a class and run on a worker thread // and also rename this button - it's been a long time since this was my original prototype string previousCaption = this.Text; btnFirstPrototype.Enabled = false; this.Text = "GENERATING..."; this.UseWaitCursor = true; // todo: move all the grunt work in to a nice proper Threaded situation // meanwhile, DoEvents is called here to allow the wait cursor, form caption and other "I'm busy..." indicators to be shown to the user before we get into the hard stuff that takes a few moments Application.DoEvents(); string outputFile = txtOutputFile.Text; string logFilePath = string.Format("{0} - LOG {1}.txt", outputFile, DateTime.Now.ToString("yyyy-MM-dd HHmmss")); StreamWriter logFile = new StreamWriter(logFilePath); CoinDef thiscoin = new CoinDef(bundle.template.CoinName, bundle.template.CoinAddressType, bundle.template.CoinIsWIFstupid); logFile.WriteLine(string.Format("Paper Wallet Printer version {0}", Application.ProductVersion)); logFile.WriteLine(string.Format("Generating wallets for coin {0}", thiscoin.ToString())); logFile.WriteLine("Using template: " + bundle.template.TemplateDescription.Replace("\n", " ")); // removes any line breaks from template description as it writes it to the log file bundle.template.LayoutDebugging = layoutDebuggingToolStripMenuItem.Checked; if (bundle.template.LayoutDebugging) { logFile.WriteLine("Layout Debugging is enabled - printed wallets are not intended for live use"); } // make a pdfSharp document PdfDocument doc = new PdfDocument(); int batchNumber = 1; bool crashingOut = false; XImage imgArtwork = XImage.FromGdiPlusImage(bundle.getArtworkImage()); // loop for each page for (int pageNumber = 1; pageNumber <= pagecount; pageNumber++) { // and put a page on it PdfPage page = doc.AddPage(); // note: if you change anything that gets written to logFile from this point until the end-marker is written, this will probably cause // compatibility issues with the Loader tool, which expects to be able to parse the log between these points logFile.WriteLine(string.Format("Generating Page {0} of {1}", pageNumber, pagecount)); logFile.WriteLine("Generated Addresses:"); logFile.WriteLine(); page.Size = bundle.template.pagePrintPaperSize; using (XGraphics gfx = XGraphics.FromPdfPage(page, XPageDirection.Downwards)) { // LOOP Down for (int y = 0; y < bundle.template.pagePrintRows; y++) { // LOOP Across for (int x = 0; x < bundle.template.pagePrintCols; x++) { try { // get PrivKey and Address for this new Wallet KeyPair kp = KeyPair.CreateX(ExtraEntropy.GetEntropy(), false, bundle.template.CoinAddressType, bundle.template.CoinIsWIFstupid); KeyCollectionItem item = new KeyCollectionItem(kp); string address = item.GetAddressBase58(); logFile.WriteLine(address); // get an XForm of our Wallet using (XForm walletForm = getSingleWallet(doc, bundle, imgArtwork, address, item.PrivateKey, batchNumber, bundle.template.LayoutDebugging)) { // decide where on the page to draw this wallet XForm object XUnit walletLeft = XUnit.FromMillimeter(bundle.template.pagePrintLeftMarginMM + ((bundle.template.widthMM + bundle.template.pagePrintColGap) * x)); XUnit walletTop = XUnit.FromMillimeter(bundle.template.pagePrintTopMarginMM + ((bundle.template.heightMM + bundle.template.pagePrintRowGap) * y)); XPoint whereToPutTheForm = new XPoint(walletLeft.Point, walletTop.Point); gfx.DrawImage(walletForm, whereToPutTheForm); } batchNumber++; } catch (Exception ex) { // well, damn... logFile.WriteLine("--- CRASH! ---"); logFile.WriteLine("Encountered Unhandled Exception inside primary Y-X Print Loop"); logFile.WriteLine("Exception:"); logFile.WriteLine(ex.Message); logFile.WriteLine(ex.Source); logFile.WriteLine(ex.StackTrace); crashingOut = true; break; } } if (crashingOut) { break; } } } if (crashingOut) { break; } logFile.WriteLine(); logFile.WriteLine("end"); logFile.WriteLine(); } if (!crashingOut) { logFile.WriteLine("Internal PDF Generation completed OK"); if (File.Exists(outputFile)) { File.Delete(outputFile); } try { doc.Save(outputFile); } catch (Exception ex) { logFile.WriteLine("--- CRASH! ---"); logFile.WriteLine("Encountered Unhandled Exception when Saving PDF from Object to File"); logFile.WriteLine("Exception:"); logFile.WriteLine(ex.Message); logFile.WriteLine(ex.Source); logFile.WriteLine(ex.StackTrace); crashingOut = true; } logFile.WriteLine("PDF saved to File OK - all done"); } logFile.Close(); // if we have failed in generating the PDF in to memory, or failed when saving it to file - show an error to the user, directing them to to the log file if (crashingOut) { this.Text = previousCaption; btnFirstPrototype.Enabled = true; this.UseWaitCursor = false; string errmsg = string.Format("Sorry, Wallet Printing has failed. See the log file for details.\n\nLog file:\n{0}", logFilePath); MessageBox.Show(errmsg, "Printing Failed, Internal Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (chkOpenAfterGenerating.Checked) { // note the current datetime, for comparison if we're trying to wait for PDF Viewer DateTime timeOfStartingViewer = DateTime.Now; System.Diagnostics.Process procViewer = System.Diagnostics.Process.Start(outputFile); if (chkWipeOutputAfterViewing.Checked) { btnFirstPrototype.Enabled = false; this.Text = "WAITING FOR PDF VIEWER TO CLOSE"; procViewer.WaitForExit(); // ok, we *think* that maybe their PDF viewer has closed. But that might not be true. // check to see if we were delayed by a Suspiciously Short length of time TimeSpan timeWaitedForViewer = DateTime.Now - timeOfStartingViewer; if (timeWaitedForViewer.TotalSeconds < 15) { MessageBox.Show("I think your PDF viewer closed really quickly - or I cannot detect if you are done with the generated PDF.\n\nPlease click OK when you are ready for me to delete the generated PDF.", "Ready to delete PDF file?", MessageBoxButtons.OK, MessageBoxIcon.Question); } // overwrite contents of PDF with junk, then delete. This won't be secure against serious forensic attack in all situations, but it's better than just-delete FileInfo info = new FileInfo(outputFile); byte[] junkbytes = new byte[info.Length]; MemSet(junkbytes, 255); File.WriteAllBytes(outputFile, junkbytes); File.Delete(outputFile); } } this.Text = previousCaption; btnFirstPrototype.Enabled = true; this.UseWaitCursor = false; }