Deployment of Outlook Add-in - no resources / images - vb.net

I am trying to deploy an Add-in I wrote, but it has trouble finding associated resources - that is, images for the ribbon.
My GetImage-function is this:
Dim path As String = AppDomain.CurrentDomain.BaseDirectory
System.Windows.Forms.MessageBox.Show(path)
path = path.Substring(0, path.LastIndexOf("\bin")) + "\Resources\" + imageName
Return New Drawing.Bitmap(path)
The reason it fails seems to be that AppDomain.CurrentDomain.BaseDirectory is C:\Users\MZE\AppData\Local\Apps\2.0\4RZKJG5Q.XVT\72NBJ1XY.1QH\andsoon. So for some reason on publishing the images are not rolled out as resources. I added them via the project properties add resources dialog in Visual Studio.
I have also tried setting build to resources and copy to out in the image properties in Visual Studio.
I would appreciate any hints.

Make sure the images you add to your project are in the Resources section of your solution.
Check the project folder structure for your images.
Try the following revised procedure for your GetImage function. Use IntelliSense to navigate to your images under My.Resources.``resourceName. You shouldn't need to reference a path for the images.
Public Function GetImage(control As Office.IRibbonControl) As System.Drawing.Bitmap
Try
Select Case control.Id
Case "btnYourButton1"
Return My.Resources.Image1
Case "btnYourButton2"
Return My.Resources.Image2
Case "btnYourButton3"
Return My.Resources.Image3
Case Else
Return Nothing
End Select
Catch ex As Exception
Return Nothing
End Try
End Function
Here is the Microsoft reference for the Resources object.

Related

Custom Post function to upload a file in Self Hosted REST API

I have written a VB.Net Visual basic console application for Self hosting a custom file upload service to be consumed by an application. Concept being the end user uses the application to generate data, when completed the file is uploaded to our server without user intervention. I have complete control over both applications. The problem is I can't figure out the POST Upload signature that can accept several params, including the file or how to actually receive the file. The User application is in beta now, testing all other functionality excluding the "Send File" sub's. I've never seen a file larger then 180 KB; I plan on accepting files sizes up to 1 MB. This lets me place some limitations (and filters) to help avoid abuse of the service.
I'm using NuGet packages webapi.client (4.0.30506), webapi.selfhost (4.0.3056) (and their associated required packages) and newtonsoft.json (4.5.11) and PostMan to test/debug the process. I'm using Visual Studio 2019 (Fully patched and up to date). All of the examples and google research point only to C# (not my language of choice), or are for hosted solutions like IIS.
In Postman, the only place where filenames are accepted are in the body, form-data. So, there is where I set up my key/value pairs with matching (including case and order) the params as defined in the FileULRequest class.
Everything that I've tried returns either
'500 internal server error'
or
"Message": "No HTTP resource was found that matches the request URI 'http://10.0.1.102:21212/file/upload/'."
The class object of the request looks like this:
Public Class FileULRequest
Public Property EncToken As String 'Holds an encrypted token for authorization
Public Property Filename As String 'Holds a recommended file name
Public Property AppID As String 'Holds the client/app ID for simpler server actions
Public Property File As Byte() 'Not sure if this is the right type/ should be the encrypted file contents.
End Class
The POST function signature currently looks like this:
Imports System.Web.Http
Namespace Controllers
Public Class FileController
Inherits ApiController
Public Function PostUpload(<FromBody()> ByVal ObjRequest As FileULRequest) As String
Return ""
End Function
End Class
End Namespace
In the Sub Main I have: (note, this is cleaned out)
Sub Main()
API_URL = Dns.GetHostByName(Dns.GetHostName()).AddressList(0).ToString()
Dim ThisConfig As New HttpSelfHostConfiguration("HTTP://" & API_URL & ":" & API_PORT)
ThisConfig.Routes.MapHttpRoute(name:="FileUpload", routeTemplate:="{controller}/{ObjRequest}", defaults:=New With {.id = RouteParameter.Optional})
ThisConfig.MaxConcurrentRequests = API_MaxCon
Dim Config As HttpSelfHostConfiguration = ThisConfig
Using Webserver As New HttpSelfHostServer(Config)
Try
Webserver.OpenAsync().Wait() 'Start the web server
Console.WriteLine("Listening at: " & API_URL & ":" & API_PORT) 'use the URL & port defined
Console.WriteLine("Enter to end")
Catch ex As Exception
Console.WriteLine("Error:{0}", ex.Message.ToString)
Console.WriteLine("Enter to end")
Console.ReadLine()
End
End Try
Dim Cmd As String = UCase(Console.ReadLine())
End
End Using
End Sub
API_Port and API_MaxCon are properties stored in the Appsettings.
What I'm trying to do is set the FileULRequest object params, post this to the service, confirm & validate the data and, if successful, save the file onto a network share. I've tried a large number of different combinations and nothing seems to get close; I cant get inside the Post event in the debugger to figure out or test anything.

