I'm trying to add multiple (actually 3 ) views to an SDI application and give the user choose witch View will be load according to his choice :
IMG
I have followed this tutorial in the official MS documentation .
So, have created three classes : CAdminView CAssistantView CBiblioView and an authentication class associated to a dialog frame .
My Questions are :
1) how to edit this three view classes (Graphically) ?
2) at first time I want to show just the authentication dialog window , how to do that ?
* I tried to change m_pMainWnd->ShowWindow(SW_SHOW);
by m_pMainWnd->ShowWindow(SW_HIDE); but no expected result
3) I expect to load the view according to parameter, this is what I added to the InitInstance funnction :
CView* pActiveView = ((CFrameWnd*) m_pMainWnd)->GetActiveView();
m_BiblioView = (CView*) new CBiblioView;
m_AdminView = (CView*) new CAdminView;
m_AssistantView = (CView*) new CAssistantView;
CDocument* pCurrentDoc = ((CFrameWnd*)m_pMainWnd)->GetActiveDocument();
// Initialize a CCreateContext to point to the active document.
// With this context, the new view is added to the document
// when the view is created in CView::OnCreate().
CCreateContext newContext;
newContext.m_pNewViewClass = NULL;
newContext.m_pNewDocTemplate = NULL;
newContext.m_pLastView = NULL;
newContext.m_pCurrentFrame = NULL;
newContext.m_pCurrentDoc = pCurrentDoc;
// The ID of the initial active view is AFX_IDW_PANE_FIRST.
// Incrementing this value by one for additional views works
// in the standard document/view case but the technique cannot
// be extended for the CSplitterWnd case.
UINT viewID = AFX_IDW_PANE_FIRST + 1;
CRect rect(0, 0, 0, 0); // Gets resized later.
// Create the new view. In this example, the view persists for
// the life of the application. The application automatically
// deletes the view when the application is closed.
m_AdminView->Create(NULL, "Fenetre Administrarteur", WS_CHILD, rect, m_pMainWnd, viewID, &newContext);
m_AssistantView->Create(NULL, "Fenetre Assistant", WS_CHILD, rect, m_pMainWnd, viewID, &newContext);
m_BiblioView->Create(NULL, "Fenetre Bibliothecaire ", WS_CHILD, rect, m_pMainWnd, viewID, &newContext);
// When a document template creates a view, the WM_INITIALUPDATE
// message is sent automatically. However, this code must
// explicitly send the message, as follows.
m_AdminView->SendMessage(WM_INITIALUPDATE, 0, 0);
m_AssistantView->SendMessage(WM_INITIALUPDATE, 0, 0);
m_BiblioView->SendMessage(WM_INITIALUPDATE, 0, 0);
and this is my switch function :
CView* CMiniProjetApp::SwitchView(int Code ) //1 : Admi / 2 : Biblio / 3 : Assistant
{
CView* pActiveView =((CFrameWnd*) m_pMainWnd)->GetActiveView();
CView* pNewView= NULL;
switch(Code){
case 1 : pNewView= m_AdminView; break;
case 2 : pNewView= m_BiblioView; break;
case 3 : pNewView= m_AssistantView; break;
}
// Exchange view window IDs so RecalcLayout() works.
#ifndef _WIN32
UINT temp = ::GetWindowWord(pActiveView->m_hWnd, GWW_ID);
::SetWindowWord(pActiveView->m_hWnd, GWW_ID, ::GetWindowWord(pNewView->m_hWnd, GWW_ID));
::SetWindowWord(pNewView->m_hWnd, GWW_ID, temp);
#else
UINT temp = ::GetWindowLong(pActiveView->m_hWnd, GWL_ID);
::SetWindowLong(pActiveView->m_hWnd, GWL_ID, ::GetWindowLong(pNewView->m_hWnd, GWL_ID));
::SetWindowLong(pNewView->m_hWnd, GWL_ID, temp);
#endif
pActiveView->ShowWindow(SW_HIDE);
pNewView->ShowWindow(SW_SHOW);
((CFrameWnd*) m_pMainWnd)->SetActiveView(pNewView);
((CFrameWnd*) m_pMainWnd)->RecalcLayout();
pNewView->Invalidate();
return pActiveView;
}
Any errors notices ??!!
*please help me !
Thanks .
Showing and Hiding the window is the correct way. But you Need to set the view as active too.
You find the required working codein this MSDN Sample VSSWAP32.
The required code to switch and hide the other views is shown in the article.
Related
Is there any way to customize the Nav Bar or the Header to have a custom link?
The use-case is that I have a JIRA issue collector that is driven by javascript. I would like the user to provide feedback from the page they are having issues. However, any solution I can come up with so far takes the user away from the current page.
Example of what I have that takes the user away:
I currently have a Suitelet that is in one of the menus. That Suitelet invokes javascript but even then the user is taken away.
I have a workflow on the case record that calls some Javascript Javascript in one of the UI-based action's conditions is invoked. Similar to #1 but on the case record.
I'm thinking I'm going to need to create and public a chrome extension for my company's domain just to get a pervasive bit of javascript to run for all pages...seems like a sledgehammer.
I hope someone can prove me wrong, but as far as I am aware there is no way to natively inject Javascript or anything into the NetSuite header/navbar - they don't offer customisation to the header/navbar.
I've resorted to creating a Userscript that I load through the Violent Monkey extension for Chrome or Firefox.
Example Userscript Template
// ==UserScript==
// #name NetSuite Mods (Example)
// #namespace Violentmonkey Scripts
// #match *.netsuite.com/*
// #include *.netsuite.com/*
// #grant GM_addStyle
// #version 1.0
// #author Kane Shaw - https://stackoverflow.com/users/4561907/kane-shaw
// #description 6/11/2020, 6:25:20 PM
// ==/UserScript==
// Get access to some commonly used NLAPI functions without having to use "unsafeWindow.nlapi..." in our code
// You can add more of these if you need access to more of the functions contained on the NetSuite page
nlapiSetFieldText = unsafeWindow.nlapiSetFieldText;
nlapiSetFieldValue = unsafeWindow.nlapiSetFieldValue;
nlapiGetFieldText = unsafeWindow.nlapiGetFieldText;
nlapiGetFieldValue = unsafeWindow.nlapiGetFieldValue;
nlapiSearchRecord = unsafeWindow.nlapiSearchRecord;
nlobjSearchFilter = unsafeWindow.nlobjSearchFilter;
nlapiLookupField = unsafeWindow.nlapiLookupField;
nlapiLoadRecord = unsafeWindow.nlapiLoadRecord;
nlapiSubmitRecord = unsafeWindow.nlapiSubmitRecord;
GM_pageTransformations = {};
/**
* The entrypoint for our userscript
*/
function GM_main(jQuery) {
// We want to execute these on every NetSuite page
GM_pageTransformations.header();
GM_pageTransformations.browsertitle();
// Here we build a function name from the path (page being accessed on the NetSuite domain)
var path = location.pathname;
if(path.indexOf('.')>-1) path = path.substr(0,path.indexOf('.'));
path = toCamelCase(path,'/');
// Now we check if a page "GM_pageTransformations" function exists with a matching name
if(GM_pageTransformations[path]) {
console.log('Executing GM_pageTransformations for '+path);
GM_pageTransformations[path]();
} else {
console.log('No GM_pageTransformations for '+path);
}
}
/**
* Changes the header on all pages
*/
GM_pageTransformations['header'] = function() {
// For example, lets make the header background red
GM_addStyle('#ns_header, #ns_header * { background: red !important; }');
}
/**
* Provides useful browser/tab titles for each NetSuite page
*/
GM_pageTransformations['browsertitle'] = function() {
var title = jQuery('.uir-page-title-secondline').text().trim();
var title2 = jQuery('.uir-page-title-firstline').text().trim();
var title3 = jQuery('.ns-dashboard-detail-name').text().trim();
if(title != '') {
document.title = title+(title2 ? ': '+title2 : '')+(title3 ? ': '+title3 : '');
} else if(title2 != '') {
document.title = title2+(title3 ? ': '+title3 : '');
} else if(title3 != '') {
document.title = title3;
}
}
/**
* Changes app center card pages (dashboard pages)
*/
GM_pageTransformations['appCenterCard'] = function() {
// For example, lets make add a new heading text on all Dashboard pages
jQuery('#ns-dashboard-page').prepend('<h1>My New Dashboard Title</h1>');
}
/**
* Convert a given string into camelCase, or CamelCase
* #param {String} string - The input stirng
* #param {String} delimter - The delimiter that seperates the words in the input string (default " ")
* #param {Boolean} capitalizeFirstWord - Wheater or not to capitalize the first word (default false)
*/
function toCamelCase(string, delimiter, capitalizeFirstWord) {
if(!delimiter) delimiter = ' ';
var pieces = string.split(delimiter);
string = '';
for (var i=0; i<pieces.length; i++) {
if(pieces[i].length == 0) continue;
string += pieces[i].charAt(0).toUpperCase() + pieces[i].slice(1);
}
if(!capitalizeFirstWord) string= string.charAt(0).toLowerCase()+string.slice(1);
return string;
}
// ===============
// CREDIT FOR JQUERY INCLUSION CODE: Brock Adams # https://stackoverflow.com/a/12751531/4561907
/**
* Check if we already have a local copy of jQuery, or if we need to fetch it from a 3rd-party server
*/
if (typeof GM_info !== "undefined") {
console.log("Running with local copy of jQuery!");
GM_main(jQuery);
}
else {
console.log ("fetching jQuery from some 3rd-party server.");
add_jQuery(GM_main, "1.9.0");
}
/**
* Add the jQuery into our page for our userscript to use
*/
function add_jQuery(callbackFn, jqVersion) {
var jqVersion = jqVersion || "1.9.0";
var D = document;
var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
var scriptNode = D.createElement ('script');
scriptNode.src = 'https://ajax.googleapis.com/ajax/libs/jquery/'
+ jqVersion
+ '/jquery.min.js'
;
scriptNode.addEventListener ("load", function () {
var scriptNode = D.createElement ("script");
scriptNode.textContent =
'var gm_jQuery = jQuery.noConflict (true);\n'
+ '(' + callbackFn.toString () + ')(gm_jQuery);'
;
targ.appendChild (scriptNode);
}, false);
targ.appendChild (scriptNode);
}
You can copy and paste that code as-is into a new Userscript and it will do the following:
Make Browser tabs/windows have useful titles (shows order numbers, customer names, vendor names etc - not just "Sales Order")
Change the header background to red (as an example)
Add a new heading to the top of all "Dashboard" pages that says "My New Dashboard Title" (as an example)
I try to create a family instance using CreateAdaptiveComponentInstance and try to host it on a reference point, that's also a control point of a CurveByPoints (spline).
The family links properly to the reference point, but the rotation of the reference point's workplane is totally ignored.
Try this standalone example. Move the reference point P2 -> The cross section at P1 will not rotate.
Now, rebuild and change the >> if(true) << to 'false'. Now you see what I want. But as soon as you move the point P2, the link between P2's coordinates and the family is broken.
CurveByPoints spl = null;
ReferencePointArray pts = null;
// create ref points
var p1 = doc.FamilyCreate.NewReferencePoint(new XYZ( 0, 0, 0)); p1.Name = "P1";
var p2 = doc.FamilyCreate.NewReferencePoint(new XYZ(10,10, 0)); p2.Name = "P2";
var p3 = doc.FamilyCreate.NewReferencePoint(new XYZ(30,20, 0)); p3.Name = "P3";
pts = new ReferencePointArray();
pts.Append(p1); pts.Append(p2); pts.Append(p3);
// create a spline
spl = doc.FamilyCreate.NewCurveByPoints(pts);
spl.Visible = true;
spl.IsReferenceLine = false; // MOdelliinie
// change points to adaptive points
foreach(ReferencePoint p in pts)
{
AdaptiveComponentFamilyUtils.MakeAdaptivePoint(doc, p.Id, AdaptivePointType.PlacementPoint);
p.CoordinatePlaneVisibility = CoordinatePlaneVisibility.Always;
p.ShowNormalReferencePlaneOnly = true;
}
// find an adaptive family to place at the points
FamilySymbol fam_sym = null;
var filter = new FilteredElementCollector(doc);
ICollection<Element> col = filter.OfClass(typeof(FamilySymbol)).ToElements();
if(col!=null)
{
foreach(FamilySymbol ele in col)
{
if(ele == null || !AdaptiveComponentInstanceUtils.IsAdaptiveFamilySymbol(ele) ) {continue;}
if(fam_sym == null)
{
fam_sym=ele;
}
if(ele.Name == "profil_adapt_offset_einfach2") // use a special one instead of the first matching
{
fam_sym = ele as FamilySymbol;
break;
}
}
}
// create family instances
if(fam_sym != null)
{
if(true) // this is waht I want. Try "false" to see what I expect
{
foreach (ReferencePoint p in pts)
{
var inst = AdaptiveComponentInstanceUtils.CreateAdaptiveComponentInstance(doc, fam_sym);
var placements = AdaptiveComponentInstanceUtils.GetInstancePlacementPointElementRefIds(inst);
ReferencePoint fam_pt = doc.GetElement(placements.FirstOrDefault()) as ReferencePoint;
var pl = Plane.CreateByNormalAndOrigin(new XYZ(1,0,0), p.Position);
// #### I THINK HERE IS MY PROBLEM ####
// "plane" just points to the reference POINT,
// and not the XZ-PLANE of the reference point.
Reference plane = p.GetCoordinatePlaneReferenceYZ();
PointOnPlane pop = doc.Application.Create.NewPointOnPlane(plane, UV.Zero, UV.BasisU, 0.0);
fam_pt.SetPointElementReference(pop);
}
}
else
{
// create family instances and place along the path
// -> looks good until you move a reference point
double ltot=0.0;
for(var i=0; i<pts.Size-1; ++i)
{
ltot += pts.get_Item(i).Position.DistanceTo(pts.get_Item(i+1).Position);
}
double lfromstart=0;
for(var i=0; i<pts.Size; ++i)
{
if(i>0)
{
lfromstart += pts.get_Item(i).Position.DistanceTo(pts.get_Item(i-1).Position);
}
var inst = AdaptiveComponentInstanceUtils.CreateAdaptiveComponentInstance(doc, fam_sym);
var placements = AdaptiveComponentInstanceUtils.GetInstancePlacementPointElementRefIds(inst);
var location = new PointLocationOnCurve(PointOnCurveMeasurementType.NormalizedCurveParameter, lfromstart / ltot, PointOnCurveMeasureFrom.Beginning);
PointOnEdge po = doc.Application.Create.NewPointOnEdge(spl.GeometryCurve.Reference, location);
// attach first adaptive point to ref point
var firstPoint = doc.GetElement(placements.FirstOrDefault()) as ReferencePoint;
firstPoint.SetPointElementReference(po);
}
}
}
I'm using Revit 2018.2, here.
People might also search for: GetCoordinatePlaneReferenceXZ, GetCoordinatePlaneReferenceXY.
[edit1]
NewReferencePoint() does not create SketchPlanes
When I manually move a generated reference point -> Now the SketchPlane for this ReferencePoint is generated. But how create that with the API?
[edi2]
- I found that e.g. manually changing the ReferencePoint.CoordinatePlaneVisibility=true will create the SketchPlane I need. But I can't do that in code:
var sel = new List<ElementId>();
foreach (ReferencePoint p in pts)
{
sel.Add(p.Id);
// make plane visible
p.CoordinatePlaneVisibility = CoordinatePlaneVisibility.Always;
// shake point
ElementTransformUtils.MoveElement(doc, p.Id, XYZ.BasisX);
ElementTransformUtils.MoveElement(doc, p.Id, XYZ.BasisX.Negate());
}
ui_doc.Selection.SetElementIds(sel);
doc.Regenerate();
ui_doc.RefreshActiveView();
Will it help if you use the NewReferencePoint overload taking a Transform argument, cf. NewReferencePoint Method (Transform)? That might define the required plane for you and associate it with the point.
The development team replied to your detailed description and test project provided in the attached ZIP file:
The developer seems to be in need of some API we haven’t exposed. PointElement’s API was written before RIDL, so the entire user interface is not exposed to the API. They need an API to get the reference plane that is normal to the the curve that it is driving. This plane is not the same as what is exposed by API PointElement.GetCoordinatePlaneReferenceYZ() (one among the three planes exposed to API).
As per SketchPlanes not being created (in the macro seen in the linked zip file), yes that is correct and matches the UI. SketchPlanes are elements and are different from Autodesk.Revit.DB.Reference. We don’t create them until we have to. And they get garbage collected too. At the end of description, I see some code that should work (assuming they wrapped it in a transaction). Normally selection of the point alone will trigger creation of the SketchPlane from the UI. That aside, I would still not recommend putting the point on SketchPlane for what they want to do.
While, what they want does not exist in API, it still does not quite mean there is no workaround for what they want to achieve. If the Selection or Reference API exposes selectable/visible references on an element, Autodesk.Revit.DB.Reference, then one can iterate over these and host the point. This is generic Element/Reference API.
I hope this clarifies.
Suppose I have a large campsite like "seating" chart with several hundred lots sectioned off and outlined in photoshop. (each lot is roughly a square) Every lot needs to be numbered in photoshop and also editable in the future in case of changes. The lots are scattered and curve around the landscape so entering text in one layer seems out since for example lot 27 with be on the right and rotate 20 degrees to match the lot and yet lot 185 might be way over on the left at a far different angle.
Is there an elegant way to do this or at least quickly import a large number sequence that places one number per layer so I can grab them and orient them to their corresponding lot quickly instead of typing out and then positioning ever number individually? I'm having trouble thinking up an elegant/fast way to handle this in Photoshop...
Edit 1 - picture: http://i.imgur.com/UT3DRBi.jpg
You can do it with Extendscript. I am not the best of Extendscript programmers, but the following script will ask you for the number of text labels you want and add that many numbers on sepearate layers. Of course, you can diddle around with the font, colour, position, size etc. but it should get you started.
Here is an example - I turned off layers 4 and 5 so you can see each number is on a new layer.
Here it asks how many numbers you want:
// Setchell - AddNumbers - Adobe Photoshop Script
// Description: Asks user for number of numbers to add, each in own layer
// Version: 0.1
// Author: Mark Setchell (mark#thesetchells.com)
// Web: http://www.thesetchells.com
// ============================================================================
// Installation:
// 1. Place script in 'C:\Program Files\Adobe\Adobe Photoshop CS#\Presets\Scripts\'
// 2. Restart Photoshop
// 3. Choose File > Scripts > AddNumbers
// ============================================================================
// enable double-clicking from Mac Finder or Windows Explorer
// this command only works in Photoshop CS2 and higher
#target photoshop
// bring application forward for double-click events
app.bringToFront();
///////////////////////////////////////////////////////////////////////////////
// AddNumbers
///////////////////////////////////////////////////////////////////////////////
function AddNumbers() {
// Change Debug=1 for extra debugging messages
var Debug=1;
// Get user to enter common stem for JPEG names
var dialog = new Window('dialog', 'Setchell - AddNumbers');
dialog.size = {width:500, height:100};
dialog.stem = dialog.add('edittext',undefined, '<Enter ending number>');
dialog.stem.size = {width:400,height:25};
dialog.stem.value = true;
dialog.stem.buildBtn = dialog.add('button', undefined,'OK', {name:'ok'});
dialog.show();
// Pick up what user entered - just digits
var limit=dialog.stem.text.match(/\d+/);
// Debug
if(Debug)alert(limit);
var cnt;
var n=0;
var nPer=10;
var deltaX=app.activeDocument.width/nPer;
var deltaY=app.activeDocument.height/nPer;
var tX=0;
var tY=deltaY;
app.preferences.typeUnits = TypeUnits.POINTS;
for(cnt=1;cnt<=limit;cnt++){
// Adds a new layer to the active document and stores it in a variable named “myTextLayer”.
var myTextLayer = app.activeDocument.artLayers.add();
// Changes myTextLayer from normal to a text layer.
myTextLayer.kind = LayerKind.TEXT;
// Gets a reference to the textItem property of myTextLayer.
var myText = myTextLayer.textItem;
// sets the font size of the text to 16.
myText.size = 16;
// Sets the contents of the textItem.
myText.contents = cnt;
// Position the label - could be improved :-)
tX=n*deltaX;
myText.position = new Array(tX, tY);
n++;
if(n==nPer){
tY+=deltaY;
n=0;
}
}
return;
}
///////////////////////////////////////////////////////////////////////////////
// isCorrectVersion - check for Adobe Photoshop CS2 (v9) or higher
///////////////////////////////////////////////////////////////////////////////
function isCorrectVersion() {
if (parseInt(version, 10) >= 9) {
return true;
}
else {
alert('This script requires Adobe Photoshop CS2 or higher.', 'Wrong Version', false);
return false;
}
}
///////////////////////////////////////////////////////////////////////////////
// showError - display error message if something goes wrong
///////////////////////////////////////////////////////////////////////////////
function showError(err) {
if (confirm('An unknown error has occurred.\n' +
'Would you like to see more information?', true, 'Unknown Error')) {
alert(err + ': on line ' + err.line, 'Script Error', true);
}
}
// test initial conditions prior to running main function
if (isCorrectVersion()) {
// Save current RulerUnits to restore when we have finished
var savedRulerUnits = app.preferences.rulerUnits;
// Set RulerUnits to PIXELS
app.preferences.rulerUnits = Units.PIXELS;
try {
AddNumbers();
}
catch(e) {
// don't report error on user cancel
if (e.number != 8007) {
showError(e);
}
}
// Restore RulerUnits to whatever they were when we started
app.preferences.rulerUnits = savedRulerUnits;
}
I have a strange problem where I'm trying to print a specific page range in microsoft word from a console app and I'm seeing strange results and I'm assuming it's something I did incorrectly when specifying a page range.
It appears that after I print a page range and go to get the total number of pages in the word document this number varies after I print specific ranges. Another weird thing is that this works in debug mode but not in release mode.
ex.
Word document consists of 2 pages
Print page 1-1.
Get number of pages returns 2
Print page 2-2
Get number of pages returns 1
Code is below for printing a range of pages:
int CWordComm::PrintAndCloseActiveDocument(int iNumOfCopies, short nTray, int pageNumber)
{
// Convenient values declared as ColeVariants.
COleVariant covTrue((short)TRUE), covFalse((short)FALSE), covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
_Document oActiveDoc = m_oWord.GetActiveDocument();
if(!this->m_szOutputFilename.IsEmpty())
{
//If we are outputting the document to a file then we need to print a single page at a time
//This is because of a limitation on the ikonprinter/requisition printer side that can only handle
//one page at a time
// Print out to file
CString szCurrentPage, szPrintRange;
szCurrentPage.Format("%d", pageNumber);
szPrintRange.Format("%d", PRINT_FROM_TO); //PRINT_FROM_TO is #define PRINT_FROM_TO 3
COleVariant printRange(szPrintRange, VT_BSTR);
COleVariant currentPage(szCurrentPage, VT_BSTR);
sprintf(m_szLogMessage, "Printing page %d of requisition", pageNumber);
LogMessage(m_szLogMessage);
oActiveDoc.PrintOut(covFalse, // Background.
covOptional, // Append.
printRange, // Range.
COleVariant(szFileName,VT_BSTR), // OutputFileName.
currentPage, // From.
currentPage, // To.
covOptional, // Item.
COleVariant((long)1), // Copies.
covOptional, // Pages.
covOptional, // PageType.
covTrue, // PrintToFile.
covOptional, // Collate.
covOptional, // ActivePrinterMacGX.
covOptional // ManualDuplexPrint.
);
}
else
{
// Print out to file
oActiveDoc.PrintOut(covFalse, // Background.
covOptional, // Append.
covOptional, // Range.
COleVariant(szFileName,VT_BSTR), // OutputFileName.
covOptional, // From.
covOptional, // To.
covOptional, // Item.
COleVariant((long)1), // Copies.
covOptional, // Pages.
covOptional, // PageType.
covTrue, // PrintToFile.
covOptional, // Collate.
covOptional, // ActivePrinterMacGX.
covOptional // ManualDuplexPrint.
);
}
//Get the number of pages in the word document
iNumPages=GetActiveDocPageCount();
//omitted code
}
Get pages method
int CWordComm::GetActiveDocPageCount()
{
try
{
_Document oActiveDoc;
//Get the Active Document
oActiveDoc = m_oWord.GetActiveDocument();
//Get the BuiltinDocumentProperties collection for the
//document
LPDISPATCH lpdispProps;
lpdispProps = oActiveDoc.GetBuiltInDocumentProperties();
//Get the requested Item from the BuiltinDocumentProperties
//collection
//NOTE: The DISPID of the "Item" property of a
// DocumentProperties object is 0x0
VARIANT vResult;
DISPPARAMS dpItem;
VARIANT vArgs[1];
vArgs[0].vt = VT_BSTR;
//property name for the number of pages in the active document
_bstr_t btVal("Number of pages");
vArgs[0].bstrVal = btVal;
dpItem.cArgs=1;
dpItem.cNamedArgs=0;
dpItem.rgvarg = vArgs;
HRESULT hr = lpdispProps->Invoke(0x0, IID_NULL,
LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
&dpItem, &vResult, NULL, NULL);
//Get the Value property of the BuiltinDocumentProperty
//NOTE: The DISPID of the "Value" property of a
// DocumentProperty object is 0x0
DISPPARAMS dpNoArgs = {NULL, NULL, 0, 0};
LPDISPATCH lpdispProp;
lpdispProp = vResult.pdispVal;
hr = lpdispProp->Invoke(0x0, IID_NULL, LOCALE_USER_DEFAULT,
DISPATCH_PROPERTYGET, &dpNoArgs, &vResult,
NULL, NULL);
CString sPropValue = "";
switch (vResult.vt)
{
case VT_BSTR:
sPropValue = vResult.bstrVal;
break;
case VT_I4:
sPropValue.Format("%d",vResult.lVal);
break;
case VT_DATE:
{
COleDateTime dt (vResult);
sPropValue = dt.Format(0, LANG_USER_DEFAULT);
break;
}
default:
// sPropValue = "<Information for the property you selected is not available>";
sPropValue = "-4";
break;
}
//Release the no longer needed IDispatch pointers
lpdispProp->Release();
lpdispProps->Release();
return atoi(sPropValue);
}
catch(...)
{
return FUNC_ERROR;
}
}
Question
Is there something obvious I am doing wrong here? Should I be interfacing with word in a different way if I wish to print a range of pages?
If it works fine in the debug mode, I suggest you write the values ( eg No of pages, page being printed etc ) to a text file. Compare the debug log output , with the release log output. Here's a link which might help you. The link is not in C++, but might guide you in the right way.
It turns out this is some sort of timing issue. I put a 500ms sleep after the printing of the document and before the calculation of the number of pages and I'm now consistently getting the correct results.
When I was debugging it was essentially doing this same thing.
I know how to get block data by module_invoke(),
but how to use standard block theme for rendering it.
I tried to use theme() function but with no success.
Could somebody give me advice?
Regards
Taken from the API comments for theme_block
// setup vars
$module = 'system';
$delta = 0; // could also be a string
// renders the "Powered by Drupal" block
// #see hook_block()
// #see module_invoke()
$block = module_invoke($module, 'block', 'view', $delta);
// must be converted to an object
$block = !empty($block) ? (object)$block : new stdclass;
$block->module = $module;
$block->delta = $delta;
$block->region = 'whateverYouWant';
echo theme('block',$block);
Haven't tested it but it seems to be doing what you want. This uses the regular theme function to theme the block you are retrieving