Newcomer developers have a tendency to copy/paste code and not realize that there's an opening for reusability. Intermediate developers understand the importance of reusability and apply it to everything that looks the same, to the point of overdoing it.   
Senior developers look at a potential reusability, compare the benefits (do we make use of the reusable part?) and drawbacks (how complex would a reusable solution have to be?) and make a judgment call based on those observations.

You've identified a possible reusability optimization. The question now is whether acting on it would do more good than bad, compared to what you're currently doing.

Personally, I am not well versed in C (compared to C#) and your current code is already sufficiently complex. I wouldn't want to introduce another layer of abstraction in there.  
However, maybe you and your colleagues are very familiar with this and do not consider this to already be complex. If so, that would mean that adding another reusability abstraction makes sense to you.

I cann't definitively tell you what you should do. What you *shouldn't* do, however, is design your code based on a dogmatic adherence to a principle. Just because you've spotted somewhat of a repetition does not mean that you _must_ remove it.  

While DRY phrases itself as an immovable command (**don't** repeat yourself), it should really be taken as a point of consideration instead (**consider** if you should avoid repeating yourself here). Or, if you prefer this phrasing: **don't** forget to consider if this should be made reusable and if not, make sure you can justify why.

You have to weigh the pros and cons and judge accordingly. An internet stranger can't tell you where you should draw the line. DRY, just like pretty much every programming guideline, can end up being an infinite well that you keep digging in. You have to find a reasonable depth at which it becomes irrelevant to dig any deeper.