Visual Studio is not letting me add CefSharpBrowserControl to a form via the designer

So I decided to try out the CefSharp extension, and what's the first thing I encounter? An error that doesn't let me use the add-on.
This is ridiculously frustrating because I've done every single thing even the administrator or creator has said to do on any forum I've been on. I tried to just compile the source code on the CEFSharp's GitHub, but that didn't work.
If I'm brutally honest, I think that they should just provide a pre-compiled .dll file or group of .dll files that you can just add to the references, instead of just expecting you to do it yourself. It's just a pain, CEFSharp.
I've tried putting the Configuration to x64 AND Any CPU. I've tried making references to several different dlls associated to CEFSharp. I've tried to add the browser element programmatically, and that's worked, but I can't do anything with it (such as execute code when the webpage is done loading). So far none of these solutions have worked at all.
Imports CefSharp
Imports CefSharp.WinForms
Public Class Browser
Dim browser As New _
CefSharp.WinForms.ChromiumWebBrowser("https://google.com/")
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles _
MyBase.Load
Me.Controls.Add(browser)
browser.Parent = Panel1
browser.Dock = DockStyle.Fill
End Sub
End Class
Any time I want to add the browser control to my form via the designer toolbox, it won't let me. It keeps showing this error box that says "Failed to load CefSharpBrowser, deleting from the toolbox." Or something along those lines. It's supposed to just be able to drop into the designer, but it's obviously not.
There are similar discussions on CefSharp's google group: Adding CefSharp control to the toolbox and The name "WebView" does not exist in the namespace.
They say that Visual Studio has some limitations when using a mixed mode (C++/CLR) assembly. There is no Visual Studio designer support out of the box in CefSharp. There is some hack about how to do it, but I do not think it worth it to even spend time on it. Most people just accept the fact and move on.
We successfully use CefSharp for one of our projects and we add ChromiumWebBrowser control to a form programmatically, very similar to how you did it in your sample.
I've tried to add the browser element programmatically, and that's
worked, but I can't do anything with it (such as execute code when the
webpage is done loading). So far none of these solutions have worked
at all.
There is a LoadingStateChanged event which you can use to monitor the status of a web browser control. We use it to show progress indication until our web page is fully loaded. Here is how we do it:
private System.Windows.Forms.PictureBox picProgress;
bool loaded = false;
ChromiumWebBrowser browse;
public Main()
{
var uiUrl = "some url or local html file";
browse = new ChromiumWebBrowser(uiUrl);
browse.Dock = DockStyle.Fill;
Controls.Add(browse);
browse.LoadingStateChanged += Browse_LoadingStateChanged;
}
private void Browse_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e)
{
if (!e.IsLoading)
{
picProgress.BeginInvoke((Action)(() => {
loaded = true;
picProgress.Visible = false;
browse.Visible = true;
}));
}
else
{
browse.BeginInvoke((Action)(() => {
loaded = false;
browse.Visible = false;
}));
}
}
Sorry, it is in C#, but I think you can easily adapt it for VB.net.

Duplicated Control Name Causing 'Not A Member' Compile Errors

I have created a custom control called MultiTextbox. When I place my control onto a form and try to run my project, I get the following errors:
'MultiTextBox' is not a member of 'MultiTextbox.MultiTextbox'.
Type 'MultiTextbox.MultiTextbox' is not defined.
In my Form1.Designer code, I can see the following issues:
Me.MultiTextbox1 = New MultiTextbox.MultiTextbox()
Me.MultiTextbox1.ObjectAlignment = MultiTextbox.MultiTextbox.ObjectPlacement.Left
Me.MultiTextbox1.Style = MultiTextbox.MultiTextbox.TextboxStyle.Normal
Friend WithEvents MultiTextbox1 As MultiTextbox.MultiTextbox
I don't understand why it is duplicating the Control name for a selected few items.
The properties it is referring to are custom properties based from Enums.
For example:
Public Enum ObjectPlacement
Left
Right
End Enum
Private m_ObjectAlignment As ObjectPlacement = ObjectPlacement.Left
'ObjectAlignment
<Browsable(True), Category("Appearance"), _
Description("The text to display as an input group header.")> _
Public Property ObjectAlignment As ObjectPlacement
Get
Return m_ObjectAlignment
End Get
Set(value As ObjectPlacement)
If m_ObjectAlignment = value Then Return
m_ObjectAlignment = value
Me.Invalidate()
End Set
End Property
UPDATE
If I place my custom control on a form and run, everything will work fine without error, but as soon as I modify my control in any way (e.g. Size, Style, etc.) it gives me errors, and I can't even run the application as the compiler just sits in an infinite loop saying 'Building...'. I have to force quit VS.
Okay, after some useful posts on this thread and some googling, I found that by removing the Root Namespace from my project it removed all of my compiler errors that I was getting regarding a duplicated namespace (MultiTextbox.MultiTextbox):
Me.MultiTextbox1 = New MultiTextbox.MultiTextbox()
Me.MultiTextbox1.ObjectAlignment = MultiTextbox.MultiTextbox.ObjectPlacement.Left
Me.MultiTextbox1.Style = MultiTextbox.MultiTextbox.TextboxStyle.Normal
Friend WithEvents MultiTextbox1 As MultiTextbox.MultiTextbox
Secondly, the lockups that I was experiencing when trying to build my project was due to me setting a button's visible state within my paint event causing an infinite refresh loop of my control.

