VS 2012 Start UI Windows from VSPackage - visual-studio-2012

i've started to work with the VS2012 extensibility possibilities. I did the first few Walkthroughs and now I'm trying get further on. What I'm trying is pretty easy I guess... I'm trying to build a simply vspackage which starts an UI window. Actually i do not find any howto or sample code.
Do you have some links with further information about doing something like that ?
Thanks for you help..
Iki

You can find initial information here.
Here is my code for menu item:
/// <summary>
/// Initialization of the package; this method is called right after the package is sited, so this is the place
/// where you can put all the initialization code that rely on services provided by VisualStudio.
/// </summary>
protected override void Initialize()
{
Debug.WriteLine ("Entering Initialize() of: {0}", this);
base.Initialize();
// Add our command handlers for menu (commands must exist in the .vsct file)
OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if ( null != mcs )
{
// Create the command for the menu item.
CommandID menuCommandID = new CommandID(GuidList.guidPackageProject, (int)PkgCmdIDList.Impl);
OleMenuCommand menuItem = new OleMenuCommand(MenuItemCallback, menuCommandID);
mcs.AddCommand( menuItem );
}
}
/// <summary>
/// This function is the callback used to execute a command when the a menu item is clicked.
/// See the Initialize method to see how the menu item is associated to this function using
/// the OleMenuCommandService service and the MenuCommand class.
/// </summary>
private void MenuItemCallback(object sender, EventArgs e)
{
MyForm form = new MyForm();
form.ShowDialog(); // Here your form is opening
}

I have been searching for a solution to this recently as I also needed to start a WPF form from a VSPackage. I have got things working after a couple of hours searching various topics on this and some good ol' trial and error.
I had an existing WPF-Project in a separate solution, which had to be merged into a VSPackage. Here's the steps to get this working:
Create a new Solution of Project type 'Visual Studio Package'
Make sure you select the 'Tool Window' option in the VS Package
Wizard (see the image below)
Now that the Solution has been created, add the already existing
WPF-Project to it (Right-Click 'Solution', Add->Existing Project) NOTE: It might be wise to copy the WPF-project to the Solution folder prior to adding it to the Solution.
Make sure you create a reference to the WPF-Project from your
VSPackage-Project and (if necessary) edit the namespaces of the WPF-Project to meet those of the VSPackage-Project, or the other way around.
Your Solution will now look something like this:
Now, you need to edit MyToolWindow.cs:
// Original:
base.Content = new MyControl();
// Change to:
base.Content = new MainWindow();
Make the following changes to VSPackage1Package.cs (or whatever your *Package.cs file is called)
// Original
private void ShowToolWindow(object sender, EventArgs e)
{
// Get the instance number 0 of this tool window. This window is single instance so this instance
// is actually the only one.
// The last flag is set to true so that if the tool window does not exists it will be created.
ToolWindowPane window = this.FindToolWindow(typeof(MyToolWindow), 0, true);
if ((null == window) || (null == window.Frame))
{
throw new NotSupportedException(Resources.CanNotCreateWindow);
}
IVsWindowFrame windowFrame = (IVsWindowFrame)window.Frame;
Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(windowFrame.Show());
}
// Change to:
private void ShowToolWindow(object sender, EventArgs e)
{
// Get the instance number 0 of this tool window. This window is single instance so this instance
// is actually the only one.
// The last flag is set to true so that if the tool window does not exists it will be created.
//ToolWindowPane window = this.FindToolWindow(typeof(MyToolWindow), 0, true);
//if ((null == window) || (null == window.Frame))
//{
// throw new NotSupportedException(Resources.CanNotCreateWindow);
//}
//IVsWindowFrame windowFrame = (IVsWindowFrame)window.Frame;
//Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(windowFrame.Show());
MainWindow mainwin = new MainWindow();
mainwin.Show();
}
If you get no build errors, you should be fine.
To test if your WPF-form opens, Press 'Start' to run the VSPackage in a new 'Experimental' Visual Studio instance. If everything went OK, you will find and should be able to run your WPF-from from the View->Other Windows menu.
If you don't see your VSPackage listed in the menu, close your 'Experimental' Visual Studio instance. Then Clean en Build your Solution and press 'Start' again. It should show up now.

