Welcome to MSDN Blogs Sign in | Join | Help

Our PM just turned on the faucet on the team blog:

http://blogs.msdn.com/opc/

This is the place to go for the latest on Microsoft efforts related to OPC. It's primarily run by the folks in Windows that work on OPC related tech, including myself.

 - Ben

http://www.microsoft.com/downloads/details.aspx?FamilyID=6db1f17f-5f1e-4e54-a331-c32285cdde0c&displaylang=en

For those of you following my blog for PrintTicket, there's not much in the way of PrintTicket news in the latest SDK. On the OPC side, you'll see no major changes in functionality, though there are a few new error codes and the documentation is substantially expanded. We removed the OPC_STREAM_IO_READWRITE mode from CreateStreamOnFile, since that mode is a bit misleading in terms of intended, supported behavior. The OPC OM APIs don't support an in-place edit model, and even writing back out to the same source data can be problematic with the OPC OM becaue of delay loading. To see the complete set of changes for the OPC Object Model and digitial signature support for OPC, diff the RC version of msopc.idl against the beta version.

Watching me use WinDbg is probably a bit like watching a new programmer write hello world in Visual Studio. I know I'm sitting in front of a very awesome, powerful, tool, and yet, I'm happy and get what I want out of a vocabulary of just a few commands. The problem is that I haven't made it past those few commands in years now. I finally decided today that I needed to figure a few more things out. In this case, I wanted to see a list, and I didn't feel like walking it by hand. For simple data types, something like dt -r 100 might work, but wasn't practical in this case. It was time to find out how to write a loop in a debugger command.

To set things up, here's the struct I was looking at:

struct link {
  void *stuff;
  link *pnext;
};

To get the whole list to dump, we need a couple of things. First, we need someplace to store the current link. For that, we can use user-defiend psuedo-registers. User regsisters are $t0 to $t19. As the name implies, they're not real registers, and changing them has no effect on program execution. I used $t0, and initialized it to the address of the head of my list:

r $t0 = 0x1234

Next we need a loop. Since this is a list, a while loop seemed like a natural choice. Note that unlike C / C++, in debugger script, the '{' and '}' are required. In my first go at this, I wrote ".while (0 != $t0) {...}" and it was quite slow. It turns out that the debugger first does a symbol lookup on $t0, and sometimes can be confused and not treat $t0 properly in expressions. For this reason, it's good to be in the habit of writing @ in front of the register names. Sometimes it'll make things faster. Other times it will make things work. I don't think there's a way to lose by doing this. That gets us to a loop that looks like:

.while (0 != @$t0) { ... }

Now, what goes in the ellipses? First, we need to output what we have, then we need to increment our loop counter. Dumping the output is easy, that's what dt was designed for. Don't forget the '@' in the register name!

dt link @$t0

We also need to update our register. Right now we have a pointer to the stuct. We need to get to the value of pNext. First, let's update our pointer to point to the location of pNext. That means we need the offset of the member. The debugger can give us this using dt again, and it's worth checking (not guessing) because the compiler can add padding. Just leave the address off the dt command and the debugger will dump the struct layout:

dt link