Converting TIFF to PDF results in Insufficient Data For Image

I have a utility that converts batches of TIFF images to PDFs using the PDFSharp library. The following code performs the actual conversion. When I open the resulting PDF files in Acrobat Reader, I receive an error message for certain ones stating "Insufficient Data for Image." Others are fine.
What could be causing this? Is there anything I'm missing in the code that could prevent this?
Public Shared Function ConvertImageToPDF(ByVal img As Image) As Byte()
Using ms As New MemoryStream()
Using pdf As New PdfDocument()
Dim pageCount = GetPageCount(img)
For index = 0 To (pageCount - 1)
Dim page = New PdfPage()
Using sourceImage = GetPage(img, index)
Using pageImage = XImage.FromGdiPlusImage(sourceImage)
page.Width = pageImage.PointWidth
page.Height = pageImage.PointHeight
pdf.Pages.Add(page)
Using xgr = XGraphics.FromPdfPage(pdf.Pages(index))
xgr.DrawImage(pageImage, 0, 0)
End Using
End Using
End Using
Next
pdf.Save(ms, False)
pdf.Close()
End Using
Return ms.ToArray()
End Using
End Function
Public Shared Function GetPageCount(ByVal img As Image) As Integer
If (img Is Nothing) Then
Return -1
End If
Return img.GetFrameCount(FrameDimension.Page)
End Function
Public Shared Function GetPage(ByVal img As Image, ByVal pageNumber As Integer) As Image
img.SelectActiveFrame(FrameDimension.Page, pageNumber)
Dim ms = New MemoryStream()
img.Save(ms, ImageFormat.Tiff)
Return Image.FromStream(ms)
End Function
UPDATE:
If I run the same code over the same TIFF files, then the PDF files that were corrupt before are now OK, and ones that were OK before are now corrupt.
UPDATE 2:
After reviewing this connect issue (https://connect.microsoft.com/VisualStudio/feedback/details/584681/system-drawing-image-flags-has-different-value-in-vista-and-windows-7) and the community comment on this MSDN page (http://msdn.microsoft.com/en-us/library/system.drawing.image.save.aspx), it appears the issue is related to an operating system level bug in Windows 7. Can anyone confirm this or offer a workaround?
As stated in my update, after reviewing this connect issue (https://connect.microsoft.com/VisualStudio/feedback/details/584681/system-drawing-image-flags-has-different-value-in-vista-and-windows-7) and the community comment on this MSDN page (http://msdn.microsoft.com/en-us/library/system.drawing.image.save.aspx), it appears the issue is related to an operating system level bug in Windows 7.
This is supported by the comment from PDFsharpTeam.
In addition, when the images are read in Windows XP, the flags property on the image object is set to 77888. On Win7, it is set to 77840. After reviewing the MSDN documentation for the flags property (http://msdn.microsoft.com/en-us/library/system.drawing.image.flags.aspx), the difference is that WinXP flagged the image as a grayscale image (which mine are), but Win7 flagged it as an RGB image. This appears to be a symptom of the problem, but I don't know enough about image formats and color spaces to speak with authority on this.
UPDATE (2014-06-13):
After continuing to experience this problem, I researched a bit further and found a post on the PDFSharp forums mentioning this issue and linking to another post with a fix.
http://forum.pdfsharp.net/viewtopic.php?f=2&t=2729
http://forum.pdfsharp.net/viewtopic.php?p=5967#p5967
Basically, there are two methods in the PdfImage.FaxEncode.cs file that need to be updated.
In both the CountOneBits() and CountZeroBits() methods, replace the following code:
return found + hits;
with
found += hits;
if (found >= bitsLeft)
return bitsLeft;
return found;

Filetype check in VB.NET?

I have an image resized program and it works. The problem is when a user selects a non-image file in the file select dialog, it crashes. How can I check for image files?
UPDATE: 2022-04-05
Since it may not be feasible to validate the binary structure of every supported image, the fastest way to check if a file contains an image is to actually load it. If it loads successfully, then it is valid. If it doesn't then it is not.
The code below can be used to check if a file contains a valid image or not. This code is updated to prevent locking the file while the method is called. It also handles resource disposal after the tests (thanks for pointing out this issue user1931470).
Public Function IsValidImage(fileName As String) As Boolean
Dim img As Drawing.Image = Nothing
Dim isValid = False
Try
' Image.FromFile locks the file until the image is disposed.
' This might not be the wanted behaviour so it is preferable to
' open the file stream and read the image from it.
Using stream = New System.IO.FileStream(fileName, IO.FileMode.Open)
img = Drawing.Image.FromStream(stream)
isValid = True
End Using
Catch oome As OutOfMemoryException
' Image.FromStream throws an OutOfMemoryException
' if the file does not have a valid image format.
isValid = False
Finally
' clean up resources
If img IsNot Nothing Then img.Dispose()
End Try
Return isValid
End Function
ORIGINAL ANSWER
⚠️⚠️ WARNING ⚠️⚠️
This code has a bug that causes a high memory consumption when called several times in a program's lifetime.
DO NOT USE THIS CODE!!
Here's the VB.NET equivalent of 0xA3's answer since the OP insisted on a VB version.
Function IsValidImage(filename As String) As Boolean
Try
Dim img As System.Drawing.Image = System.Drawing.Image.FromFile(filename)
Catch generatedExceptionName As OutOfMemoryException
' Image.FromFile throws an OutOfMemoryException
' if the file does not have a valid image format or
' GDI+ does not support the pixel format of the file.
'
Return False
End Try
Return True
End Function
You use it as follows:
If IsValidImage("c:\path\to\your\file.ext") Then
'do something
'
Else
'do something else
'
End If
Edit:
I don't recommend you check file extensions. Anyone can save a different file (text document for instance) with a .jpg extension and trick you app into beleiving it is an image.
The best way is to load the image using the function above or to open the first few bytes and check for the JPEG signature.
You can find more information about JPEG files and their headers here:
http://www.fastgraph.com/help/jpeg_header_format.html
http://en.wikipedia.org/wiki/JPEG
A very primitive check is to simply try to load the image. If it is not valid an OutOfMemoryException will be thrown:
static bool IsImageValid(string filename)
{
try
{
System.Drawing.Image img = System.Drawing.Image.FromFile(filename);
}
catch (OutOfMemoryException)
{
// Image.FromFile throws an OutOfMemoryException
// if the file does not have a valid image format or
// GDI+ does not support the pixel format of the file.
//
return false;
}
return true;
}
If I understood your question correctly your application it going to load the image anyway. Therefore simply wrapping the load operation in a try/catch block does not mean any additional overhead. For the VB.NET solution of this approach check the answer by #Alex Essilfie.
The ones wondering why Image.FromFile is throwing an OOM on invalid files should read the answer of Hans Passant to the following question:
Is there a reason Image.FromFile throws an OutOfMemoryException for an invalid image format?
Your first line of defense, of course, would be simply to check the file's extension:
Function IsImageFile(ByVal filename As String) As Boolean
Dim ext As String = Path.GetExtension(filename).ToLowerInvariant()
' This supposes your program can deal only with JPG files; '
' you could add other extensions here as necessary. '
Return ext = ".jpg" OrElse ext = ".jpeg"
End Function
Better yet, as SLC suggests in a comment, set your dialog's Filter property:
dialog.Filter = "Image files|*.jpg;*.jpeg"
This isn't a guarantee -- ideally you'd want to check the file itself to verify it's an image, and theoretically you should also be able to load files with anomalous extensions if they are in fact image files (maybe just ask for the user's acknowledgement first) -- but it's an easy start.
The VB and C# answers are great but also contain a "gotcha" if you plan to alter or move the file: the created 'img' object will lock the image file unless the dispose() method is invoked to release it. See below:
VB
Function IsValidImage(filename As String) As Boolean
Try
Dim img As System.Drawing.Image = System.Drawing.Image.FromFile(filename)
img.dispose() ' Removes file-lock of IIS
Catch generatedExceptionName As OutOfMemoryException
' Image.FromFile throws an OutOfMemoryException
' if the file does not have a valid image format or
' GDI+ does not support the pixel format of the file.
'
Return False
End Try
Return True
End Function
C#
static bool IsImageValid(string filename)
{
try
{
System.Drawing.Image img = System.Drawing.Image.FromFile(filename);
img.dispose(); // Removes file-lock of IIS
}
catch (OutOfMemoryException)
{
// Image.FromFile throws an OutOfMemoryException
// if the file does not have a valid image format or
// GDI+ does not support the pixel format of the file.
//
return false;
}
return true;
}
The most robust way would be to understand the signatures of the files you need to load.
JPEG has a particular header format, for example.
This way your code won't be as easily fooled if you just look at the extension.
163's answer should get you most of the way along these lines.