Related

create custom module for pdf manipulation

I want to create a custom Kofax module. When it comes to the batch processing the scanned documents get converted to PDF files. I want to fetch these PDF files, manipulate them (add a custom footer to the PDF document) and hand them back to Kofax.
So what I know so far:
create Kofax export scripts
add a custom module to Kofax
I have the APIRef.chm (Kofax.Capture.SDK.CustomModule) and the CMSplit as an example project. Unfortunately I struggle getting into it. Are there any resources out there showing step by step how to get into custom module development?
So I know that the IBatch interface represents one selected batch and the IBatchCollection represents the collection of all batches.
I would just like to know how to setup a "Hello World" example and could add my code to it and I think I don't even need a WinForms application because I only need to manipulate the PDF files and that's it...
Since I realized that your question was rather about how to create a custom module in general, allow me to add another answer. Start with a C# Console Application.
Add Required Assemblies
Below assemblies are required by a custom module. All of them reside in the KC's binaries folder (by default C:\Program Files (x86)\Kofax\CaptureSS\ServLib\Bin on a server).
Setup Part
Add a new User Control and Windows Form for setup. This is purely optional - a CM might not even have a setup form, but I'd recommend adding it regardless. The user control is the most important part, here - it will add the menu entry in KC Administration, and initialize the form itself:
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ISetupForm
{
[DispId(1)]
AdminApplication Application { set; }
[DispId(2)]
void ActionEvent(int EventNumber, object Argument, out int Cancel);
}
[ClassInterface(ClassInterfaceType.None)]
[ProgId("Quipu.KC.CM.Setup")]
public class SetupUserControl : UserControl, ISetupForm
{
private AdminApplication adminApplication;
public AdminApplication Application
{
set
{
value.AddMenu("Quipu.KC.CM.Setup", "Quipu.KC.CM - Setup", "BatchClass");
adminApplication = value;
}
}
public void ActionEvent(int EventNumber, object Argument, out int Cancel)
{
Cancel = 0;
if ((KfxOcxEvent)EventNumber == KfxOcxEvent.KfxOcxEventMenuClicked && (string)Argument == "Quipu.KC.CM.Setup")
{
SetupForm form = new SetupForm();
form.ShowDialog(adminApplication.ActiveBatchClass);
}
}
}
Runtime Part
Since I started with a console application, I could go ahead and put all the logic into Program.cs. Note that is for demo-purposes only, and I would recommend adding specific classes and forms later on. The example below logs into Kofax Capture, grabs the next available batch, and just outputs its name.
class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, eventArgs) => KcAssemblyResolver.Resolve(eventArgs);
Run(args);
return;
}
static void Run(string[] args)
{
// start processing here
// todo encapsulate this to a separate class!
// login to KC
var login = new Login();
login.EnableSecurityBoost = true;
login.Login();
login.ApplicationName = "Quipu.KC.CM";
login.Version = "1.0";
login.ValidateUser("Quipu.KC.CM.exe", false, "", "");
var session = login.RuntimeSession;
// todo add timer-based polling here (note: mutex!)
var activeBatch = session.NextBatchGet(login.ProcessID);
Console.WriteLine(activeBatch.Name);
activeBatch.BatchClose(
KfxDbState.KfxDbBatchReady,
KfxDbQueue.KfxDbQueueNext,
0,
"");
session.Dispose();
login.Logout();
}
}
Registering, COM-Visibility, and more
Registering a Custom Module is done via RegAsm.exe and ideally with the help of an AEX file. Here's an example - please refer to the documentation for more details and all available settings.
[Modules]
Minimal CM
[Minimal CM]
RuntimeProgram=Quipu/CM/Quipu.KC.CM/Quipu.KC.CM.exe
ModuleID=Quipu.KC.CM.exe
Description=Minimal Template for a Custom Module in C#
Version=1.0
SupportsTableFields=True
SupportsNonImageFiles=True
SetupProgram=Minimal CM Setup
[Setup Programs]
Minimal CM Setup
[Minimal CM Setup]
Visible=0
OCXFile=Quipu/CM/Quipu.KC.CM/Quipu.KC.CM.exe
ProgID=Quipu.KC.CM.Setup
Last but not least, make sure your assemblies are COM-visible:
I put up the entire code on GitHub, feel free to fork it. Hope it helps.
Kofax exposes a batch as an XML, and DBLite is basically a wrapper for said XML. The structure is explained in AcBatch.htm and AcDocs.htm (to be found under the CaptureSV directory). Here's the basic idea (just documents are shown):
AscentCaptureRuntime
Batch
Documents
Document
A single document has child elements itself such as pages, and multiple properties such as Confidence, FormTypeName, and PDFGenerationFileName. This is what you want. Here's how you would navigate down the document collection, storing the filename in a variable named pdfFileName:
IACDataElement runtime = activeBatch.ExtractRuntimeACDataElement(0);
IACDataElement batch = runtime.FindChildElementByName("Batch");
var documents = batch.FindChildElementByName("Documents").FindChildElementsByName("Document");
for (int i = 0; i < documents.Count; i++)
{
// 1-based index in kofax
var pdfFileName = documents[i + 1]["PDFGenerationFileName"];
}
Personally, I don't like this structure, so I created my own wrapper for their wrapper, but that's up to you.
With regard to the custom module itself, the sample shipped is already a decent start. Basically, you would have a basic form that shows up if the user launches the module manually - which is entirely optional if work happens in the back, preferably as Windows Service. I like to start with a console application, adding forms only when needed. Here, I would launch the form as follows, or start the service. Note that I have different branches in case the user wants to install my Custom Module as service:
else if (Environment.UserInteractive)
{
// run as module
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new RuntimeForm(args));
}
else
{
// run as service
ServiceBase.Run(new CustomModuleService());
}
}
The runtime for itself just logs you into Kofax Capture, registers event handlers, and processes batch by batch:
// login to KC
cm = new CustomModule();
cm.Login("", "");
// add progress event handlers
cm.BatchOpened += Cm_BatchOpened;
cm.BatchClosed += Cm_BatchClosed;
cm.DocumentOpened += Cm_DocumentOpened;
cm.DocumentClosed += Cm_DocumentClosed;
cm.ErrorOccured += Cm_ErrorOccured;
// process in background thread so that the form does not freeze
worker = new BackgroundWorker();
worker.DoWork += (s, a) => Process();
worker.RunWorkerAsync();
Then, your CM fetches the next batch. This can either make use of Kofax' Batch Notification Service, or be based on a timer. For the former, just handle the BatchAvailable event of the session object:
session.BatchAvailable += Session_BatchAvailable;
For the latter, define a timer - preferrably with a configurable polling interval:
pollTimer.Interval = pollIntervalSeconds * 1000;
pollTimer.Elapsed += PollTimer_Elapsed;
pollTimer.Enabled = true;
When the timer elapses, you could do the following:
private void PollTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
mutex.WaitOne();
ProcessBatches();
mutex.ReleaseMutex();
}