That shows us that the offset pNext pointer is at offset 0x8 (I'm debugging on x64). Putting together expressions in the debugger can feel a bit like a black art sometimes, but if you're familiar with just poi, +, *, and -, you'll be able to get most things done that you need to. poi dereferences a value in an expression to a location in the target process memory, and the result is a pointer-sized value at the target location.

r $t0 = poi(@$t0+8)

Put it all together, and we get:

r $t0 = 0x1234; .while (0 == @$t0) { r $t0; dt _link @$t0; r $t0 = poi(@$t0+8); }

There's probably an even better way to do this. There almost always is in WinDbg. This got the job done for me though, and I've tucked this away on my blog in case I forget & need to find it again later.

So, was this useful? If you found this useful, or want to see some other topic up here, leave a comment and let me know. Anything C++, debugging, printing, XPS, or OPC related is fair game right now.

- Ben

Just a quick note: we've opened up a new forum on MSDN for questions and discussion about OPC.

http://social.msdn.microsoft.com/Forums/en-US/os_opc/threads

Enjoy!

Ben

My team has been heads down getting some great stuff together for all of you working on printing & beyond, so I haven't been writing as much lately. I haven't abandoned those of you who follow my blog for PrintTicket, though things in that space have been pretty quiet around here for the most part. If there's a topic you'd like to see more info on though, please do leave a comment or send me feedback.

The big news though is that coming in Windows 7, and available with the beta, there are two new sets of APIs coming out in the upcoming Windows 7 SDK. First, we'll have support for XPS document reading & creation. Second, we'll have a set of APIs for creating OPC (Open Packaging Conventions) packages. Both APIs will support reading & writing of the corresponding file types, progressive loading, and COM interface surfaces. Additionally, we have support for digital signatures for XPS, and the ability to create digital signatures & policies for your own packages as well.

Along with that news, I'd also like to point out that the Windows 7 SDK Beta has just been released, and is available here.

Getting started with the OPC APIs doesn't take much:

1) Install the Beta. The OPC APIs only run on Windows 7

2) Install the SDK. If you're using Visual Studio, you'll find a tool in the start menu after installing to update Visual Studio to use the new SDK as well.

3) Create / open a C++ project

4) Include Windows.h & msopc.h.

That's it. you're ready to go!

 FYI, If you're interested in the XPS / OPC space, here's another blog that you should be watching:

http://blogs.msdn.com/adrianford

 I'll be posting more about OPC, XPS & the new APIs in the coming weeks, so stay tuned!

 - Ben

My co-worker Aaron was quick to reply to my earlier post on templates in type-lists with this alternative:

You instead add a non-templated function invoker object:

 

struct factory_invoker{

    template <class a, class b>

    struct apply{

        typedef typedef factory<a,b>::type type;

    };

};

 

Then your typelist has normal types in the list, but those types happen to be template metafunctions.  To invoke one of these that is in a typelist:

 

// assuming tlist1 is a typelist

typename tlist1::head::template apply<int, char>::type

 

(the above ‘template’ and ‘typename’ keywords are, as always, only required or even allowd when used inside a template)

Which in this case will end up naming the type ‘MyType<int, char>’ for you.

This also works. However in my case since I was trying to reduce the number of generated types, so I stuck with the previous solution.

Thanks Aaron!

[Mohave] Microsoft's 'new' operating system is apparently doing well at wow-ing customers. This sounds fun, and I'm looking forward to seeing how this story develops. http://news.cnet.com/8301-13860_3-9998336-56.html?tag=nefd.lede

[crash dumps] Ben Martens has a good point here: send your crash dumps, we care! We don't necessarily look at every one, one by one, but in aggregate, we rely on them as one way of understanding your pain when things go boink. If you don't tell us, we don't know.

 

Scenario:

I have a template that takes a significant number of arguments, but in the most common use scenarios, there are some constraints that can be applied. I want to make it easier for clients to use the templates in the most common cases.

template <

      typename command_base_t,

      typename thread_policy_t,

      typename completion_policy_t,

      ...

> 

class CommandQueue

{

      ...

};

 

class ExecOnThreadPool;

class ExecSingleThreaded;

class SyncronousCompletion;

class AsyncCompletion;

 

Now, 99% of all of our usage is for either sync or async threadpool or single threaded command queues. I want to minimize the surface area used in common use cases to make it easier to modify the base template in the future.

Solution:

We can default the recusion policy, but that still requires the caller to be aware of all of the type names, order of parameters, etc. It also means that if we want to add some parameters later or tweak the class in some non-trivial way, we have to touch all of the client code. We can abstract a lot of this by creating templates that take just the thing that changes frequently, and abstracts away the actual template parameters.

template <typename command_base_t>

struct CommandQueueFactory

{

      typedef CommandQueue<

                  command_base_t,

                  ExecOnThreadPool,

                  SyncronousCompletion,

                  ...

            > SyncronousQueue;

 

      typedef CommandQueue<

                  command_base_t,

                  ExecOnThreadPool,

                  AsyncCompletion,

                  ...

            > AsyncronousQueue;

}; 

With this in place, most clients would use the template via the typedefs:

CommandQueueFactory<CommandBase>::SyncronousQueue myQueue;

CommandQueueFactory<CommandBase>::AsyncQueue myAsyncQueue;

Now most client code doesn't have a dependency on the specific policies or template parameter ordering of the original template class. When you need to go back and change the base template, you have far less code to touch to add a new parameter. Type factories are also useful in some scenarios involving template metaprogramming. Most notably, they can be used in typelists and traits classes to act as unspecifed template in metaprogramming constructs (I'll post more on this later).

[Special thanks to Tom M. for introducing me to this technique. As far as I can tell, he was the first to discover this trick.]

 

[edited 7-23-08: updated title, tags]

I'm planning a talk on template use, and thought my blog might be a good way to gether my thoughts, and also to share some of the concepts that I've been working with. Over the next few days (or maybe weeks) I'll try to post a number of articles dealing with a variety of ways to get more mileage out of templates & related techniques. Tonight I want to show how to make even the  simplest templates a bit more flexible.

 Consider the following: you want to write a storage class that operates on a class T, but over the years, you've acquired a few different smart pointer libraries, and you need to replace the value in the pointer. You're smart pointer libraries all use different semantics though:

1) sp::replace(spObject, pValue)

2) pObject.Reset(pValue)

3) pObject = pValue

Now, without making a value judgement on which I prefer, how do you write a template that can work with all three types? One solution is to create a library of overloaded functions that we can use in our template to perform operations on the types that might be smart pointers. To handle the assign case above, we can use this:

namespace sp_ops

{

      template <class T>

      void assign( spa<T> & pointer, const T & value)

      {

            pointer.reset(value);

      }

 

      template <class T>

      void assign(spb<T> & pointer, const T & value)

      {

            spb<T>::reset(pointer, value);

      }

 

      template <class dest_t, class T>

      void assign( dest_t & target, const T & value)

      {

            target = value;

      }

};

The overloads for assign allow us to use a consistent semantic for assign in our template implementation regardless of which smart pointer is used as a template argument. This is a bit like a policy, but unlike a policy, we pre-configure the possible policies, and don't require the usr of the template to supply the correct policy for their pointer. Also, note taht by using two template parameters on the last variation, we create a catch-all. Anything that supports assignment, and isn't one of the two template types falls into the last bucket. Here's how this actually plays out in the template that we wanted to write in the first place:

template <class storage_t, class value_t>

class canister

{

public:

      void set( const value_t & value )

      {

            sp_ops::assign(contents, value);

      }

private:

      storage_t contents;

};

Could we have just written overloads for set? Not really, because the type that we wanted to change behavior on is a class template parameter, not a function parameter. Finally, it's worth noting that container is a very incomplete, rough class. It's just enough code to show the usage. As an interesting excercise, it's also worth noting that you can use this to handle diverse parameters as well. For example:

template <class storage_t, class value_t>

class canister

{

public:

       template <class T>

      assign_to( T & target )

      {

            sp_ops::assign(target, contents);

      }

private:

      storage_t contents;

};

With this last variation, we can now assign out to anything that supports assignment semantics. To really support the last scenario, we may need to define versions of assign that define some transfer semantics for our intrusively ref counted objects, and of course there's not much we can do for transferring objects managed by shared pointers from one library to another. Assuming that the smart pointers are assignable to pointers of the same type though, and not implicitly convertable to bare pointers (this is almost always a bad idea, quite dangerous) this will cover the valid caess. If one of your smart pointers can implicitly convert to a bare pointer, you may want to create a prototype for the assign from that smart pointer to the other smart pointer types, but not give it a body. This prevents accidentally creating two owners for the same object. Any attempt to do so will result in use of an undefined function. A compile time assert in the function would also provide a meaningful check (I won't cover compile time asserts here. They are well documented elsewhere).

Well, that's enough fun for one night. I'll try to post again soon. If you have suggestions for topics related to templates, feel free to send suggestions via my feedback link. Note that for the time being, I'm going to try to avoid some of the heavier topics around template metaprogramming (I have some ideas queued up, but those need to wait until I get through some more basics!)

Thanks,

Ben

 

Ok, I said in an earlier post that I wasn't going to cover metaprogramming, but I have to post just this one.. it's a bit of a useful technique, and I haven't seen it described anywhere else. I've been playing around with template metaprogramming in my spare time, and I ran accross an interesting C++ metaprogramming solution for a certain problem that, as far as I can tell, is rather novel. The issue that I had was that for various reasons, I wanted to store unspecified templates in a typelist (meaning that I wanted to use them as a template parameter so that I could specialize the types later). However, the classic type list uses typedefs, and you can't put an un-specialized template into a typedef. The way I got around this problem is to use a type factory. The type factory is a templatized class that declares a typedef of a concrete type using the type factor's template parameters:

template <class a, class b>

struct factory {

  typedef MyType<a, b> result;

};

To put these into a typelist, then, we just create a custom typelist that takes a template template parameter, and defines head as a type factory for the template template parameter type:

template <

  template <class, class> class t_head,

  typename next

>

class t2_typelist

{

public:

  template <class a, class b>

  struct head_factory {

    typedef t_head<a, b> result;

  };

  typedef next tail;

};

It takes a lot of structure to create, but the practical upshot of it is that it seems to do a pretty good job of breaking up exponential expansions of type names in certain scenarios. One other downside which you may have noticed is that you have to create variations for templates that take different numbers of arguments. On the other hand, once you've done that, you can create a list that contain factories for templates that use different numbers of template parameters.

 

This is a bit older news now, but still, it's pretty awesome. The XPS Essentials Pack is now available for download from http://www.microsoft.com/xps/. Among other things installing it on XP gets you an XPS viewer & the Microsoft XPS Document Writer, a print queue that allows you to convert any document you can print into XPS format.

We've released the final version of Print Schema, and it can be downloaded from here:

http://www.microsoft.com/whdc/xps/printschema.mspx

Thanks everyone for the great feedback.

Ben

When developing PrintTicket support in the configuration module of a filter-pipeline driver, you should be aware that your driver's PrintTicket code paths will be called within the SplWoW64.exe process when converting GDI content to XPS from 32-bit applications running under 64-bit Vista. As a result, this article applies to the implementation of PrintTicket provider methods within the driver: 

http://msdn2.microsoft.com/en-us/library/aa505681.aspx

These limitations apply only to drivers in which the rendering module calls PrintTicket APIs, such as filter pipeline drivers. If your rendering module does not call PrintTicket APIs, this artical doesn't apply. With a few limited exceptions, PrintTicket APIs should not be called from GDI-based printer driver rendering modules.

The Print Schema 0.95 specification is finally live & ready for review:

http://www.microsoft.com/whdc/xps/printschema.mspx

As mentioned in my previous post, we're not trying to change anything with this version of the documentation, but we do clarify a lot of things, and there's a lot more detail. So now, we'd love to get your feedback. If you do have comments or concerns about anything in the documentation, let us know at prninfo@microsoft.com. We'll take feedback for approximately a month. We haven't set a firm cutoff date yet, but I'll share it with you as soon as I know when it is.

As far as suggestions go, generally speaking, we will not add new keywords, remove keywords, or change the structure of the document. However, we can clarify wording, broaden or narrrow the scope of a definition or add missing material.

The next release will be the 1.0 final version so this will be the only chance to provide comments for this version of the specification.

 

I just wanted to give everyone a quick heads up:

We've had a lot of feedback that it would be helpful to have a standalone document covering the Print Schema in a format comparable to what we've released for XPS. Well, we've been working hard at it and should have something to share very soon. I don't have an exact date yet for when it will be available, but I'll post again with a link as soon as I can.

Tentatively, our plan is to allow for a brief comment period to make sure there are no unexpected surprises in the final version. We're not actually changing anything that shipped with Vista, but there is a lot of clarification, and a we've resolved some discrepancies in the existing documentation. If you're working with Print Schema, you may want to plan on leaving a bit of time in your schedule over the next few weeks to grab the review copy and let us know what you think. I’ll also tell you how to provide feedback once the document is available.

Thanks

- Ben

 

More Posts Next page »
 
Page view tracker