VSTO-Excel Custom Task Pane AutoResize based on Screen Resolution

I have a problem with my VSTO addin for excel.
I tried creating custom task pane fot my addin. However, when I tried to deploy it on a screen with different resolution from the developer's monitor, the addin does not automatically fits the screen. Note: my clients have different screen resolution.
On my vsto project, i tried to create a custom user control, and attach it on the excel pane.
Please see my code below:
private void btnDownload_Click(object sender, RibbonControlEventArgs e)
{
taskPaneView = new ucCusipAddPanel();
if (myTaskPane == null)
{
myTaskPane = Globals.ThisAddIn.CustomTaskPanes.Add(taskPaneView, "My Custom Task Pane");
myTaskPane.DockPosition = Office.MsoCTPDockPosition.msoCTPDockPositionRight;
myTaskPane.DockPositionRestrict = Office.MsoCTPDockPositionRestrict.msoCTPDockPositionRestrictNoChange;
myTaskPane.Visible = true;
myTaskPane.Width = 303;
}
else
{
myTaskPane.Visible = true;
taskPaneView.BringToFront();
taskPaneView.Focus();
}
}
ucCusipAddPanel is the name of my user control.
This is how invoke my custom taskpane upon ribbon button click. I already set the AutoSize property to true of my user control however still the problem exists.
How could I resolve this?
Thank you in advance.
You need to play with the AutoScaleMode of the myTaskPane object.
I think the correct solution is to use: myTaskPane.AutoScaleMode = AutoScaleMode.Dpi;
see MSDN

Create Property Sheet in Frame Window

I am using an MDI application. I want to create a property sheet inside Frame Window area as shown by arrow in image below:
I have seen examples where we can use ShowWindow() function after creating property sheet but it creates property sheet which is not embedded in frame window.
Can we create propertysheet on frame window only like other controls as static box etc?
If you need to embed a resizable property sheet to the view, please take a look at BCGSoft size(http://www.bcgsoft.com) - the latest BCGControlBar from version shows how to do it:
http://www.bcgsoft.com/images/resizableform220.jpg
If you simply need a tabbed MDI windows, just create a Visual Studio-like application in MFC AppWizard (VS 2008 or later).
Hope, this helps.
Rob
Adding CMultiDocTemplate instances solved my problem. Here is code snippet. This is part of ProjectName.cpp file:
BOOL CEmuDiagnosticsClientApp::InitInstance()
{
// InitCommonControlsEx() is required on Windows XP if an application
// manifest specifies use of ComCtl32.dll version 6 or later to enable
// visual styles. Otherwise, any window creation will fail.
INITCOMMONCONTROLSEX InitCtrls;
InitCtrls.dwSize = sizeof(InitCtrls);
// Set this to include all the common control classes you want to use
// in your application.
InitCtrls.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&InitCtrls);
CWinAppEx::InitInstance();
// Initialize OLE libraries
if (!AfxOleInit())
{
AfxMessageBox(IDP_OLE_INIT_FAILED);
return FALSE;
}
AfxEnableControlContainer();
//Added new code
{
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(IDR_STRING_LOGGINGWINDOW,
RUNTIME_CLASS(CEmuDiagnosticsClientDoc),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CLoggingWindow));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
}
//End: Added new code
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need
// Change the registry key under which our settings are stored
// TODO: You should modify this string to be something appropriate
// such as the name of your company or organization
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
LoadStdProfileSettings(4); // Load standard INI file options (including MRU)
InitContextMenuManager();
InitKeyboardManager();
InitTooltipManager();
CMFCToolTipInfo ttParams;
ttParams.m_bVislManagerTheme = TRUE;
theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);
// Register the application's document templates. Document templates
// serve as the connection between documents, frame windows and views
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(IDR_STRING_SIGNALWINDOW,
RUNTIME_CLASS(CEmuDiagnosticsClientDoc),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CSignalWindow)); //Changed Code
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
// create main MDI Frame window
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME))
{
delete pMainFrame;
return FALSE;
}
m_pMainWnd = pMainFrame;
// call DragAcceptFiles only if there's a suffix
// In an MDI app, this should occur immediately after setting m_pMainWnd
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Dispatch commands specified on the command line. Will return FALSE if
// app was launched with /RegServer, /Register, /Unregserver or /Unregister.
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// The main window has been initialized, so show and update it
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();
return TRUE;
}
In //Added New code section, created a new CMultiDocTemplate instance. CLoggingWindow is the class which I wanted to display in frame window.
Another class CSignalWindow I also wanted to display which is modified in //changed code area.
Things to remember:
-Dialog which you want to display must be derived from CFormView, not CDialog.
-Changed dialog property: Border -> None, Style -> Child and all other properties to false.

Confirm dialog window when closing a tab

I'm new to JavaFX. I want to create Listener which calls question dialog when user closes a tab into the TabPane. So far I managed to create tabs dynamically and add some custom configuration.
tabAvLabel = new Label(ss);
tabPane.getTabs().add(0, tab); // Place the new tab always first
tabPane.getSelectionModel().select(tab); // Always show the new tab
tabPane.setTabClosingPolicy(TabPane.TabClosingPolicy.ALL_TABS); // Add close button to all new tabs
I don't know what event listener I need to use and how to define it. Would you show me how to implement this?
You can try onCloseRequest for Tab class
tab.setOnCloseRequest(new EventHandler<Event>()
{
#Override
public void handle(Event arg0)
{
//your code
}
});
Try this code :
tabAvLabel = new Label(ss);
tabPane.getTabs().add(0, tab); // Place the new tab always first
tabPane.getSelectionModel().select(tab); // Always show the new tab
tabPane.setTabClosingPolicy(TabPane.TabClosingPolicy.ALL_TABS); // Add close button to all new tabs
tabPane.getOnClosed(), setOnClosed(new EventHandler<Event>(){
#Override void handle(Event e){
// What you have to do here
}
})
For more information, see http://docs.oracle.com/javafx/2/api/javafx/scene/control/Tab.html#onClosedProperty
I've hacked a similar support you have in jdk8 support into 2.2 (https://git.eclipse.org/c/efxclipse/org.eclipse.efxclipse.git/tree/bundles/runtime/org.eclipse.fx.e4.controls.fx2/src/org/eclipse/fx/e4/controls/fx2)
The answer of #VagrantAI can work. But you have to add the following codes on your 'OK' button click action function:
stage.fireEvent(
new WindowEvent(
stage,
WindowEvent.WINDOW_CLOSE_REQUEST
)
);
While the problem of this approach is the event is triggered when you click 'X' to close the window too. This should not be the purpose normally.
To solve this, add a flag (or static variable) in the class that loads the window. So every time the window is loaded, set the flag to false. When the window is closed, set the flag only when the 'OK' button is clicked. Then you can do your action regarding the value of this flag.

Trying to Use LoadMoreElement in Monotouch.Dialog

I am using Monotouch to write an Ipad app. The app uses tables to browse down through a directory tree and then select a file. I have used Monotouch.Dialog to browse the directories and I set up the directory tables as the app starts.However there are too many files to set up in a table as the app starts and so I want to set up the 'file table' as the file is selected from the lowest level directory table. I am trying to use LoadMoreElement to do this but I cannot make it work or find any examples online. I have coded the 'Elements API Walkthrough' in the Xamarin tutorial at:- http://docs.xamarin.com/ios/tutorials/MonoTouch.Dialog
I then add a new section to the code:-
_addButton.Clicked += (sender, e) => {
++n;
var task = new Task{Name = "task " + n, DueDate = DateTime.Now};
var taskElement = new RootElement (task.Name){
new Section () {
new EntryElement (task.Name,
"Enter task description", task.Description)
},
new Section () {
new DateElement ("Due Date", task.DueDate)
},
new Section()
{
new LoadMoreElement("Passive","Active",
delegate {MyAction();})
}
};
_rootElement [0].Add (taskElement);
Where MyAction is:-
public void MyAction()
{
Console.WriteLine ("we have been actioned");
}
The problem is that MyAction is triggered and Console.Writeline writes the message but the table stays in the active state and never returns to passive. the documentation says:-
Once your code in the NSAction is finished, the UIActivity indicator stops animating and the normal caption is displayed again.
What am I missing?
Ian
You need to set the "Animating" property in the element to false.
Like this:
LoadMoreElement loadMore = null;
loadMore = new LoadMoreElement (
"Passive", "Active",
delegate {loadMore.Animating = false;});
Where did you see any documentation that says that the animation stops when the delegate stops running? If that is documented anywhere, that is wrong.

Resources